% Copyright (c) 2023 by Toby Thurston. This material may be distributed only % subject to the terms and conditions set forth in the Open Publication License, % v1.0 or later (the latest version is presently available at % http://www.opencontent.org/openpub/). \documentclass[a4paper,landscape]{article} \usepackage{luamplib} \mplibtextextlabel{enable} \usepackage{fontspec} \newfontfamily{\demo}{TeX Gyre Pagella} \DeclareTextFontCommand{\textdemo}{\demo} \usepackage{unicode-math} \usepackage[inner=1in,textwidth=5in,textheight=6in, marginparsep=0.5in, marginparwidth=4.2in]{geometry} \usepackage{sectsty} \allsectionsfont{\normalfont\sffamily\bfseries} \usepackage{graphicx} \usepackage{mflogo} \def\mfbook{\textsl{The \MF\kern1pt book}} \def\texbook{\textsl{The \TeX\kern1pt book}} \usepackage{shortvrb}\MakeShortVerb{"} \usepackage{dwmpcode} \title{Drawing with Metapost} \author{Toby Thurston} \date{March 2017 – April 2023} \overfullrule=2pt \def\kw#1{\begingroup\def\_{\kern.04em \vbox{\hrule width.3em height .6pt}\kern.08em}% \ifmmode\mathop{\textbf{#1}}\else\hbox{\bf#1\/}\fi\endgroup} \def\op#1{\begingroup\def\_{\kern.04em \vbox{\hrule width.3em height .6pt}\kern.08em}% \ifmmode\mathop{\textrm{#1}}\else\hbox{\rm#1\/}\fi\endgroup} \def\id#1{\begingroup\def\_{\kern.04em \vbox{\hrule width.3em height .6pt}\kern.08em}% \ifmmode\mathop{\textit{#1}}\else\hbox{\it#1\/}\fi\endgroup} \def\cycle{{\rm cycle}} \def\vpic#1#2{\moveright5.5in\vbox to 0pt{\hsize4in\vskip#1\centerline{\includegraphics{#2}}\vss}} \def\mpic#1#2{\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip#1\centerline{\includegraphics{#2}}\vss}}} \def\mnote#1#2{\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip#1\noindent #2\par\vss}}} \def\mwpic#1#2{\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip#1\centerline{\includegraphics[width=4in]{#2}}\vss}}} \def\mxpic#1#2#3{\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip#1\centerline{\includegraphics[width=#2]{#3}}\vss}}} \def\nb{$\vcenter{\begin{mplibcode}beginfig(1); for t=0 upto 3: fill unitsquare scaled 4 shifted right shifted up rotated 45 rotated 90t; endfor currentpicture := currentpicture scaled 1/2; endfig;\end{mplibcode}}$\ } \def\unit#1{\ifmmode\,\else\thinspace\fi\hbox{#1}} \def\to{\mathrel{\ldotp\ldotp}} \def\<#1>{\ensuremath{\langle\hbox{#1}\rangle}} \newfontface\ding{Zapf Dingbats} \def\hey{\llap{\ding ☞\ }} % \begin{document} \let\folio\thepage \renewcommand{\thepage}{\rlap{\hbox to 5in{\hss\small\folio}}} \pagestyle{myheadings} \raggedbottom % title & toc in the margin \makeatletter \moveright 6in\vbox to 0pt{\vskip23pt\noindent\sffamily{\Large\bfseries\@title}\par\bigskip \noindent\@author\ --- \@date\par \bigskip\noindent \includegraphics{archimedes.pdf} \vss} \makeatother \thispagestyle{empty} \section{Start here} This document contains a collection of ideas and techniques for producing attractive technical drawings with John Hobby’s \MP\ language. I’m assuming that you already know the basics of the language, that you have it installed as part of your up to date \TeX\ ecosystem, and that you have established a reasonable workflow that let’s you write a Metapost program, compile it, and include the results in your \TeX\ document. If not, you might like to start at the \MP\ page on CTAN, and read some of the excellent tutorials, including "mpintro.pdf". If you have already done this, please read on. These notes are partly based on the examples I have developed as answers to questions about technical drawing on the \TeX\ Stack Exchange site. In accordance with their terms and conditions, I’ve only included material here that I’ve written myself --- if you want other people’s code then visit the site; while most answers there focus on writing \LaTeX\ documents, there are a great many questions about drawing, and some of the answers are very illuminating. My approach here will be to explore plain \MP, with examples grouped into themes. One approach to using this document would be to read it end to end. Another would be to flick through until you see something that looks like it might be useful and then see how it’s done. And when I say \textit{plain} \MP\ I mean \MP\ with the default format (as defined in the file "plain.mp") loaded and only a few simple external packages (like "boxes.mp" occasionally). Nearly all of the examples here are supposed to be self contained, and any macros are defined locally so you can get to grips with what’s going on. \MP\ is a very subtle language, and it’s possible to do some very clever and completely inscrutable things with it; in contrast I’ve tried to be as clear as possible in my examples. \newpage \section{Some features of the syntax} \begin{itemize} \item Assignment or equation: the equation "a=3;" means “"a" is the same as "3" throughout the current scope”; the assignment "a:=3;" means “update the value of "a" to the value "3" immediately”. The difference becomes apparent when you try to update a variable in the same scope. \mwpic{0pt}{tiling} This difference also lets you write linear equations like "a=-b;". After this, as soon as you give a value to "a", \MP\ immediately works out the value of "b". This is clever but has its limitations. As the following snippet reveals: \begin{code} % if you run this you will get this in the log a + b = 0; show (a,b); % >> (a,-a) a=42; show (a,b); % >> (42,-42) a:=43; show (a,b); % >> (43,-42) \end{code} As soon as you assign to variable with ":=" \MP\ breaks any previously established equations. \item Variable types: — \ "a", \ "(a,b)" — \ "(r,g,b)", \ "(c,m,y,k)" \ "(x,y,xx,xy,yx,yy)" — \, \, \ If you don’t declare a variable, it’s assumed that it’s a \. When you do declare a variable --- \ or otherwise — any value that it already had in the current scope is removed. \item Implicit multiplication: \MP\ inherits a rich set of rules about numerical expressions from \MF, and of special interest is the scalar multiplication operator. Any simple number, like "42", "3.1415", or ".6931", or any simple fraction like "1/2" or "355/113" standing on it’s own (technically at the primary level) and not followed by "+" or "-" becomes a scalar multiplication operator that applies to the next token (which should be variable of some appropriate type). So you can write things like "3a", or even "1/2 a" (the space between the number and the variable name is optional). This lets you write very readable mathematical expressions. It’s quite addictive after a while. \end{itemize} \vskip -22pt \moveright5.5in\vbox to 0pt{\vss\hsize 4in\noindent The \mpl{sqrt} operator is defined at the same (top) level of precedence, so that \mpl{sqrt2+1} is read as \mpl{(sqrt2)+1} and not \mpl{sqrt(2+1)}, but fractions trump even that, so \mpl{sqrt 1/2 = 0.7071} is true.} \newpage \section{Workflow} This document is not meant for beginners, so you won't find step by step tutorials for something so simple as running \MP. But since you might not find it all that simple, and since the basic tutorials can go out of date, here are descriptions of my own workflows that you might find helpful. You might also think I'm being really inefficient; if so please drop me a line and suggest an improvement. The common features of each of these workflows are: mac os, the MacVim editor to edit \MP\ source code, and Skim.app to view PostScript and PDF files. I have the complete MacTeX distribution installed; any commands mentioned below are supplied by MacTeX. \subsection{Stand alone graphics with plain \MP}\label{sec:plain-flow} \MP\ source files have the extension ".mp", when I open a file in MacVim that matches "*.mp", my editor profile sets the file type to "mp" (which picks up the highlight and indentation rules supplied with MacVim), and adds some relevant directories to the search tree. Finally, if the file is a new file, then the profile loads this template: \begin{smallcode} prologues := 3; outputtemplate := "%j%c.%{outputformat}"; beginfig(1); endfig; end. \end{smallcode} The first two lines are important: "prologues := 3;" makes \MP\ put the full font details in the output so that the files are self-contained; the "outputtemplate" line means that the output will be written to files with an extension that matches the chosen output format, which will be "png", "svg", or more usually "eps", which is the default (and suggests that the output is Encapsulated PostScript). I then add drawing and label commands, using all the traditional facilities for typesetting labels described in section \ref{sec:trad-labels}. I compile the source with "mpost". I usually do this from within MacVim using the command line ":!mpost %" where "!" means “this is an external command” and the "%" picks up the current file name. Usually I need several attempts to get a diagram right, so I open Skim to preview the output with ":!open -a Skim %:r1.eps". I have Skim set up so that when I recompile the source, it automatically updates the view of the PostScript output. \vadjust{\moveright5.4in\vbox to 0pt{\vss\hsize 4in\noindent $$\includegraphics[width=4in]{workflow-plain.pdf}$$ If I want to use the diagram in a \LaTeX\ document I can include the EPS file directly with \begin{texcode} \includegraphics{some-diagram1.eps} \end{texcode} but usually I prefer to convert the EPS to PDF using "epstopdf" rather than rely on the automatic conversion. This is mainly because the PDFs are generally more useful files to have about (I can include them in presentations etc). Sometimes I do this manually but usually I use a small Python script to automate this process: run "mpost" with the "-recorder" option; scan the list of files to see what got produced; check which ones are PostScript; call "esptopdf" to make each one into a PDF file; remove each EPS file if successful. Your mileage may vary.\par }} \subsection{Stand alone graphics with Lua\LaTeX}\label{sec:sa-lua-flow} For graphics with more complicated text formatting, I prefer now to use \texttt{lualatex} with the \texttt{luamplib} package. \mpic{0cm}{workflow} The work flow is a bit simpler because there are no intermediate EPS files to worry about. Instead of compiling with plain "mpost" I use "lualatex" with the "luamplib" package, which calls \MP\ from within the Lua environment. The \MP\ engine actually used is exactly the same. Here is the template I use: \begin{texcode} \documentclass[border=5mm]{standalone} \usepackage{luamplib} \begin{document} \mplibtextextlabel{enable} \begin{mplibcode} \end{texcode} \vskip-12pt \begin{smallcode} beginfig(1); endfig; \end{smallcode} \vskip-12pt \begin{texcode} \end{mplibcode} \end{document} \end{texcode} As you can see, we have \MP\ source code wrapped up in a minimal \LaTeX\ document using the \texttt{standalone} class, which automatically adjusts the page size to fit the contents of document, so is ideal for single diagrams. One small disadvantage is that you can only produce a single PDF output file, so you need to have a separate file for each picture, but the good news is that you get a much simpler and more effective integration with \LaTeX, in particular with the font environment. Since this only works with "lualatex" you have to use the "fontspec" package, as explained in section \ref{sec:neo-labels}. \subsection{Integrated graphics with Lua\LaTeX} If you are ready to use "lualatex" for processing your entire document, then you can directly embed your \MP\ drawings in a series of "mplibcode" environments. Each one produces a horizontal-mode box. For details try "texdoc luamplib". The only drawback of this all-in-one approach is that you have to compile all the drawings every time you compile the document, which might slow you down --- although on a modern machine this is not really an issue any more. \newpage \section{Making and using paths} \label{plain-shapes} In \MP\ there are two sorts of paths: open and closed. \mpic{-12pt}{closed-triangles} A closed path is called a cycle, and is created with the \mpl{cycle} primitive like this: \begin{code} path t; t = origin -- (55,0) -- (55,34) -- cycle; \end{code} You can think of \mpl{cycle} as meaning ‘connect back to the start and close the path’. Note that you have explicitly put \mpl{cycle} to make a closed path. If you wrote \begin{code}[xrightmargin=-32pt] path u; u = origin {right} .. (55,0) .. (55,34) .. {-2,-1} origin; \end{code} then $u$ would be an open path even though the last point is the same as the first. Any path that does not have \mpl{cycle} at the end is an open path.\mpic{-12pt}{open-triangle} You can use \mpl{draw} with either sort of path, but you can only use \mpl{fill} with a cycle. This concept is common to most drawing languages but it’s often hidden: an open path might be automatically closed for you when you try to fill it. \MP\ takes a more cautious approach; if you pass an open path to \mpl{fill} you will get an error that says ‘Not a cycle’, even if the first and last points are the same like path $u$ above. If you want to write a macro that deals differently with the two types of path, then you can use \mpl{cycle} in a boolean context to test whether a given path $p$ is closed: \begin{code} if cycle p: % do something for closed path p else: % do something for open path p fi \end{code} \smallskip\noindent \MP\ inherits the rich path-making syntax directly from \MF, so if you want a general refresher, or you are not quite sure what the five joiners do, $\longrightarrow$\marginpar{% \vbox to 0pt{\vss\halign{\kern .5in\mpl{#}\hfil\quad&#\hfil\cr ..&free curve\cr ...&bounded curve\cr --&straight line\cr ---&tense line\cr \&&splice.\cr}\vss}} or you would like to bone up on exactly what \mpl{curl} and \mpl{tension} are for, then you are recommended to review Chapter 14 of \mfbook. \vfill\noindent Most of the examples in this document use only the two simple joiners \mpl{--} and \mpl{..} with the occasional use of a direction-specifying pair before or after a point. \clearpage \subsection{Predefined closed paths} There are several closed paths defined for you in plain \MP. \mpic{0pt}{closed-standards} \begin{itemize} \item "unitsquare" is defined as the path \mpl{(0,0)--(1,0)--(1,1)--(0,1)--cycle}. It runs counter-clockwise from the origin, and you can use it to draw any rectangle with appropriate use of \mpl{xscaled} and \mpl{yscaled}, or a parallelogram with \mpl{slanted}, or a diamond with \mpl{rotated} --- but note that the definition means that is it centred on point \mpl{(1/2, 1/2)} so you might want to shift it by \mpl{-(1/2,1/2)} before you transform it. \item "fullcircle" which you can use to draw any circle or ellipse with appropriate use of \mpl{xscaled} and \mpl{yscaled}. Unlike the square, it is defined so that it is centred at the origin. But beware that it has unit \textit{diameter}, so its radius is $0.5\unit{bp}$ long. The path runs counter-clockwise and starts at 3 o’clock; which means \mpl{point 0 of fullcircle = 1/2 right} is true. \item "superellipse()" which creates the shape beloved of the Danish designer Piet Hein. Unlike the other two, this one is defined as a function rather than a \ constant, so you need to call it like this: \begin{code} path s; s = superellipse(1/2 right, 1/2 up, 1/2 left, 1/2 down, .8); \end{code} to create a ‘unit’ shape that matches \mpl{fullcircle} as shown on the right. The fifth parameter is the ‘superness’: the value 1 makes it look almost square, 0.8 is about right, 0.5 gives you a diamond, and values outside the range $(0.5,1)$ give you rather weird propeller shapes. Note that, unaccountably, $\id{superellipse}()$ is defined in \texttt{plain.mp} with a \kw{def} rather than a \kw{vardef}. This means you need to enclose it in a group before you can transform it in any way. One way to do this is to use parentheses; or you can assign it to a \ variable, as shown above. \end{itemize} \newpage\subsection{Points on the standard closed paths} \noindent\mpic{-10pt}{closed-points}% \textsc{Here are the three shapes} centred on the origin and labelled to show the points along them. \textbf{Note} that the \textit{unitsquare} shape has been shifted so that it is centred on the origin in all of these examples. The small red circle marks the \textit{origin}, and the labelled red dots are the points of each path. The \textit{unitsquare} has four points, while the other two shapes both have eight. The small arrows between point~0 and point~1 of each shape indicate the direction of the path that makes up the shape. \vfill\noindent If you want to highlight a segment of your shape, there’s a neat way to define it using "subpath". Assuming "p" is the path of your shape, then this: \begin{code} center p -- subpath(1,2) of p -- cycle \end{code} creates a useful wedge shape which looks like this in our three ‘standard’ shapes. \vfill\noindent Better still, you are not limited to integer points along the path of your closed shape. So if you wanted a wedge that was exactly $1/5$ of the area of your shape, you could try \begin{code} center p -- subpath(0,1/5 length p) of p -- cycle \end{code} Clearly this works rather better with more circular shapes. Indeed for a circle you can convert directly between circumference angle and points along the path. So you have defined path $c$ to be scaled copy of \mpl{fullcircle}, then \mpl{point 1 of c} is $45^\circ$ round and 1~radian is \mpl{point 1.27324 of c}, (because $4/\pi \simeq 1.27324$). \vfill\noindent In a closed path, the point numbering in \MP\ wraps round: so in a circle, point $n$ is the same as point $n+8$; and in general point $n$ is the same as point $n+\hbox{\bf length }p$. This works with negative numbers too, so we could use \begin{code} center p -- subpath(-1,1) of p -- cycle \end{code} to get wedge that extends either side of point 0. The same idea was used to draw the arrows in the first row: \begin{code} drawarrow subpath(1/2, length p + 1/2) of p; \end{code} \newpage \subsection{Regular polygons of a given radius}\label{polygons} \noindent\mpic{-10pt}{closed-polygons}% \textsc{Regular polygons} with a given radius can be defined or drawn directly with a simple inline loop: \vadjust{\moveright -60pt \vbox to 0pt{\vskip-3pt\includegraphics{little-hexagon.pdf}\vss}} \begin{code} draw for i=0 upto 5: 20 dir 60i -- endfor cycle; \end{code} which works because \mpl{dir d} expands to \mpl{right rotated d}. But you might prefer to make a macro: \begin{code} vardef polygon(expr n, r) = for i=0 upto n-1: (r, 0) rotated (360/n * i) -- endfor cycle enddef; \end{code} This produces a closed path to represent an $n$-sided polygon that fits in a circle of radius $r$ centred at the origin and that starts at \mpl{(r, 0)}, like the corresponding circular path, as shown in this polygonal version of the previous segment chart.\rlap{\ $\rightarrow$}\\ If you need polygon paths that start at the top, you can just swap the coordinates: \begin{code} vardef polygon(expr n, r) = for i=0 upto n-1: (0, r) rotated (360/n * i) -- endfor cycle enddef; \end{code} $$\includegraphics[width=0.66\textwidth]{closed-polygon-tops.pdf}$$ \hey Note also that some extra care is required to find the centres of these shapes. The \mpl{center} macro defined in "plain.mp" gives you the centre of the bounding box, but this is not the same as the centre of the polygon when the number of sides is odd. What you need instead is the geometric median: \begin{code} vardef median primary p = origin for i=1 upto length p: + point i of p / length p endfor enddef; \end{code} This should work for any closed path, not just regular polygons. \newpage \subsection{Regular polygons of a given side length}\label{polygons-given-side} But you might want a polygon with a fixed side instead of a fixed radius. This needs a little trigonometry, using the sine rule:\mpic{-42pt}{closed-fixed-polygon} \begin{code} vardef polygon_with_side(expr n, s) = save a, b, r; numeric a, b, r; a * n = 360; a + 2b = 180; r = s * sind(b) / sind(a); for i = 0 upto n-1: (0, r) rotated (a * i) -- endfor cycle enddef; \end{code} Which you can use like this to produce a nest of polygons $\rightarrow$ \begin{smallcode} for n = 11 downto 3: path p; p = polygon_with_side(n, 72); fill p withcolor (n/32)[white, 3/4 if odd n: red else: blue fi]; draw p; endfor \end{smallcode} These polygon paths are centred on $(0, 0)$ but sometimes it is more convenient to construct a polygon on a known segment rather than working out how to rotate and shift it into place. $$\includegraphics[width=0.9\textwidth]{closed-polygon-chain.pdf}$$ Here is a way to do that using the \mpl{of} syntax in the macro construction $\longrightarrow$ \vadjust{\moveright 384pt\vbox to 0pt{\vss \begin{smallcode} vardef poly expr n of p = save x, y; z0 = point 0 of p; z1 = point 1 of p; for i=2 upto n-1: z[i] = z[i-2] rotatedabout(z[i-1], 180(2/n-1)); endfor for i=0 upto n-1: z[i] -- endfor cycle enddef; path P[]; P3 = for i=0 upto 2: 6 up rotated 120i -- endfor cycle; fill P3 withcolor 3/4 red; draw P3; for n = 4 upto 23: numeric m; m = floor(n / 2); P[n] = poly n of subpath (m, m-1) of P[n-1]; fill P[n] withcolor (n/32)[3/4 if odd n: red else: blue fi, white]; draw P[n]; label(decimal n, median(P[n])); endfor \end{smallcode}\vskip -12pt}} \newpage\subsection{Curved polygons} \textsc{The regular polygons} above are all defined with straight edges using the \mpl{--} connector that makes a tense path. If you changed each connector to \mpl{..} you would get a circle, and contrariwise, if you try \mpl{tensepath(fullcircle scaled 20)} you will get a regular octagon. But we can also adjust the directions at the corners to make a variety of closed polygon shapes with closed edges. One of the most pleasing is the Reuleaux polygon, with circular arcs for edges. $$\includegraphics[width=0.9\textwidth]{closed-reuleaux-set.pdf}$$ The figure on the right attempts to explain the geometry.\mwpic{-160pt}{closed-reuleaux-geometry} \begin{code} vardef reuleaux(expr n, r) = save a; numeric a; a = 90/n; for t = 0 step 4a until 359: (0,r) rotated t {left rotated (a+t)} .. {left rotated (3a+t)} endfor cycle enddef; \end{code} If you swap the directions at each point you get shapes that are not quite like hypocycloids; play about a bit more to get flower shapes or windmills. $$\includegraphics[width=0.9\textwidth]{closed-antireuleaux-set.pdf}$$ \newpage \subsection{A triangle of Schläfli polygons}\label{sec:gcd} Apart from the curious polygon patterns in the display, the main \MP\ point of interest is the recursive "gcd" macro to find the greatest common divisor.\mpic{-108pt}{gons} \begin{code} input colorbrewer-rgb vardef gcd(expr a, b) = if b = 0: a else: gcd(b, a mod b) fi enddef; beginfig(1); for n=2 upto 24: for s=1 upto floor n/2: pair p; p = (12n - 24s, -24n); path gon; gon = for t=0 upto n/gcd(s,n) - 1: 10 up rotated (360/n * s * t) -- endfor cycle; if (n mod s = 0): fill gon shifted p withcolor Blues 9 2; label("$" & decimal (n/s) & "$", p); fi draw gon shifted p withpen pencircle scaled 1/8; endfor endfor endfig; \end{code} \noindent The macro also leads directly to an efficient way to find the least common multiple: \begin{code} vardef lcm(expr a, b) = a / gcd(a, b) * b enddef; \end{code} As always in \MP, it is safer to divide as early as possible to reduce the chance of arithmetic overflow. \newpage\subsection{Building cycles from parts of other paths} Plain \MP\ has a built-in function to compute the intersection points of two paths, and there’s a handy high level function called "buildcycle" that uses this function to create an arbitrary closed path. \mpic{0pt}{area-under-graph} The arguments to the function are just a list of paths, and providing the paths all intersect sensibly, it returns a closed path that can be filled or drawn. This is often used for colouring an area under a function in a graph. Here is an example. The red line has been defined as path "f" and the two axes as paths "xx", and "yy". The blue area was defined with \begin{code} buildcycle(yy shifted (1u,0), f, yy shifted (2.71828u,0), xx) \end{code} Note the re-use of the $y$-axis path shifted along by different amounts. \smallskip\noindent There are similar examples in the \MP\ manual, but "buildcycle" can also be useful in more creative graphics. Here’s a second example that uses closed paths to give an illusion of depth to a simple graphic of the planet Saturn. \mpic{0pt}{saturn} \marginpar{\hbox{}\vskip1.3in\raggedright\noindent\textbf{Notes}\begin{itemize} \item The first five paths are just circles and ellipses based on "fullcircle". \item The drawing is done inside an "image" simply so that the final result can be drawn at an angle \item "unfill gap" is shorthand for "fill gap withcolor background" \item The subpaths passed to "buildcycle" are chosen carefully to make sure we get the intersections at the right points and so that the component paths all run in the same direction. Note that "subpath (8,4) of globe" runs clockwise (that is backwards) from point 8 to point 4. \end{itemize}} \mpexternal{saturn-code.mp} \newpage\subsection{The implementation of \texttt{buildcycle}} \textsc{The implementation} of "buildcycle" in plain \MP\ is interesting for a number of reasons. Here it is copied from "plain.mp" (with minor simplifications) $\longrightarrow$ \vadjust{\moveright5.5in\vbox to 0pt{\kern-1cm% \begin{code} vardef buildcycle(text input_path_list) = save ta, tb, k, j, pp; path pp[]; k=0; for p=input_path_list: pp[incr k]=p; endfor j=k; for i=1 upto k: (ta[i], length pp[j]-tb[j]) = pp[i] intersectiontimes reverse pp[j]; if ta[i]<0: errmessage("Paths " & decimal i & " and " & decimal j & " don't intersect"); fi j := i; endfor for i=1 upto k: subpath (ta[i],tb[i]) of pp[i] .. endfor cycle enddef; \end{code} \vss}} \noindent Notice how freely the indentation can vary; this is both a blessing (because you can line up things clearly) and a curse (because the syntax may not be very obvious at first glance). Notice also the different ways we can use a $\kw{for}$-loop. The first two are used at the ‘outer’ level to repeat complete statements (that end with semi-colons); the third one is used at the ‘inner’ level to build up a single statement. The use of a "text" parameter allows us to pass a comma-separated list as an argument; in this case the list is supposed to be a list of path expressions that (we hope) will make up a cycle. The first "for" loop provides us with a standard idiom to split a list; in this case the comma-separated value of "input_path_list" is separated into into a more convenient array of paths called "pp" indexed by "k". Note that the declaration of the array as "path" forces the argument to be a list of paths. The second "for" loop steps through this array of paths looking for intersections. The index "j" is set to be "k" when "i=1", and then set to the previous value of "i" at the end of the loop; in this way "pp[j]" is the path before "pp[i]" in what is supposed to be a cycle. The macro uses the primitive operator \mpl{intersectiontimes} to find the intersection points, if any. Note that we are looking for two path times: the time to start a subpath of the current path and the time to end a subpath of the previous path; the macro does this neatly by reversing the previous path and setting the $b$-point indirectly by subtracting the time returned from the length of the path. If all has gone well, then "ta" will hold all the start points of the desired subpaths, and "tb" all the corresponding end points. The third and final "for" loop assumes that this is indeed the case, and tries to connect them all together. Note that it uses ".." rather than "&" just in case the points are not quite co-incident; finally it finishes with a \mpl{cycle} to close the path even though point "tb" of path "k" should be identical (or at least very close) to point "ta" of path "0". This implementation of \mpl{buildcycle} works well in most cases, provided that there are enough components to the cycle of paths. If you only have two paths, then the two paths need to be running the same direction, and the start of each path must not be contained within the other. This is explored in the next section. \newpage \subsection{Strange behaviour of \texttt{buildcycle} with two closed paths} The implementation of "buildcycle" in plain \MP\ can get confused if you use it with just two paths. Consider the following example: \mpic{0pt}{overlaps-missing-filler} \begin{code} beginfig(1); path A, B; A = fullcircle scaled 2.5cm; B = fullcircle scaled 1.8cm shifted (1cm,0); fill buildcycle(A,B) withcolor .8[blue,white]; drawarrow A; drawarrow B; endfig; \end{code} When we compile this example, we get no error message from "buildcycle", but there is no fill colour visible in the output. The problem is that the points found by "buildcycle" are the same both times that it steps through the middle loop, so the closed path it returns consists of two identical (or very close) points and the so the fill has zero area. Now observe what happens when we rotate and reverse each of the paths in turn.\mpic{-24pt}{overlaps-default-fillers} Number 1 corresponds to the example shown above; point~0 of~$A$ is inside the closed path $B$. In~2 we have rotated path $A$ by 180° so that the start of path~$A$ is no longer inside $B$, and now "buildcycle" works ‘properly’ --- but this is the only time it does so. In~3, we've rotated $B$ by 180° as well, so that $B$ starts inside $A$ and as expected "buildcycle" fails. In 4 we've rotated $A$ back to it's original position, so that both paths start inside each other; and we get the union of the two shapes. In 5--8, we've repeated the exercise with path $A$ reversed, and "buildcycle" fails in yet more interesting ways. You could use this behaviour as a feature if you need to treat $A$ and $B$ as sets and you wanted to fill the intersection, union, or set differences, but if you just wanted the overlap, then you need to ensure that both paths are running in the same direction and that neither of them starts inside the other. \newpage \subsection{Find the overlap of two closed paths} As we have seen, in order to get the overlap of two closed paths from "buildcycle", we need both paths to be running in the same direction, and neither path should start inside the other one. It's not hard to create an "overlap" macro that does this automatically for us. The first element we need is a macro to determine if a given point is inside a given closed path. Following Robert Sedgwick's \textit{Algorithms in C} we can write a generic "inside" function that works with any simple closed path. The approach is to extend a horizontal ray from the point towards the right margin and to count how many times it crosses the closed path; if the number is odd, the point must be inside.\vadjust{\moveright5.5in\vbox to 0pt{\kern-4.05cm \begin{code} vardef inside(expr p, ring) = save t, count, test_line; count := 0; path test_line; test_line = p -- (infinity, ypart p); for i = 1 upto length ring: t := xpart(subpath(i-1,i) of ring intersectiontimes test_line); if ((0<=t) and (t<1)): count := count + 1; fi endfor odd(count) enddef; \end{code} \vss}}\label{function:inside} Equipped with this function we can create an "overlap" function that first uses the handy "counterclockwise" function to ensure the given paths are running in the same direction, and then uses "inside" to determine where the start points are. \begin{smallcode} vardef front_half primary p = subpath(0, 1/2 length p) of p enddef; vardef back_half primary p = subpath(1/2 length p, length p) of p enddef; % a and b should be closed paths... vardef overlap(expr a, b) = save A, B, p, q; path A, B; boolean p, q; A = counterclockwise a; B = counterclockwise b; p = not inside(point 0 of A, B); q = not inside(point 0 of B, A); if (p and q): buildcycle(A,B) elseif p: buildcycle(front_half B, A, back_half B) elseif q: buildcycle(front_half A, B, back_half A) else: buildcycle(front_half A, back_half B, front_half B, back_half A) fi enddef; \end{smallcode} Using this "overlap" macro in place of "buildcycle" produces less surprising results.\mpic{-2in}{overlaps} \newpage \subsection{Fitting dashed lines to a path} \textsc{This one is} perhaps for perfectionists, but also shows how simple it is to make useful adjustments in \MP. As you will know, plain \MP\ provides two built-in dash patterns, so that you can draw a path \mpl{dashed withdots} or \mpl{dashed evenly}. \vadjust{% \moveright384pt\vbox to 0pt{\vskip-46pt\hsize 4.2in\small $$ \begin{mplibcode} vardef exactly(expr a) = save m; numeric m; 2m = (a-6) / round(a/6); dashpattern(on m off m) enddef; vardef gooddots(expr a) = save m; numeric m; 2m = (a-5) / round(a/5); dashpattern(off m on 0 off m) enddef; beginfig(1); for i=2 upto 8: path c[]; c1 = fullcircle scaled 16i shifted 80 left; c2 = fullcircle scaled 16i shifted 80 right; draw c1 dashed evenly withcolor 2/3 blue; draw c2 dashed exactly(arclength c2) withcolor 1/2 red; %draw c1 shifted 160 down dashed withdots withcolor 2/3 blue; %draw c2 shifted 160 down dashed gooddots(arclength c2) withcolor 1/2 red; endfor endfig; \end{mplibcode} $$ \noindent The blue circles on the left were drawn with \mpl{dashed evenly}, and the uneven gaps are noticeable at the “three o’clock” positions where the paths begin and end. As you can see the default dash spacing looks fine at some sizes but bad on others. On the right you can see the same circular paths coloured red, and drawn with \mpl{dashed exactly(arclength c, 6)}. $$ \begin{mplibcode} vardef exactly(expr a, u) = save m; numeric m; 2m = a / round(a/u); dashpattern(on m off m) enddef; beginfig(1); for i=2 upto 8: path c[]; c1 = unitsquare shifted -(1/2, 1/2) scaled 16i shifted 80 left; c2 = unitsquare shifted -(1/2, 1/2) scaled 16i shifted 80 right; draw c1 dashed evenly withcolor 2/3 blue; draw c2 dashed (exactly(arclength c2, 8) shifted 6 right) withcolor 1/2 red; endfor endfig; \end{mplibcode} $$ Other paths may require a bit more ingenuity and thought. Because the square paths have four equal sides, they work better with a target dash length that is a multiple of 4. Here the blue squares on the left use the default \mpl{dashed evenly}, and the red on the right, \mpl{exactly(arclength c2, 8)} \mpl{shifted 6 right}. The shift makes the corners look better. \vss}} The keyword \mpl{dashed} gives you access to the PostScript "setdash" command, its argument is a special \ defined with the \MP\ \mpl{dashpattern} function. If you look in "plain.mp" you will find these declarations: \begin{code} picture evenly,withdots; evenly = dashpattern(on 3 off 3); % dashed evenly withdots = dashpattern(off 2.5 on 0 off 2.5); % dashed withdots \end{code} The detailed syntax is explained in §9.4 of the \MP\ manual, but essentially \mpl{withdots} creates a unit 5 points long with a dot in the middle, and \mpl{evenly} creates a unit 6 points long with the dashes 3pt long (plus the round bit at the end of each dash, unless you have changed \mpl{linecap}) and gaps 3pt long (minus any round bits). You probably also know that you can adjust these sizes by applying a suitable scaling, so that \mpl{dashed withdots scaled 1/2} gives a rather denser dotted line, and \mpl{dashed evenly scaled 4} will give you very long dashes. But you may also notice that the dash patterns (particularly the longer ones) do not always fit your paths exactly -- this is especially noticeable with closed paths, where you may end up with one unsightly long dash or a very short gap a the point where the path begins and ends. Fortunately there is a very simple solution: adjust the length of the dash pattern so that an integer number of dash units exactly fit your path. \begin{code} vardef exactly(expr a, u) = save m; numeric m; 2m = (a-u) / round(a/u); dashpattern(on m off m) enddef; \end{code} Here "a" is supposed to be the \mpl{arclength} of your path, and "u" the desired unit size, so you can use it like this: \begin{code} path c; c = fullcircle scaled 200; draw c dashed exactly(arclength c, 6); \end{code} to get a close approximation to \mpl{dashed evenly} that exactly fits the path. \newpage \section{Numbers} This section discusses plain \MP's scalar numeric variables and what you can do with them. \MP\ inherits its unusual native system of scaled numbers from \MF; like many of Knuth's creations it is slightly quirky, but works very well once you get the hang of it. The original objective was to make \MF\ produce identical results on a wide variety of computers. By default all arithmetic is carried out using 28-bit integers in units of $1/65536$. This is done automatically for you, so you don’t need to worry about it, but you should be aware of a couple of practical implications: \begin{itemize} \item All fractions are rounded to the nearest multiple of $1\over65536$, so negative powers of 2 ($1\over2$, $1\over4$, $1\over8$, $\dots$) are exact, but other common fractions are not: for example $1\over3$ is represented as ${21845\over65536} \simeq 0.333328$, and $1\over10$ as ${6554\over65536} \simeq 0.100006$. You should bear this in mind particularly when you choose fractional step-values in a "for" loop; the errors can accumulate so that you may miss your expected terminal value.\vadjust{\moveright5.5in\vbox to 0pt{\kern-2in\hsize4in\noindent Compare the following two snippets: $$\vbox{\halign{#\hfil\quad&#\hfil\cr Code&Output\cr\noalign{\smallskip\hrule\bigskip} \vtop{\parindent0pt\hsize2.2in \bgroup\obeylines $\kw{for}$ $i=0$ \kw{step} $1/10$ \kw{until} $1$: \quad$\kw{show}$ $i$; $\kw{endfor}$ \egroup } & \vtop{\parindent0pt\parskip-2pt\obeylines\hsize60pt\tt >> 0 >> 0.1 >> 0.20001 >> 0.30002 >> 0.40002 >> 0.50003 >> 0.60004 >> 0.70004 >> 0.80005 >> 0.90005 } \cr\noalign{\bigskip} \vtop{\parindent0pt\hsize2.2in \bgroup\obeylines $\kw{for}$ $i=0$ \kw{step} $1$ \kw{until} $10$: \quad$\kw{show}$ $i/10$; $\kw{endfor}$ \egroup } & \vtop{\parindent0pt\parskip-2pt\obeylines\hsize60pt\tt >> 0 >> 0.1 >> 0.2 >> 0.3 >> 0.4 >> 0.5 >> 0.6 >> 0.7 >> 0.8 >> 0.9 >> 1 }\cr\noalign{\bigskip\hrule}\cr }}$$ You get 11 iterations in the second but only 10 with the first. \vss}} \item The system limits you to numbers that are less than 4096 in absolute value. This can be an irritation if you are trying to plot data with large values, but the solution is simple: scale your values to a reasonable range first. \item Intermediate calculations are allowed to be up to 32768 in absolute value before an error occurs. You can sometimes avoid problems by using the special Pythagorean addition and subtraction operators, but the general approach should be to do your calculations before you scale a path for filling or drawing. \item You can turn a number up to 32768 into a string using the "decimal" command, and then you could append zeros to it using string concatenation. \end{itemize} If you are using a recent version of \MP\ you can avoid all these issues by choosing one of the three new number systems: double, binary, or decimal, with the "numbersystem" command line switch. But beware that if you write programs that depend on these new systems, they might not be so portable as others. It's nice to have these new approaches just in case, but you will not need to use them very often. \newpage\subsection{Numeric constants} Alongside the quirky number system, plain \MP\ also inherits three numeric constants from \MF: \id{infinity}, \id{epsilon}, and \id{eps}: \begin{itemize} \item $\id{eps}$ is defined to be a small amount that is noticeable to \MF’s rounding algorithms, namely ${32\over65536}={1\over2048}\simeq 0.00049$. As a distance on the page or screen it's invisible at any resolution less than 150,000 dots per square inch. If you were designing fonts in \MF, $\id{eps}$ could help you avoid bad choices of pixels at low resolutions, but in \MP\ it's only really useful in comparisons that might suffer from rounding errors. \id{eps} is tiny, but it's bigger than any rounding error you may encounter, so you can safely test for equality with: $\kw{abs}(\id{a}-\id{b})<\id{eps}$. \item $\id{epsilon}$ is defined to be $1\over65536$, the smallest positive scaled number. \item $\id{infinity}$ is defined to be $4096-\id{epsilon}$, which is the largest number you will normally deal with. This is useful when you just want a quantity larger than any other in the immediate vicinity. For an example, look at the definition of the "inside" function in section~\ref{function:inside}. \end{itemize} These three quantities retain (approximately) the same value even if you choose one of the alternative, higher precision, number systems. This is probably the most sane approach, but the constants lose their status as the smallest and largest numbers you can have. \vadjust{\moveright5.5in\vbox to 0pt{\kern-221pt\hsize 4.25in \noindent Running the toy program: \par\bigskip $\kw{show} \id{numbersystem}, \id{eps}, \id{epsilon}, \id{infinity}; \kw{end}\!.$ \par\bigskip\noindent gives the following results with the different number systems: \begin{code} >> "scaled" >> 0.00049 >> 0.00002 >> 4095.99998 >> "double" >> 0.00048999999999999998 >> 1.52587890625e-05 >> 4095.9999800000001 >> "binary" >> 0.00048999999999999999999999999999999993 >> 0.0000152587890625 >> 4095.9999800000000000000000000000001 >> "decimal" >> 0.00049 >> 0.0000152587890625 >> 4095.99998 \end{code} \vss}} The messy set of results shown on the right arises because "plain.mp" defines these constants like this (in version 1.005, which is current at the time of writing): \begin{code} eps := .00049; % this is a pretty small positive number epsilon := 1/256/256; % but this is the smallest infinity := 4095.99998; % and this is the largest \end{code} If you want cleaner constants, feel free to redefine the two decimals as: \begin{code} eps := 1/2048; infinity := 64*64-epsilon; \end{code} These definitions are equivalent with "scaled" numbers, but more consistent at higher precision. In particular they ensure that we always have $4096 = \id{infinity} +\id{epsilon}$ whichever number system is in use. \newpage\subsection{Units of measure} In addition to the very small and very large numeric variables, plain \MP\ inherits eight more that provide a system of units of measure compatible with \TeX. The definitions in "plain.mp" are very simple: $\longrightarrow$ \vadjust{\moveright 384pt\vbox to 0pt{\kern-24pt \begin{code} mm=2.83464; pt=0.99626; dd=1.06601; bp:=1; cm=28.34645; pc=11.95517; cc=12.79213; in:=72; \end{code} \vss}} When the output of \MP\ is set to be PostScript, then the basic unit of measure is the PostScript point. This is what \TeX\ calls a "bp" (for `big point'), and it is defined so that $1\unit{inch}=72\unit{bp}$. The traditional printers' point, which \TeX\ calls a~"pt", is slightly smaller so that $1\unit{inch}=72.27\unit{pt}$. Normal use of these units relies on \MP's implicit multiplication feature. If you write `$\id{w}=10\,\id{cm};$' in a program, then the variable \id{w} will be set to the value 283.4645. The advantage is that your lengths should be more intuitively understandable, but if you are comfortable thinking in PostScript points (72 to the inch, 28.35 to the centimetre) then there is no real need to use any of the units.\marginpar{Bizarrely, 28.35 is also the number of grammes to the ounce.} It is sometimes useful to define your own units; in particular many \MP\ programs define something like `$\id{u}=1\,\unit{cm};$' near the start, and then define all other lengths in terms of \id{u}. If you later wish to make a smaller or larger version of the drawing then you can adjust the definition of \id{u} accordingly. Two points to note: \begin{itemize} \item If you want different vertical units, you can define something like `$\id{v}=8\,{mm}$' and specify horizontal lengths in terms of \id{u}, but verticals in terms of \id{v}. \item If you want to change the definition of \id{u} or \id{v} from one figure to the next, you will either have to use `$\kw{numeric} \id{u},\id{v};$' at the start of the your program in order to reset them, or use the assignment operator instead of the equality operator to overwrite the previous values. \end{itemize} The unit definitions in "plain.mp" are designed for use with the default scaled number system; if you want higher precision definitions, then you can update them by including something like this at the top of your program: $\longrightarrow$ \vadjust{\moveright 5.5in \vbox to 0pt{\kern-24pt \begin{code} % exact values to re-define the plain.mp units numeric bp, in, mm, cm, pt, pc, dd, cc; 72 = 72 bp = 1 in; 800 = 803 pt = 803/12 pc; 3600 = 1270 mm = 127 cm; 1238 pt = 1157 dd = 1157/12 cc; \end{code} %\bgroup\obeylines\parindent0pt %$\kw{numeric} \id{bp}, \id{in}, \id{mm}, \id{cm}, \id{pt}, \id{pc}, \id{dd}, \id{cc};$ %$72 = 72\id{bp} = 1\id{in}$; %$800 = 803 \id{pt} = 803/12 \id{pc};$ %$3600 = 1270 \id{mm} = 127 \id{cm};$ %$1238 \id{pt} = 1157 \id{dd} = 1157/12 \id{cc};$ %\egroup \vss}} The effect of the $\kw{numeric}$ keyword is to remove the previous definitions; the four equation lines then re-establish the units with very slightly more accurate definitions. You can safely use these definitions with "scaled", as they are equivalent to the decimals currently given in "plain.mp", but the main point of the example is to show how you can do implicit definitions with equations. \newpage \subsection{Integer arithmetic, clocks, and rounding} Native \MP\ provides nothing but a "floor" function, but "plain.mp" provides several more useful functions based on this. \begin{itemize} \item `$\mathop{\kw{floor}} x$' returns $\lfloor x\rfloor$, $\hbox{the largest integer} \le x$. You can use "x=floor x" to check that $x$ is an integer. \item `$\mathop{\kw{ceiling}} x$' returns $\lceil x\rceil$, $\hbox{the smallest integer} \ge x$. \item `$x \mathbin{\kw{div}} y$' returns $\lfloor x/y \rfloor$, integer division. \item `$x \mathbin{\kw{mod}} y$' returns $x-y\times\lfloor x/y \rfloor$, integer remainder. \end{itemize} Note that $\kw{mod}$ preserves any fractional part, so $355/113 \mathrel{\kw{mod}} 3 = 0.14159$. \smallskip \parshape=1 0pt 3.4in This behaviour is usually what you want. \vadjust{\moveright 266pt \vbox to 0pt{\noindent \begin{mplibcode} input clocks beginfig(1); draw clock(hour, minute) scaled 0.8; endfig; \end{mplibcode}\vss}} For example we can use it to turn the time of day into an appropriate rotation for the hands of a clock.% \vadjust{\moveright 384pt\vbox to 0pt{\kern-196pt \begin{code} path hand[]; hand1 = origin .. (.257,1/50) .. (.377,1/60) & (.377,1/60) {up} .. (.40,3/50) .. (.60, 1/40) .. {right} (.75,0); hand1 := (hand1 .. reverse hand1 reflectedabout(left,right) .. cycle) scaled 50; hand2 = origin .. (.60, 1/64) .. {right} (.925,0); hand2 := (hand2 .. reverse hand2 reflectedabout(left,right) .. cycle) scaled 50; % hour of the day to degrees vardef htod(expr hours) = 30*((15-hours) mod 12) enddef; vardef mtod(expr minutes) = 6*((75-minutes) mod 60) enddef; vardef clock(expr hours, minutes) = image( % face and outer ring fill fullcircle scaled 100 withcolor 1/256(240, 240, 230); draw fullcircle scaled 99 withcolor .8 white; draw fullcircle scaled 100 withpen pencircle scaled 7/8; % numerals for h=1 upto 12: label( decimal h infont "bchr8r", (40,0) rotated htod(h)); endfor % hour and minute marks for t=0 step 6 until 359: draw ((48,0)--(49,0)) rotated t; endfor drawoptions(withpen pencircle scaled 7/8); for t=0 step 30 until 359: draw ((47,0)--(49,0)) rotated t; endfor % hands rotated to the given time filldraw hand1 rotated htod(hours+minutes/60); filldraw hand2 rotated mtod(minutes); % draw the center on top fill fullcircle scaled 5; fill fullcircle scaled 3 withcolor .4 white; ) enddef; \end{code} \vss}} In the program given on the right, this idea is used to define functions that convert from hours and minutes to degrees of rotation on the clock. \MP\ provides two internal variables \id{hour} and \id{minute} that tell you the time of day when the current job started. The clock face shown here was generated using $$\kw{beginfig}(1);{}\mathbin{\kw{draw}}\id{clock}(\id{hour},\id{minute}); \kw{endfig};$$ to give a sort of graphical time stamp. \vfill There is also a "round" function that rounds a number to the nearest integer. It is essentially defined as $\mathop{\kw{floor}}(x+0.5)$ except that it is enhanced to deal with $\kw{pair}$ variables as well. If you round a pair the $x$-part and the $y$-part are rounded separately, so that $\mathop{\kw{round}}(3.14159, 2.71828) = (3,3)$. The "round" function only takes a single argument, but you can use it to round to a given number of places by multiplying by the precision you want, rounding, and then dividing the result. So to round to the nearest eighth you might use `$\kw{round}(x\times8)/8$', and to round to two decimal places `$\kw{round}(x\times100)/100$'. The only restriction is that the intermediate value must remain less than 32767 if you are using the default number system. \newpage \subsection{Integer powers} \textsc{Even if you use} one of the new number systems, you may occasionally get caught out by the \mpl{**} operator. As the table on the right shows, you may get an approximate answer from \mpl{x ** y} even when $x$ and $y$ are both integers. \vadjust{\moveright 384pt\vbox to 0pt{\kern -2pt $$\begin{mplibcode} beginfig(0); %primarydef x ** y = 1 for n=1 upto y: * x endfor enddef; for x=1 upto 19: for y = 1 upto 7: if x = 1: label("$x" if y>1: & "^{" & decimal y & "}" fi & "$", (52y, -20x)); elseif y * mlog(x) < mlog(infinity): numeric r; r = x ** y; label(decimal r, (52y, -20x)) withcolor 3/4 if r = round(r): blue else: red fi; fi endfor endfor label.lft("Results of \mpl{x**y} for small values, using", lrcorner currentpicture shifted 36 up); label.lft("the default \mpl{scaled} number system", lrcorner currentpicture shifted 24 up); currentpicture := currentpicture scaled 0.8; endfig; \end{mplibcode}$$\vss}} Note that the squares are all integers, and the powers of two appear to be ok (although if the page was wider you would see that \mpl{2**9} is $512.00002$), but that with a couple of exceptions cubes and higher powers are slightly off. Changing the number system makes it worse; even $x^1$ is not always an integer. The reason can be found in the way that the \mpl{**} operator is defined in "plain.mp". \begin{smallcode}[xleftmargin=0pt, xrightmargin=-36pt] primarydef x ** y = if y = 2: x * x else: takepower y of x fi enddef; def takepower expr y of x = if x > 0: mexp(y * mlog x) elseif (x = 0) and (y > 0): 0 else: if y = floor y: if y >= 0: 1 for n=1 upto y: * x endfor else: 1 for n=-1 downto y: / x endfor fi else: hide(errmessage "Undefined power: " & decimal x & "**" & decimal y) fi fi enddef; \end{smallcode} This is inherited direction from plain \MF, and as it says in the \mfbook, it is optimized for $x^2$ and takes care to handle correctly negative numbers and zeros. But for all positive values of $x$ other than 2 it is implemented using logs, and the results are therefore only approximate. To avoid confusion where this might matter (such as a particular offset into a recursively defined path) you could simply use \mpl{round(7**3)} to get a whole number, or if you are sure that your $y$ values are all non-negative integers, you could temporarily replace the definition: \begin{smallcode} primarydef x ** y = 1 for n=1 upto y: * x endfor enddef; \end{smallcode} \newpage \section{Pairs, triples, and other tuples} \vpic{7pt}{random-selection} \noindent \MP\ inherits a generalized concept of number from \MF\ that includes ordered pairs. Pairs are primarily used as Cartesian coordinates, but can also be used as complex numbers, as discussed below. \MP\ extends this gener\-al\-ization with 3-tuples and 4-tuples. Just like pairs, the elements in these tuples can take any numeric value, so in theory it would be possible to use them for three- and four-dimensional coordinates, but there are no built-in facilities for this in plain \MP, so some external library is needed. \textit{All of the various attempts at three dimensions in \MP\ are rather difficult to use, so none of them is discussed in this document}. \smallskip\noindent Unlike simple numerics, the extended tuple variables are not automatically declared for you, so if you want to define points $A$ and $B$ you need to explicitly write `$\kw{pair} \id{A},\id{B};$' before you assign values to them. Once you have declared them, you can equate them to an appropriate tuple using $=$ as normal. \begin{code} pair A,B; A = B = (1,2); color R; R = (1,2,3); cmykcolor C; C = (1,2,3,4); \end{code} The normal use of triples and quads is for colours (RGB colours and CMYK colours); Triples are type \kw{color}, quads are type \kw{cmykcolor}. You can't have tuples of any other length, not even as constants, except for transforms. A transform is how \MP\ represents an affine transformation such as "rotated 45 shifted (10,20)". They are represented as 6-tuples, but if you try to write: \begin{code} transform T; T = (1,2,3,4,5,6); % <-- doesn't work \end{code} you will get a parsing error (that complains about a missing parenthesis after the 4). You can examine and assign the individual parts using `$\kw{xpart} \id{T}$' etc. More details below, and full details in the \MF\ book. \newpage\subsection{Pairs and coordinates} Now \textbf{pairs}: if you enclose two numerics in parentheses, you get a \. A pair generally represents a particular position in your drawing with normal, orthogonal Cartesian $x$- and $y$-coordinates, but you can use a pair variable for other purposes if you wish. As far as \MP\ is concerned it's just a pair of numerics. \MP\ provides a simple, but slightly cumbersome, way to refer to each half of a pair. The syntax `$\kw{xpart} \id{A}$' returns a numeric equal to the first number in the pair, while `$\kw{ypart} \id{A}$' returns the second. The names refer to the intended usage of pair variable to represent pairs of $x$ and $y$-coordinates. Note that they are read-only; you can't assign a value to an $\kw{xpart}$ or a $\kw{ypart}$. So if you want to update only one part of a pair, you have to do something like this: $\id{A} \mathrel{:}= (42, \kw{ypart}\id{A});$ In addition there is a neat macro definition in plain \MP\ that allows you do deal with the $x$- and $y$-parts of pairs rather more succinctly. \vadjust{\moveright 384pt\vbox to 0pt{\kern-140pt \noindent Plain \MP\ provides this definition \begin{code} vardef z@#=(x@#,y@#) enddef; \end{code} which you can use to find orthogonal points. \bigskip\noindent \includegraphics{random-function} \vss}}% The deceptively simple definition of $\id{z}$ as a subscripted macro allows you to write "z1 = (10,20);" and have it automatically expanded into the equivalent of "x1=10;" and "y1=20;". You can then use "x1" and "y1" as independent numerics or refer to them as a pair with "z1". A common usage is to find the orthogonal points on the axes in graphs, like so $\longrightarrow$ \smallskip There is also a simple way to write coordinates using a polar notation using\label{polar} \mpl{dir}. This macro is defined so that \mpl{dir 30} expands to \mpl{right rotated 30} and then to \mpl{(1,0) rotated 30}, which becomes \mpl{(cosd(30), sind(30)} or \mpl{(0.86603, 0.5)}. So to get the polar notation point $(r,\theta)$, where $r$ is the radius and $\theta$ is the angle in degrees counter-clockwise from the positive $x$-axis, you can write `\mpl{r * dir theta}'. As usual, with a constant you can omit the multiplication sign, so `\mpl{2 dir 30}' provides another way to define the point "(sqrt(3),1)". \smallskip Plain \MP\ defines five useful pair variables: \id{origin}, \id{right}, \id{up}, \id{left}, and \id{down}. As so often, Knuth-Hobby definitions in "plain.mp" are quite illuminating $\longrightarrow$ \vadjust{\moveright 384pt\vbox to 0pt{\kern-36pt \begin{code} % pair constants pair right,left,up,down,origin; origin=(0,0); up=-down=(0,1); right=-left=(1,0); \end{code} \vss}}% As you can see, pair variables can be used in implicit equations. They can also be scaled using implicit multiplication, so writing `$144 \id{right}$' is equivalent to writing `$(144,0)$' but possibly a bit more readable. In particular the idiom `$\kw{shifted} 200 \id{up};$' works well when applied to a point, a path, or an image. Unfortunately, this convenient notation does not work well with units of measure. This is because implicit multiplication only works between a numeric constant and a variable. So `$2 \id{in}\, \id{right}$' does not work as you might expect; you can write `$2\id{in} \mathrel{\ast}\id{right}$' but by that stage it's probably simpler to write `$(2\id{in},0)$' or even just `$(144,0)$'. \newpage \subsection{Pairs as complex numbers} As you might expect in a language designed by mathematicians, \MP's pair variables work rather well as complex numbers. To represent the number $3+4i$ you can write "(3,4)". To get its modulus, you write "abs (3,4)" (which gives $5$ in this case), and to get its argument, you write "angle (3,4)" (which gives $53.1301$). Note that "angle" returns the argument in degrees rather than radians, and that the result is normalized so that $-180 < \kw{angle} (x,y) \le 180$. The standard notation for points supports this usage. You can write "z0=(3,4);" and then extract or set the real part with "x0" and the imaginary part with "y0". If you want to use other letters for your variable names, you can use "xpart" and "ypart" to do the same thing. So after `\mpl{pair w; w=(3,4);}' you can get the real part with "xpart w" and the imaginary part with "ypart w". You can also use the polar notation shown above to write complex numbers. For $re^{i\theta}$ you can write `\mpl{r * dir theta}' where "r" is the modulus and "theta" is the argument in degrees. The predefined constants \mpl{up}, \mpl{down}, \mpl{left}, and \mpl{right} also provide points on the unit circle corresponding to $i$, $-i$, $-1$, and $+1$ respectively. It's tempting to define `\mpl{pair i; i=(0,1);}', so that you can write constants like "4i" directly, but this is not very helpful, because "3+4i" will give you an error since \MP\ does not let you add a "numeric" to a "pair". However \MP\ does let you add (and subtract) two pairs, so complex addition and subtraction are just done with the normal operators. \vadjust{\moveright 384pt\vbox to 0pt{\vskip -3.74in $$\includegraphics{complex-operators}$$ \begin{code} beginfig(1); numeric u; u = 1cm; z1 = 2 dir 15; z2 = 1.2 dir 60; z3 = z1+z2; z4 = z1 zscaled z2; z5 = (x1,-y1); drawoptions(withcolor 2/3 white); draw (1/2 left -- 3 right) scaled u ; draw (1/2 down -- 3 up ) scaled u ; draw subpath (0,3) of fullcircle scaled 2u rotated -22.5; drawoptions(); dotlabel.lrt (btex $\scriptstyle 1$ etex, (u,0)); dotlabel.ulft(btex $\scriptstyle i$ etex, (0,u)); interim ahangle := 30; forsuffixes @=1,2,3,4,5: x@ := x@ * u; y@ := y@ * u; drawarrow origin -- z@ cutafter fullcircle scaled 5 shifted z@ withcolor 2/3 if @ < 3: blue else: red fi; endfor fill fullcircle scaled dotlabeldiam; dotlabel.rt (btex $A$ etex, z1); dotlabel.urt(btex $B$ etex, z2); dotlabel.top(btex $A+B$ etex, z3); dotlabel.top(btex $A \times B$ etex, z4); dotlabel.rt (btex $\bar{A}$ etex, z5); endfig; \end{code} \vss}}% To get the complex conjugate you could use "reflectedabout(left,right)", but it's probably easier just to write "(x0,-y0)" or define a simple function: \begin{code} def conj(expr z) = (xpart z, -ypart z) enddef; \end{code} Complex multiplication is provided as part of the core language by the "zscaled" operator. This is defined with the same precedence as "scaled" or normal scalar multiplication (which is what you usually want). So "(3,4) zscaled (1,2)" gives "(-5,10)" because $(3+4i)\times(1+2i) = 3+6i+4i-8 = -5+10i$. "zscaled" is only defined to work on two "pair" variables, so you can't write \mpl{(3,4) zscaled 4}. To get that effect with "zscaled" you would have to write \mpl{(3,4) zscaled (4,0)}, but this is the same as \mpl{(3,4) scaled 4}, which is usually simpler to write. If your pair is stored as a variable you can write (for example) \mpl{4 z0} to get the same effect. Or \mpl{1/4 z0} or \mpl{z0/4} for scalar division. There are no other complex operators available, but it is not hard to implement the usual operations when they are required\dots \newpage \subsubsection{Extra operators for complex arithmetic} Since multiplication by $z$ can be thought of as a transformation consisting of rotation by the argument of $z$ and scaling by $|z|$, you can define the complex inverse and complex square root simply using \mpl{angle} and \mpl{abs}. \vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip -24pt \centerline{\includegraphics{complex-inverse-and-sqrt}} The interesting part of the left hand figure was drawn as follows: \begin{smallcode} input colorbrewer-rgb for i=1 upto 3: z[i] = (3/2 + 1/4 normaldeviate) * dir (16 i + normaldeviate); path a; a = z[i] scaled 42 -- origin -- zinverse(z[i]) scaled 42; drawarrow a cutafter fullcircle scaled 5 shifted point 2 of a withcolor SetTwo[7][2+i]; drawdot point 0 of a withpen pencircle scaled dotlabeldiam; drawdot point 2 of a withpen pencircle scaled dotlabeldiam; drawdot point 2 of a withpen pencircle scaled 2 withcolor white; endfor \end{smallcode} The only difference on the right is that the drawing used "zsqrt()". \vss}} \smallskip\noindent First an inverse function. The idea here is to find a function that is the opposite of complex multiplication, so we want something that gives \begin{code} z zscaled zinverse(z) = (1,0) \end{code} In other words you need to find a complex number with an argument that is the negative of the argument of $z$ and a modulus that will scale $|z|$ to 1. You can use the polar notation with "dir" to write this directly: \begin{code} vardef zinverse(expr z) = 1/abs z * dir - angle z enddef; \end{code} The complex division, $z/w$, can now be done as: \mpl{z zscaled zinverse(w)}. The only difficulty with this function is how it deals with zero, or rather with the point $(0,0)$. Since `\mpl{abs (0,0)}' gives $0$, the function will give you a `divide by zero' error if it's called with $(0,0)$. But this is probably what you want it to do, since there is no easy way to represent the point at infinity in the extended complex plane on paper. \medskip\noindent For square root, you want a function `\mpl{zsqrt(z)}' that returns a complex number with half the argument of $z$ and a modulus that is the square root of the modulus of $z$, so that `\mpl{zsqrt(z) zscaled zsqrt(z) = z}'. This does the trick: \begin{code} def zsqrt(expr z) = sqrt(abs z) * dir 1/2 angle z enddef; \end{code} This function also has a difficulty with the point $(0,0)$, because "angle (0,0)" is not well defined, and so \MP\ throws an error. If you want a function that correctly returns $(0,0)$ as its own square root, then try something like this: \begin{code} def zsqrt(expr z) = if abs z > 0: sqrt(abs z) * dir 1/2 angle fi z enddef; \end{code} \newpage \subsubsection{Using complex numbers to draw fractals} As an example of what you can do with complex arithmetic, here is a version of the diagram from §4.1 of Knuth's \textsl{Seminumerical Algorithms} showing $S$, the set of all points that can be written as $\sum_{k\ge1}a_k(i-1)^{-k}$. \vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip -81pt \begin{smallcode} vardef fizz(expr X) = pair m, n; m = right; n = origin; numeric a, x; x = X; forever: exitif x = 0; m := m zscaled zinverse((-1, 1)); a := x mod 2; n := n + a * m; x := x div 2; endfor n enddef; input colorbrewer-rgb color shade[]; shade0 = Reds 5 4; shade1 = Oranges 5 4; shade2 = Greens 5 4; shade3 = Blues 5 4; beginfig(1); numeric s, t; s = 256; t = 4; for n=0 upto (s/t*s/t-1): numeric h, v; h = floor 1/8 (n mod 32); v = n mod 4; fill fullcircle scaled t shifted (fizz(n) scaled s) withcolor (1/2 + 1/8 v)[white, shade[h]]; endfor; path xx, yy; xx = (left--right) scaled (s+8); yy = xx rotated 90; for i=-1 upto 1: draw xx shifted (0, s*i) withpen pencircle scaled 1/8; draw yy shifted (s*i, 0) withpen pencircle scaled 1/8; endfor dotlabel.lrt(btex $-1-i$ etex, (-1, -1) scaled s); dotlabel.lrt(btex $-1$ etex, (-1, 0) scaled s); dotlabel.lrt(btex $-1+i$ etex, (-1, 1) scaled s); dotlabel.lrt(btex $-i$ etex, (0, -1) scaled s); dotlabel.lrt(btex $+i$ etex, (0, 1) scaled s); dotlabel.lrt(btex $+1-i$ etex, (1, -1) scaled s); dotlabel.lrt(btex $+1$ etex, (1, 0) scaled s); dotlabel.lrt(btex $+1+i$ etex, (1, 1) scaled s); endfig; \end{smallcode} \vss}} $$\includegraphics[width=\textwidth]{double-dragon.pdf}$$ \vbox to 0pt{\noindent\small\textbf{Note}: you can adjust the “resolution” with the parameter $t$, but don't make it smaller than 1 if you are using the default number system; the diagram looks a bit strange unless $t$ is an integer power of 2.\vss} \newpage \section{Colours} \MP\ implements colours as simple numerics, or tuples of three or four numeric values. Three-tuples (which are type \mpl{color}) represent RGB colours; four-tuples (which are type \mpl{cmykcolor}) represent CMYK colours. Simple numerics are used to represent grey scale colours. The numeric values of the colours can take any \kw{numeric} value, but \MP\ only considers the range 0 to 1 --- values less than zero are treated as zero, values greater than 1 are treated as 1. So British Racing Green with RGB code "(1,66,37)", or Pillar Box Red with code "(223,52,57)", can be defined like this: \begin{code} color brg, pbr; brg = (0.00390625, 0.2578125, 0.14453125); pbr = (0.87109375, 0.203125, 0.22265625); \end{code} or, slightly more idiomatically: \begin{code} brg = 1/256 (1, 66, 37); pbr = 1/256 (223, 52, 57); \end{code} As you can see, you can apply implicit multiplication to a \mpl{color}, so after the declaration above "2 brg" would be a valid colour, although you have to think a bit to know what that means in terms of colour in your drawings. \vadjust{\moveright 384pt\vbox to 0pt{\kern-72pt To use RGB hex strings, you'll need to write a function: \begin{code} vardef hexrgb(expr Spec) = save r, g, b; numeric r, g, b; r = hex(substring (1,3) of Spec); g = hex(substring (3,5) of Spec); b = hex(substring (5,7) of Spec); 1/256(r,g,b) enddef; brg = hexrgb("#014225"); pbr = hexrgb("#df3439"); \end{code} \vss}}% Plain \MP\ defines five basic colour constants: \mpl{red}, \mpl{green}, \mpl{blue}, \mpl{white}, \mpl{black}. These are quite useful with leading fractions: \mpl{2/3 red} gives a nice dark red, that's good for drawing lines you want to emphasize; \mpl{1/2 white} gives you a shade of grey; and so on. But since \mpl{black} is defined as \mpl{(0,0,0)}, \mpl{1/2 black} just gives you \mpl{black}. You can also add up \mpl{colors}. So \mpl{red + 1/2 green} gives you a shade of orange; this is more long-winded than writing \mpl{(1, 0.5, 0)} but maybe slightly easier to read. Much more usefully, you can use the mediation notation to get a colour that is part way between two others. So \mpl{1/2[red, white]} gives you a shade of pink, and \mpl{2/3[blue, white]} a sort of sky blue. You can also use this idea to vary colour with data, as in \mpl{(r)[red, blue]} where \mpl{r} is some calculated value. \vadjust{\moveright 384pt\vbox to 0pt{\kern-36pt \begin{code} color brg; brg = 1/256 (1, 66, 37); color pbr; pbr = 1/256 (223, 52, 57); N = 5; n = 0; for y=1 upto N: for x=1 upto N: fill fullcircle scaled 16 shifted 20(x,y) withpen pencircle scaled 2 withcolor (n/N/N)[pbr, brg]; label(decimal incr n infont "phvr8r", 20(x,y)) withcolor white; endfor endfor \end{code}\vss}} Here's a toy example: \vbox to 0pt{\centerline{\includegraphics[scale=0.8]{color-blend-toy}}\vss} \newpage \subsection{CMYK colours} \MP\ also implements a CMYK colour model, using tuples of four numerics. This is more or less a direct mapping onto the PostScript "cmykcolor" functions. In this model the four components represent cyan, magenta, yellow, and black. White is \mpl{(0,0,0,0)} and black is anything where the last component is 1. Beware however that the constants, \mpl{white} and \mpl{black} are defined in "plain.mp" as RGB colours, and you can't mix the two models, so anything like \mpl{1/2[(1,1,0,0), white]} will not work. If you want to do lots of work with CMYK colours you might like to redefine the color constants. $$\includegraphics[width=0.7\textwidth]{blended-color-circles}$$ \hey The apparent blending of colours here is done by calculating the overlaps and filling them in order. In plain \MP, there is no support for transparency in any of the colour models; this is because they are inherited directly from PostScript. \moveright 384pt\vbox to 0pt{\vss \begin{code} % the illusion of blended colours is helped by buildcycle path C[], B[]; % arrange each circle so that point 0 is outside the others C1 = fullcircle scaled 120 rotated 90 shifted 40 up; C2 = C1 rotated 120; C3 = C2 rotated 120; B0 = buildcycle(C1, C2, C3); B1 = buildcycle(C1, C2); B2 = buildcycle(C2, C3); B3 = buildcycle(C3, C1); picture P; for x=0 upto 1: for y=0 upto 1: P := image( s := 1/4 + x/2; k := 0 + y/4; fill C1 withcolor s*(1,0,0,k); fill C2 withcolor s*(0,1,0,k); fill C3 withcolor s*(0,0,1,k); fill B3 withcolor s*(1,0,1,k); fill B2 withcolor s*(0,1,1,k); fill B1 withcolor s*(1,1,0,k); fill B0 withcolor s*(1,1,1,k); undraw C1; undraw C2; undraw C3; ) shifted -(200x, 200y); draw P; label.bot(("shade: " & decimal s & ", k: " & decimal k) infont "phvr8r", point 1/2 of bbox P); endfor endfor \end{code}} \newpage \subsection{HSV colours} HSV colours are colours defined by a triple of hue, saturation, and value. Unlike RGB and CMYK colours there is no native support in \MP\ but it is possible to write a routine that maps HSV triples into RGB colours: \begin{code} vardef hsv_color(expr h,s,v) = save chroma, hh, x, m; chroma = v*s; hh = h/60; x = chroma * (1-abs(hh mod 2 - 1)); m = v - chroma; if hh < 1: (chroma,x,0)+(m,m,m) elseif hh < 2: (x,chroma,0)+(m,m,m) elseif hh < 3: (0,chroma,x)+(m,m,m) elseif hh < 4: (0,x,chroma)+(m,m,m) elseif hh < 5: (x,0,chroma)+(m,m,m) else: (chroma,0,x)+(m,m,m) fi enddef; \end{code} This is based on information from the Wikipedia article on on “HSL and HSV”. \medskip\noindent The hue values in HSV colours map nicely to the familiar spectrum of the rainbow. In the model used here 0 is red, 120 green, and 240 blue: $$\includegraphics[width=0.85\textwidth]{color-hsv-gamut}$$ With less saturation the colours look faded; if you lower the value they get darker. Once you get the hang of them, they make choosing colours rather easier. You can produce ranges of colour by changing hue, or make gradations of a single colour by changing the saturation or value. \moveright 384pt\vbox to 0pt{\vss \begin{code} defaultfont := "phvr8r"; numeric s[], v[]; s0 = 1/2; v0 = 7/8; s1 = 7/8; v1 = 7/8; s2 = 7/8; v2 = 1/2; for y=0 upto 2: for h=0 step 15 until 360: fill fullcircle scaled 24 shifted (h, -32y) withcolor hsv_color(h, s[y], v[y]); draw fullcircle scaled 24 shifted (h, -32y) withcolor white; if y=1: label(decimal h infont defaultfont scaled 1/2, (h,-16)); fi endfor endfor label.urt("Less saturation", (-20,12)); label.lrt("Lower value", (-20,-76)); drawarrow (-15, -12) -- (-15,12); drawarrow (-15, -52) -- (-15,-76); \end{code}} \newpage \subsubsection{An HSV example of a graduated scale} \noindent This example requires the \mpl{hsv_color} routine from the previous page. \mpic{12pt}{color-hsv-bathymetric} \begin{code}[xleftmargin=0pt] defaultfont := "phvr8r"; defaultscale := 3/4; path h,d,b; numeric n; n = 10; h = ((-2,0)--(0,0)--(-1,3)--(-2,3)--cycle) scaled 60; d = h rotated 180; b = subpath (0,1) of h -- point 1+1/n of d -- (xpart point 0 of h, ypart point 1+1/n of d) -- cycle; fill b withcolor hsv_color(123, 1/8, 7/8); draw subpath (2.13,4) of b; for i=1 upto n: fill point 4-(i-1)/n of h -- point 1+(i-1)/n of h -- point 1+i/n of h -- point 4-i/n of h -- cycle withcolor hsv_color(42, 1/4 + 3/4 * i/n, 1 - i/3n); fill point 4-(i-1)/n of d -- point 1+(i-1)/n of d -- point 1+i/n of d -- point 4-i/n of d -- cycle withcolor hsv_color(200, i/n - 1/n, 1 - i/3n); endfor string s; for i=1 upto n-1: draw point 4-i/n of h -- point 1+i/n of h; draw point 4-i/n of d -- point 1+i/n of d; s := decimal if i < 4: (i**2+1) else: (10 + (i-3)*10) fi & "00"; label.rt(s, point 1+i/n of h); label.lft(s, point 1+i/n of d); endfor label.rt("Metres", point 2 of h); label.lft("Metres", point 2 of d); label.lft("Hypsometric tints" infont defaultfont scaled defaultscale rotated 90, point 7/2 of h); label.rt("Bathymetric tints" infont defaultfont scaled defaultscale rotated -90, point 7/2 of d); label.lft("sea level", point 0 of h); label("areas below sea level", center b); draw h; draw d; \end{code} \newpage \subsection{Grey scale} \moveright5.5in\vbox to 0pt{\vskip6pt \begin{code}[xleftmargin=0pt] numeric s; s = 13; path atom; atom = origin -- (2s,0) rotated -30 -- (2s,0) rotated -30 + (0,s) -- ( s,0) rotated 30 -- ( s,0) rotated 30 + (0,s) -- (0,2s) -- cycle; picture p[]; for i=0 upto 2: p[i] = image( fill atom rotated -120i withcolor (7/8 - 1/8i) ; draw atom rotated -120i; ); endfor n = 13; for i=-n upto n: for j=-n upto n: forsuffixes $=0,1,2: draw p$ shifted ((3i*s,0) rotated -30 + (0,floor(1/2i)*3s + 3j*s)); endfor endfor endfor clip currentpicture to (unitsquare shifted -(1/2,1/2) xscaled 55.425s yscaled 30s); \end{code} \vss} \noindent The \mpl{withcolor} command will also take a single \mpl{numeric} instead of a 3-tuple or a 4-tuple. This produces a colour in grey scale (or gray scale if you prefer the Webster spellings). Just as for the other colour types, values below 0 count as zero and values above 1 count as one. And since the smallest possible positive number in plain \MP\ is: $\id{epsilon} = 1/256/256;$ then you can have at most 65,536 shades in between. Grey scale is appropriate for some printed media, and can make effective textures and patterns. The code on the right was used to produce this: $$\includegraphics[width=\textwidth]{escher}$$ First a basic path (named $\id{atom}$) is defined, then in the first loop three picture variables, $p_1$, $p_2$, and $p_3$, are defined, each one rotated 120° from the previous and filled with a slightly darker shade of grey. The double loop then draws the three versions of the shape on an up-and-down grid. Finally the picture is clipped to a neat rectangle. \newpage \subsubsection{Drawing algorithmic shadows} \moveright5.5in\vbox to 0pt{\vskip6pt \begin{code}[xleftmargin=0pt] path b, w; b = ((-3,-4)--(3,-2)--(3,+2)--(-3,4)--cycle) scaled 5; w = b reflectedabout(up, down); numeric n; n = 128; picture B, W; B = image(for i=0 step 1/n until 1: draw point 4-i of b -- point 1+i**2 of b withcolor 1-i**8; endfor); W = image(for i=0 step 1/n until 1: draw point 4-i of w -- point 1+i**2 of w withcolor 3/4-i**8; endfor); for i=-9 upto 9: for j=-4 upto 4: draw if odd (i+j): W else: B fi shifted (i*30,j*30); endfor endfor clip currentpicture to bbox currentpicture yscaled 7/8; \end{code} \vss} \noindent Here is a more complex pattern, showing one way to create an illusion of shadows with multiple fine lines. $$\includegraphics[width=\textwidth]{shadows}$$ The first part defines two wedge-shaped closed paths, $\id{w}$ being the mirror image of $\id{b}$. Like the standard \id{unitsquare} path, the path $\id{b}$ is defined so that point 0 is the bottom left corner. The two $\kw{picture}$ variables are produced by drawing lines across the shapes from bottom to top. By setting $n$ high enough, these multiple lines blend smoothly to give an even colour. And by using higher powers of the index variable, an effective shadow can be drawn ‘bunched up’ into the top of each shape. By repeating them alternately in a grid, we get an effective texture, which is clipped at the end to a neat rectangle again. \newpage \subsection{Colorbrewer palettes}\label{colorbrewer} \moveright 384pt\vbox to 0pt{\vskip144pt\raggedright\hsize4in\noindent This map shows the "RdYlBu[9]" palette in action on a map of the Brexit vote in London. The outlines are the 33 London boroughs, and the colours show how we voted, faded by turnout. The data and the outlines are from publicly-available UK government sources. They were prepared for \MP\ using various Python scripts, and they are available in the source for this document. \vskip 72pt Here is the code for the palette used as the legend: \begin{smallcode} input colorbrewer-rgb numeric s; s = 10; for i = 1 upto 9: fill unitsquare scaled s shifted (i*s, 0) withcolor RdYlBu[9][i]; if i > 1: draw (i*s, 0) -- (i*s, s); fi endfor draw unitsquare xscaled 9s yscaled s shifted (s,0); label.top("Leave" infont "phvr8r", (s, s)); label.top("Remain" infont "phvr8r", (10s, s)); \end{smallcode} \vss} \noindent The well-known Colorbrewer website ("http://colorbrewer2.org") provides a useful set of colour palettes that are suitable for a wide range of applications. They were originally written for maps, but they are useful for many other types of drawing. If you are using an up-to-date, and complete, \TeX\ distribution, you should find that my implementation of them for \MP\ is already installed on your system, otherwise you can get it from "https://ctan.org/pkg/metapost-colorbrewer". The package provides two files that define all the colour ranges; one for CMYK and another for RGB; an example of usage is shown below on the right. $$\includegraphics[width=\textwidth]{brexit-map.pdf}$$ %-------------------------------------------- \newpage \section{Random numbers} \MP\ provides us with two built-in functions to generate random numbers. \vadjust{\moveright 384pt\vbox to 0pt{\kern-24pt \begin{code} vardef dice(expr pip_count, pip_color) = save d,r,p, ul, ur, lr, ll; r=1/8; path d; picture p; d = for i=0 upto 3: quartercircle scaled 3 shifted (15,15) rotated 90i -- endfor cycle; p = image(draw fullcircle scaled 6; fill fullcircle scaled 6 withcolor pip_color); pair ul, ur, ll, lr; ul = 1/5[ulcorner d, lrcorner d]; lr = 4/5[ulcorner d, lrcorner d]; ur = 1/5[urcorner d, llcorner d]; ll = 4/5[urcorner d, llcorner d]; image(fill d withcolor background; draw d; if odd(pip_count): draw p shifted center d; fi; if pip_count > 1: draw p shifted ul; draw p shifted lr; fi; if pip_count > 3: draw p shifted ur; draw p shifted ll; fi; if pip_count = 6: draw p shifted 1/2[ul,ur]; draw p shifted 1/2[ll,lr]; fi) enddef; beginfig(1); for i=0 upto 4: draw dice(1+floor uniformdeviate 6, red) rotated (2 normaldeviate) shifted (36i,0); endfor endfig; \end{code} $$\includegraphics{dice}$$ \vss}} \begin{itemize} \item `$\kw{uniformdeviate}\,n$' generates a random real number between $0$ and $n$. Note that the $n$ is required. It can be negative, in which case you get negative random numbers; or it can be zero, but then you just get $0$ every time. In other words the implementation generates a number $r$ such that $0\le r<1$ and then multiplies $r$ by $n$. If you want a random whole number, use `$\kw{floor}$' on the result. So to simulate six-sided dice, you can use `$1+\kw{floor}\,\kw{uniformdeviate}6$'. If you use the new number systems, and you find that the numbers generated are all multiples of $n/4096$, so $\kw{uniformdeviate} 8192$ (for example) generates even integers instead of random real numbers, then you should update your \TeX\ distribution. This `feature' was an accident of the original way that the scaled arithmetic routines were adapted. \item `\kw{normaldeviate}' generates a random real number that follows the familiar normal distribution. The algorithm used is discussed in \textsl{The Art of Computer Programming}, section~3.4.1. If you generate enough samples, the mean should be approximately zero, and the variance about 1. The chance of getting a number between $-1$ and 1 is about 68.3\%; between $-2$ and 2, about 95.4\%. \vadjust{\moveright 3.6in\vbox to 0pt{\hsize 1.6in \vskip21pt \noindent \small 10000 samples suggest\\\kw{normaldeviate} works.\par\vss}} $$\includegraphics[width=4.6in]{gaussian}$$ To relocate the mean, just add a constant. To rescale the distribution, multiply by the desired standard deviation (the square root of the desired variance). \end{itemize} \newpage\subsection{Random numbers from other distributions} The \kw{normaldeviate} function is provided as a primitive \MP\ operation. The implementation is based on the `Ratio method' presented in \textsl{The Art of Computer Programming}, section~3.4.1. It turns out to be very straightforward to implement the algorithm for this method as a user-level program $\longrightarrow$ \vadjust{\moveright5.5in\vbox to 0pt{\kern -64pt \begin{smallcode} vardef normaldeviate = save u, v, xa; forever: forever: u := uniformdeviate 1; exitif (u>1/64); endfor v := sqrt(8/mexp(256)) * ( -1/2 + uniformdeviate 1 ); xa := v/u; exitif ( xa**2 <= -mlog(u)/64 ); endfor xa enddef; vardef exponentialdeviate = save u; forever: u := uniformdeviate 1; exitif (u>0); endfor -mlog(u)/256 enddef; vardef gammadeviate(expr a,b) = save y, x, v, s, accept; boolean accept; s = sqrt(2a-1); forever: forever: y := tand(uniformdeviate 180); exitif y<64; endfor x := s * y + a - 1; accept := false; if x>0: v := uniformdeviate 1; if (v <= (1+y**2)*mexp((a-1)*mlog(x/(a-1))-(256*s*y))): accept := true; fi fi exitif accept; endfor x/b enddef; \end{smallcode} \vss}}% There are a couple points here. First, the inner loop around the assignment to $u$ is designed to avoid very small values that would cause $v/u$ to be larger than 64, and hence make "xa**2" overflow. This is a useful general technique, and justified in terms of the algorithm since large values of $v/u$ are rejected anyway. Secondly, the expression "sqrt(8/mexp(256))" is a constant ($ \sqrt{8/e} \simeq 1.71553 $) and could be replaced by it's value, but this does not make an appreciable improvement to the speed of the routine. On a modern machine, this routine is only very slightly slower than using the primitive function. It is also fairly straightforward to implement random number generators that follow other statistical distributions. The mathematical details are in the section of \textsl{TOACP} referenced above. Two examples, for the exponential distribution and the gamma distribution, are shown on the right. In both cases, note the care required to avoid arithmetic overflow (and see section~\ref{trig} for the "tand" function). \medskip\label{mexp}\noindent You can also see the special nature of \MP's \kw{mexp} and \kw{mlog} functions. They are defined so that $\kw{mexp} x = \exp(x/256)$ and $\kw{mlog} x =256\log(x)$. This is another artefact of the scaled number system. \MP\ computes $x^y$ using the formula "mexp(y*mlog(x))", and the adjusted log values give more accurate results. Note that this means that you have $e=\kw{mexp}(256)$. \medskip\noindent At the start of each job, \MP\ automatically sets a new seed for the random number generator, so that the sequence of numbers is different each time. But you can set this yourself if you need the same sequence each time. At the start of your program you should put "randomseed:=3.14;" (or whatever value you prefer). According to \textsl{The Metafont Book}, the default value is $\id{day}+\id{time}\ast\id{epsilon}$, but in \MP\ the exact value used depends on the resolution of the timers available on your system; essentially the value should be different every time you run \MP. \newpage\subsection{Random walks} You can use the random number generation routines to produce visualizations of random walks, with various levels of analysis. \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4.4in\kern -2\baselineskip \begin{code} beginfig(1); numeric w, h, n; w = 377; h = 80; n = 500; draw (origin--right) scaled w; draw (origin--right) scaled w shifted (0,+h/2) withcolor 3/4; draw (origin--right) scaled w shifted (0,-h/2) withcolor 3/4; pair zenith, nadir; zenith = nadir = origin; path walk[]; for i=1 upto 8: numeric y; y = 0; walk[i] = origin for x=w/n step w/n until w: hide( y := y if uniformdeviate 1 < 1/2: + else: - fi 1; if y > ypart zenith: zenith := (x,y) ; fi if y < ypart nadir: nadir := (x,y) ; fi ) -- (x,y) endfor; undraw walk[i] withpen pencircle scaled 3/4; draw walk[i] withcolor (1/2+y/h)[red, blue] endfor drawarrow (12 up -- 2 up) shifted zenith withcolor blue; drawarrow (12 down -- 2 down) shifted nadir withcolor red; endfig; \end{code} \smallskip\noindent \hey Note the \mpl{undraw} line using a slightly thicker pen; this makes it easier to follow the lines as they cross each other. \vss}} $$\includegraphics[width=\textwidth]{random-walks-red-blue}$$ In this example the random walk lines are coloured according to the final $y$-value, and the global maximum and minimum points are marked. Each walk is created with an `inline' for-loop; the loop is effectively expanded before the assignment, so that each \id{walk} variable becomes a chain of connected $(x,y)$ pairs. Inside the loop you can conceal yet more instructions in a `\kw{hide}' block. These instructions contribute nothing to the assignment, but can change the values of variables outside the block. Note the first line of the \kw{hide} block adds $\pm1$ to $y$ with equal probability. You can (of course) create different kinds of random walks, by changing the way you set this delta value, for example by using a different type of random variate, or scaling the value, or changing the odds in favour of one direction or the other. For example: \begin{code} y := y if uniformdeviate 1 < p: + 2 else: - 1 fi; \end{code} will set the delta to $+2$ with probability $p$ and and to $-1$ with probability $1-p$. \newpage\subsection{Brownian motion} A random walk is normally constrained to move one unit at a time, but if you relax that constraint and use `\kw{normaldeviate}' in place of `\kw{uniformdeviate}' you can get rather more interesting patterns.\vadjust{\moveright5.5in\vbox to 0pt{ \hsize4in\kern -20pt \begin{code} beginfig(2); for n=1 upto 4: x:=y:=0; draw (x,y) for i=1 upto 2000: hide(x:=x+4normaldeviate; y:=y+4normaldeviate;) .. (x,y) endfor withcolor ((n+2)/9)[blue,white]; fill fullcircle scaled 3 shifted (x,y) withcolor red; endfor % mark the origin fill fullcircle scaled 3 withcolor green; endfig; \end{code} \kern 120pt \noindent Using these random number generators means that the output is different each time because \MP\ produces a different sequence of numbers. You may find yourself running the program a few times until you find one you like. At this point you will wish that you knew what "randomseed" had been used, so that you can re-create picture. Unfortunately \MP\ does not log the value used, unless you set it manually. So here's a trick to use in this situation: set your own random seed using a random number at the top of your program. \begin{code} randomseed := uniformdeviate infinity; \end{code} Now \MP\ writes the (random) value used in the log for you to copy. Note that if you are using "luamplib" you need to add the "\mplibshowlog{enable}" option. \vss}} If you also allow the $x$-coordinates to wander at random as well as the $y$-coordinates you get two-dimensional random patterns. And if you replace the straight line segments "--" with ".." so that \MP\ draws a smooth curve through the points, as well as vary the colour each time you draw a new curve, then the result is almost artistic. \medskip\noindent \hbox to \textwidth{\includegraphics[width=1.2\textwidth]{brown3a}\hss} \newpage\subsection{Drawing freehand} This idea is shamelessly stolen from the wonderful collection of \MP\ examples available at "http://melusine.eu.org/syracuse/metapost/". But since the examples there are all in French (including all the names of the custom macros), perhaps it would be better to say `translated' rather than `stolen'; moreover my implementations are easier to use with plain \MP.\vadjust{\moveright5.5in\vbox to 0pt{ \hsize4in\kern -5.5\baselineskip \begin{smallcode} def freehand_segment(expr p) = point 0 of p {direction 0 of p rotated (4+normaldeviate)} .. point 1 of p {direction 1 of p rotated (4+normaldeviate)} enddef; def freehand_path(expr p) = freehand_segment(subpath(0,1) of p) for i=1 upto length(p)-1: & freehand_segment(subpath(i,i+1) of p) endfor if cycle p: & cycle fi enddef; defaultfont := "eurm10"; color sepia; sepia = (0.44, 0.26, 0.08); picture marker; marker = image(for s=-1/2, 1/2: draw (left--right) scaled 2 rotated 60 shifted (s,0); endfor); def moved_along expr x of p = rotated angle direction x of p shifted point x of p enddef; beginfig(1); pair A, B, C, D; A = (0,-30); B = (180,0); C = (120,90); D = (1/2 + 1/40 normaldeviate)[A, B]; path triangle, circumcircle, bisector; triangle = freehand_path(A--D--B--C--cycle); bisector = freehand_segment(C--D); circumcircle = freehand_path(A..B..C..cycle); draw triangle; draw bisector; draw circumcircle withcolor .67 red; draw marker moved_along 1/2 of triangle withcolor .67 red; draw marker moved_along 3/2 of triangle withcolor .67 red; label.lft("A", A); label.rt ("B", B); label.top("C", C); label.bot("D", D); endfig; \end{smallcode} \vss}} \subsubsection{Making curves and straight lines look hand drawn} $$\includegraphics{random-freehand-circumcircle}$$ A small amount of random wiggle makes the drawing come out charmingly wonky. Notice that the "freehand_path" macro will transform a path whether it is straight or curved, and open or closed. Notice also that to find $D$ the mid-point of a $AB$, you need to find the point along the freehand path; if you simply put "1/2[A,B]" there's no guarantee that the point would actually be on the free hand path between $A$ and $B$. In this case a little extra randomness has been added, and the two segments $AD$ and $DB$ have been marked with traditional markers to show that they are equal. The "moved_along" macro combines shifted and rotating to make the markers fit the wonky lines properly. The Euler font complements the hand-drawn look; but you might find that a little of this type of decoration goes a long way. \newpage \subsubsection{Extending straight lines slightly}\label{euler} This second freehand figure uses a macro to draw a wonky line through two points with a bit of overlap at each end. The overlap size is given using the suffix syntax. The lines are drawn in sepia ink to enhance the hand-drawn look. The angle labels are positioned on invisible arcs between neighbouring wonky lines. \vadjust{\moveright5.5in\vbox to 0pt{ \hsize4in\kern -4.5\baselineskip \begin{code}[xleftmargin=0pt] vardef freehand_through@#(expr a, b) = save t; pair t; t = @# * unitvector(b - a) rotated (4 + normaldeviate); a - t .. a {t} .. b {t} .. b + t enddef; vardef mid_arc@#(expr p, a, b) = save c; path c; c = fullcircle scaled (2*@#) shifted p cutbefore a cutafter b; point arctime 1/2 arclength c of c of c enddef; beginfig(1); defaultfont := "eurm10"; color sepia; sepia = (0.44, 0.26, 0.08); pair A, B, C; A = (0,-30); B = (180,0); C = (120,90); path a, b, c; a = freehand_through 7 (A, B); b = freehand_through 8 (B, C); c = freehand_through 6 (C, A); drawoptions(withcolor sepia); draw a; draw b; draw c; drawoptions(withcolor .67 blue); label.bot ("a", point 3/2 of a); label.rt ("b", point 3/2 of b); label.ulft("c", point 3/2 of c); drawoptions(withcolor .5 red); label(char 11, mid_arc 16 (A, a, c)); label(char 12, mid_arc 14 (B, b, a)); label(char 13, mid_arc 14 (C, c, b)); drawoptions(); endfig; \end{code} \vss}} $$\includegraphics{random-freehand-through}$$ \vfill \noindent\llap{\nb\ }The AMS Euler font available to \MP\ as "eurm10" is encoded as a subset of the \TeX\ math italic layout --- essentially it has all the Greek letters but none of the arrows, nor the musical notation. $$\includegraphics{euler-sampler}$$ If you can't get the upper case $\Gamma$ at \mpl{char 0}, then you might be running an old out-of-date version of "luamplib". \newpage\subsection{Increasingly random shapes of the same size} If you want a random-looking shape, the general approach is to find a method to make a path that allows you to inject some random noise at each point of the path. $$\hbox to \textwidth{\includegraphics{random-shapes}\hss}$$ For these shapes the objective was to make them increasingly random, but to keep them all the same length.\vadjust{\moveright5.5in\vbox to 0pt{ \hsize4in \begin{code} beginfig(1); numeric desired_length, n, s; desired_length = 180; n = 30; s = 80; for r=0 upto 8: path shape; shape = for i=1 upto n: (s + r * normaldeviate, 0) rotated (360/n*i) .. endfor cycle; shape := shape scaled (desired_length/arclength shape); draw shape shifted (r*s, 0) withcolor (r/8)[black,red]; label(decimal r, (r*s, 0)); endfor endfig; \end{code} \vss}} Each time round the outer loop the \id{shape} is redeclared to clear it, and then redefined by an inline-loop with $n$ steps like this: \begin{code} shape = for i=1 upto n: (s,0) rotated (360/n*i) .. endfor cycle; \end{code} except that some random noise is added to the $s$ at each step: when the noise is zero ($\id{r}=0$) you get a circle; as the noise increases the circle is increasingly distorted. The scaling is done using the \mpl{arclength} operator. This works like \mpl{length} but instead of telling you the number of points in a path, it returns the actual length as a dimension. Dividing the desired length by this dimension gives the required scaling factor for the random shape just defined. Notice that you have to do this in two steps, and update the shape using ":=". This is because you need to have defined \id{shape} before you can refer to it. \newpage\subsection{Explosions and splashes} Random numbers are also useful to make eye catching banners for posters, presentations, and infographics. Here are two simple example shapes: $\to$ \mpic{18pt}{explode} \begin{smallcode} string heavy_font; heavy_font = "PlayfairDisplay-Black-osf-t1--base"; randomseed:=2128.5073; beginfig(1); n = 40; r = 10; s = 50; path explosion, splash; explosion = for i=1 upto n: (s if odd(i): - else: + fi r + uniformdeviate r,0) rotated (i*360/n) -- endfor cycle; splash = for i=1 upto n: (s if odd(i): - else: + fi r + uniformdeviate r,0) rotated (i*360/n) .. endfor cycle; splash := splash shifted (3s,0); fill explosion withcolor 1/2 green + red; draw explosion withpen pencircle scaled 2 withcolor 2/3 red; label("BOOM!" infont heavy_font scaled 2, center explosion) withcolor red; fill splash withcolor 1/2 green + blue; draw splash withpen pencircle scaled 2 withcolor 2/3 blue; label("SPLAT!" infont heavy_font scaled 2, center splash) withcolor blue; endfig; \end{smallcode} \noindent In this figure "n" is the number of points in the shape, "r" is the amount of randomness, and :"s" is the radius used. In order to get a clear zig-zag outline, the loop alternately adds or subtracts "r"; and then adds a random amount on top to make it look random. Notice that the only difference between the "explosion" and "splash" is that how the connecting lines are constrained to be straight or allowed to make smooth curves.\vadjust{\moveright5.5in\vtop to -2pt{\hsize 4in\vss\noindent The display font used here is one of the gems hidden away in "psfonts.map". If you run \MP\ with the "-recorder" option, it will create a list of all the files used, with the current job name and an extension of ".fls". This file will include a line which tells you exactly which version of "psfonts.map" is being used. The DVIPS documentation explains the format of the file, but for \MP's purposes the first word of each non-comment line defines a font name you can try. However beware that just because a name is defined in your map file, does not necessarily mean that you actually have the required PostScript font files installed as well. But if you have a full TexLive installation you will find that very many of them are already installed.\strut }} \newpage\subsection{Simulating jagged edges or rough surfaces} You can use the idea of adding a little bit of noise to simulate a rough surface. $$\includegraphics[width=0.95\textwidth]{qed}$$ These diagrams are supposed to represent light rays reflecting from a surface: on the left the surface is smooth ($r=0$) and on the right it's rough ($r=0.42$). The parameter $r$ is used in the \MP\ program as a scaling factor for the random noise added to each point along the rough surface; the only difference in the code to produce the two figures was the value of $r$.% \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss \begin{smallcode} def perpendicular expr t of p = direction t of p rotated 90 shifted point t of p enddef; beginfig(1); u = 5mm; r = 0.42; n = 32; s = 8u; theta = -45; path base; base = origin for i=1 upto n-1: -- (i/n*s,r*normaldeviate) endfor -- (s,0) -- (s,-u) -- (0,-u) -- cycle; fill base withcolor .8[blue,white]; draw base withcolor .67 blue; path ray[]; for i=2 upto 6: ray[i] = (left--right) scaled 2/3 s rotated theta shifted (i*u,0); b := ypart (ray[i] intersectiontimes base); ray[i] := point 0 of ray[i] -- point b of base -- point 0 of ray[i] reflectedabout(point b of base, perpendicular b of base); drawarrow ray[i]; endfor label("r=" & decimal r, center base); endfig; \end{smallcode} \vss}} First the base block is created with some noise on the upper side. Then five rays are created. Applying \mpl{ypart} to the pair of times returned by \mpl{intersectiontimes} gives us the point of the base where the incident ray hits it. This point and the perpendicular at that point are then used to get the angle for the reflected ray. The diagrams are effective because the rays are reflected at realistic looking angles. The simple approach to adding noise along a path works well in most cases provided there's not too much noise, but it is always possible that you'll get two consecutive values at opposite extremes that will show up as an obtrusive jag in your line. To fix this you can simply run your program again to use a different random seed value; or you could try using ".." instead of "--" to connect each point, but beware that sometimes this can create unexpected loops. \newpage\subsubsection{Walking along a torn edge} It's also possible to use a random walk approach so that each random step takes account of the previous one to avoid any big jumps. Here's one way to do that. $$\includegraphics{torn-edge-straight}$$ \begin{code} path t; numeric x, y; x = 0; y=0; t = (x, -20) -- (x, y) for i=1 upto 288: -- (incr x, walkr y) endfor -- (x, -20) -- cycle; draw t withcolor .67 blue; \end{code} The "walkr" routine works like the "incr" and "decr" commands; it updates the value of the argument. The idea is that the further away from zero you are, the more likely is that the next value will take you back towards zero. \begin{code} vardef walkr suffix $ = $ := $ if uniformdeviate 1 < (2**-abs($)): + else: - fi signr $; $ enddef; vardef signr suffix $ = if $<0: - else: + fi uniformdeviate 1 enddef; \end{code} You can use this to produce more realistic torn edges. You can also apply this as a form of jitter to a curved path, by adding a suitably rotated vector to enough points along the path. \moveright5.5in\vbox to 0pt{\kern-4in \begin{code} path c; c = fullcircle scaled 200; draw c withcolor .8 white; y=0; n = 600; path t; t = for i=0 upto n-1: point i/n*length(c) of c + (0, walkr y) rotated angle direction i/n*length(c) of c -- endfor cycle; draw t withcolor .67 red; \end{code} $$\includegraphics{torn-edge-circle}$$ \vss} \newpage \section{Plane geometry} \noindent\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\kern-9pt\noindent Here is the equilateral triangle point macro in action. $$\includegraphics{geometry-triangles-on-circle}$$ \vskip -12pt \begin{code} beginfig(1); path c; c = fullcircle scaled 144; pair a,b,p,q; for i=0 upto 7: a := point i of c; b := point i+1 of c; p := equilateral_triangle_point(a,b); q := equilateral_triangle_point(b,a); draw a -- p -- b withcolor .67 green; draw a -- q -- b withcolor .67 red; endfor draw c withcolor .53 blue; endfig; \end{code} \vss}}% This section deals with drawing geometrical figures that involve lines, angles, polygons, and circles. Plain \MP\ provides very few tools that are explicitly designed to help draw geometric figures, but it is usually possible to find an elegant construction using these tools and the relevant primitive commands. It is tempting to build up your own library of special purpose macros, but experience suggests that it is often better to adapt a general technique to the task in hand, and to create a specific solution to your current problem. One of the main issues is catching exceptions; since it is hard to write completely general macros, I have tried simply to present each technique so that you can understand it and adapt it as required. The classical constructions from Euclid's \textsl{Elements} are often useful sources of inspiration for macros, but they do not always point in the right direction. For example consider the first proposition: \textit{given two points find a third point, so that the three points make an equilateral triangle}. Euclid's construction is to draw an arc, with radius equal to the length of the segment between the two points, at each point and find the intersection. This might lead us to a function like this: \begin{code} vardef equilateral_triangle_point(expr a, b) = save c; path c; c = fullcircle scaled 2 abs(b-a); (c shifted a intersectionpoint c shifted b) enddef; \end{code} This works but has a couple of issues. First using \mpl{intersectionpoint} feels a bit like cheating; secondly, and more seriously, the point returned depends on the orientation of the points "a" and "b". In some configurations the first intersection found will be on the left, in others on the right. We could fix this by rotating the circle "c" by "angle (b-a)", but we can do better with a simple rotation of the second point about the first: \begin{code} vardef equilateral_triangle_point(expr a, b) = b rotatedabout(a,60) enddef; \end{code} And if you want to get right back to primitives you could even write that as: \begin{code} vardef equilateral_triangle_point(expr a, b) = b shifted -a rotated 60 shifted a enddef; \end{code} \newpage \subsection{Bisecting lines and paths} \moveright5.5in\vbox to 0pt{\hsize4in\noindent $$\includegraphics{mediation-pitfall}$$ \vskip 50pt $$\includegraphics[width=4in]{mediation-shapes}$$ \bigskip $$\includegraphics[width=4in]{mediation-sallows}$$ \centerline{\textsl{Lee Sallows' theorem of median triangles}} \vss} \noindent The best way to bisect a line depends on how you have defined it. If you have two pairs $a$ and $b$, then the simplest way to find the pair that bisects them is to write "1/2[a,b]". This mediation mechanism is entirely general, so you can write \mpl{1/3[a,b]}, "1/4[a,b]", and so on to define other pairs that are part of the way from $a$ to $b$. The expression "0[a,b]" is equal to $a$, and "1[a,b]" is equal to $b$; but the number before the left bracket does not have to be confined to the range $(0,1)$. If you write "3/2[a,b]" you will get a pair on the extension of the line from $a$ to $b$ beyond $b$. To get a pair going the other way you can either reverse $a$ and $b$, or use a negative number; but don't get caught out by the \MP\ precedence rules: "-1/2[a,b]" is interpreted as "-(1/2[a,b])" and not as "(-1/2)[a,b]", so either put in the parentheses or swap the order of the pairs: "(3/2)[b,a]". See $\longrightarrow$. If you want to work with a \kw{path} variable, rather than separate \kw{pair} variables, you can use the \mpl{point t of p} notation to do mediation along the path. For a simple straight path $p$ of length 1 then \mpl{point 1/2 of p} will give you the midpoint. More generally, \mpl{point 1/2 length p of p} will give you the midpoint of a path of any length. This works fine for simple paths, along which \MP's time moves evenly, but for more complicated, curved paths you have to use this rather cumbersome notation: \begin{code} point arctime 1/2 arclength p of p of p \end{code} If your path is closed, and makes a triangle or a regular polygon, then you can bisect it with the line \begin{code} point t of p -- point t + 1/2 length p of p \end{code} \textbf{NB}: if the polygon has an odd number of sides, then $2t$ must be a whole number. \smallskip\noindent In a triangle these bisecting lines are called medians. The three medians intersect at the centroid of the triangle. The centroid is a good place to put a label on a triangle. You could find it \mpl{intersectionpoint} or with a construction using \mpl{whatever} on any two medians, but since we know that the centroid divides each median in the ratio $2:1$ we can find the centroid of a triangle path $p$ most simply with: \begin{code} z0 = 2/3[point 0 of p, point 3/2 of p]; \end{code} The median is the basis for several beautiful theorems about the geometry of the triangle. The theorem shown here was first published in 2014. \newpage \subsection{Bisecting angles}\label{sec:bisect} \moveright5.5in\vbox to 0pt{\hsize4in\noindent $$\includegraphics{bisection-euclidean}$$ \smallskip $$\includegraphics{bisection-vector}$$ \vss} \noindent In an equilateral triangle the medians also bisect the angles at each vertex; this is the basis of Euclid's method of bisecting an angle set out in the Second Proposition. You can do the same in \MP, but it might not always be the best way. Whatever approach you take, an angle is defined by three points; one that defines the corner and two that define the lines extending from that corner. In this exploration I've used $a$, $b$, and $c$ to represent the points, with $b$ being the one in the middle, and at the corner. Euclid's method is to draw an arc centred at the corner, and then construct an equilateral triangle on the two points where the arc crosses the lines. This is shown on the right, with a macro that re-uses the equilateral triangle point macro given above. But if your aim were to find any point on the line bisecting $\angle ABC$, then you could simplify this and make it more efficient by using $e = \frac12[p,q]$ instead of calling the triangle macro at all. However the macro is still making two calls to \mpl{intersectionpoint}. If you wanted to eliminate this you could use the useful plain \MP\ macro "unitvector" to produce a solution based on adding two equal length vectors from the corner to the two other points. Another approach is to exploit another geometric theorem that states that the bisector of an angle in a triangle divides the opposite side in the ratio of the two other sides. So if sides $AB$ and $BC$ have lengths $p$ and $q$ then the bisector will be ${p\over p+q}={1\over1+q/p}$ from $A$ to $C$, and you can express this simply using \MP's mediation syntax: \vbox to 0pt{ $$\includegraphics{bisection-interior}$$ \vss} \newpage \subsection{Trisections and general sections of angles} There is no classical method to trisect an arbitrary angle, so you need to resort to measuring and arithmetic in \MP. If the angle is a given this is trivial: \mpic{-12pt}{trisection-simple.pdf} \begin{smallcode} path ray; numeric theta; ray = origin -- 200 right; theta = 42; draw ray; draw ray rotated 1/3 theta withcolor 2/3 red; draw ray rotated 2/3 theta withcolor 2/3 red; draw ray rotated theta; dotlabel.llft("$0$", origin); label("$\theta/3$", 72 right rotated 1/6 theta); label("$\theta/3$", 72 right rotated 3/6 theta); label("$\theta/3$", 72 right rotated 5/6 theta); \end{smallcode} But if you have only the coordinates of some points then you need to use the \mpl{angle} primitive to measure the angle first; \mpl{angle} takes a \kw{pair} argument and returns a numeric representing the angle in degrees measured clockwise from the $x$-axis to a line through the origin and the point represented by the pair. This definition means that if you have three points $A$, $B$, and $C$, then you can measure $\angle ABC$ with \mpl{angle(C-B)-angle(A-B)}. Following the usual convention this gives you the angle at $B$; if you list the points in clockwise order you will get a positive result. If you don't care about the order, you can make this into a more robust macro: \begin{smallcode} vardef measured_angle(expr P, Q, R) = (angle (P-Q) - angle (R-Q)) * turningnumber (P--Q--R--cycle) mod 360 enddef; \end{smallcode} The primitive \mpl{turningnumber} is explained on p.\thinspace 111 of \textsl{The METAFONTbook}. It takes a closed path and returns number of times that you would turn through 360${}^\circ$ if you traversed the path. We use this here to negate the measured angle if necessary, so that you always get the interior angle. The \mpl{mod 360} on the end ensures that the result is in the range $0 \le \theta < 360$. Armed with a measured angle, all you then need is arithmetic. \mpic{-160pt}{trisection-classical.pdf} It might be possible to use the \id{solve} macro to simulate the Neusis construction (that allows you to measure a length) illustrated on the right, but measuring the angles is rather easier. \newpage \subsection{Intersections}\label{sec:intersect} \moveright5.5in\vbox to 0pt{\hsize4in\noindent \centerline{A puzzle square featuring some intersections} $$\includegraphics[width=3in]{magic-square-14}$$ The points were defined like this (the order was important). \begin{code} z1 = (10,10); z4 = 144 right rotated 12; z5 = z4 shifted (2, 78); z7 = z4 reflectedabout(origin, (1,1)); z2 = 1/2 [z5, z7]; z9 = whatever [z1, z4]; z2-z9 = whatever * (z7-z1); z8 = whatever [z1, z5] = whatever [z2, z4]; z3 = whatever [z2, z9] = whatever [z4, z7]; z6 = whatever [z1, z7] = whatever [z3, z5]; \end{code} \vss} \noindent If you have line segments defined by their endpoints, then the canonical way to find their intersection, is to use the mediation syntax with \id{whatever} twice: $$\includegraphics[width=\textwidth]{whatever.pdf}$$ The mediation syntax works even if the intersection point does not actually lie on either of the two line segments. The intersection will be the point where the two (infinite) lines through the pairs of points meet. If the two lines are parallel, you'll get an `inconsistent equation' error. If you want to capture the calculated values, then use undefined numeric variables instead of \id{whatever}: \begin{code} z0 = alpha [z1, z2] = beta [z3, z4]; \end{code} In this example you would find $\alpha=0.286$ and $\beta=0.5$. If you are trying to find where the line through your points intersects a horizontal or vertical, then you only need one mediation and a simple equation for the relevant $x$ or $y$ coordinate: \begin{code} z0 = alpha [z1, z2]; x0 = 0; % for example \end{code} If you have defined your lines as paths, and especially if they are more complicated than straight lines, you need to use the \mpl{intersectiontimes} primitive or the \mpl{intersectionpoint} macro, as explained on pp.136–137 of \mfbook. \newpage \subsubsection{The intersection algorithm} \MP\ inherits a fast algorithm for finding the intersection between two paths from \MF. It is explained rather more gnomically than usual at the end of Chapter 14 of \mfbook, with more detail given in the web source for \MF. The core algorithm works on paths of length 1. If you have longer paths, \MP\ works its way along the paths applying the core algorithm to successive pairs of unit subpaths. It does this is lexicographic order; this means that, if you have two circles $A$ and $B$, and you do this: \begin{code} (t, u) = A intersectiontimes B; \end{code} then \MP\ will first look for an intersection between subpath $(0,1)$ of $A$ and subpath $(0,1)$ of $B$, then subpath $(0,1)$ of $A$ and subpath $(1,2)$ of $B$, and so on, with $B$ varying faster, until you get to subpath $(7,8)$ of $A$ and subpath $(7,8)$ of $B$. But you may never get that far, as the process stops as soon as the first intersection is found. The upshot of this is that the intersection point found will always be as early as possible on $A$. Note that after the call above point $t$ of $A$ will be very close to point $u$ of $B$, as they both refer to the same intersection point. If you want the alternative point that is earlier on $B$, then use `$B \mathbin{\textrm{intersectiontimes}} A$' instead.\mpic{-222pt}{intersection-AB-or-BA} \vfill\noindent When we get down to paths of length 1, the algorithm works something like this: $$ \includegraphics{intersection-algorithm} $$ \vadjust{\moveright 384pt\vbox to 0pt{\hsize 4.2in\vss \noindent The two paths are represented as rectangles that enclose the end points and the control points for each path. If these rectangles don't overlap then there is certainly no intersection. Otherwise \MP\ bisects each path and considers four smaller rectangles, in the order $(1,2)$, $(1,4)$, $(3,2)$, $(3,4)$ (as shown). In this case it will pick $(1,2)$, discard 4, and push 3 onto a stack. It carries on doing this, back tracking as required, until it finds sufficiently small overlapping rectangles. The two times returned by \mpl{intersectiontimes} are the midpoints of the subpaths enclosed by these two tiny rectangles, which is why they do not always refer to exactly the same point.}} \subsubsection{Finding all intersection points} As noted above, the \mpl{intersectiontimes} algorithm will stop at the first intersection of the two paths, but it is possible that the two paths will intersect again further along. If you want to find all the intersection points then the simplest technique is just to unwrap the algorithm slightly, and loop through all the unit subpaths applying \mpl{intersectiontimes} to each pair. Using an array to hold the points and a counter, you can get them with something like this: \begin{smallcode} pair P[], times; numeric n; n = 0; for i = 1 upto length(A): for j = 1 upto length(B): times := subpath (i-1,i) of A intersectiontimes subpath (j-1,j) of B; if xpart times > -1: P[incr n] = 1/2[point xpart times of subpath (i-1,i) of A, point ypart times of subpath (j-1,j) of B]; fi endfor endfor \end{smallcode} and then use them like this: \begin{smallcode} for i=1 upto n: draw fullcircle scaled 4 shifted P[i]; % or whatever endfor \end{smallcode} There are a couple of \MP\ technical points to note. The \mpl{intersectiontimes} operation returns a pair, which we assign to a pair variable $\id{times}$ above; we have to use \mpl{:=} to re-assign it in each loop, and we have to use an explicit pair variable because you can't assign to a literal pair; \MP\ will give you an error if you try \mpl{(t, u) := A intersectiontimes B;}. This may come as a surprise, because you \textit{can} legally do \mpl{(t, u) = A intersectiontimes B}, but in a loop this causes an inconsistent equation error on the second iteration. If you need to avoid the repeated use of \mpl{xpart} and \mpl{ypart}, one alternative is to do this inside the loop: \begin{smallcode} ... numeric t, u; (t, u) = A intersectiontimes B; ... \end{smallcode} Now the numerics are reset each time and the equation is not inconsistent. \vadjust{\moveright 384pt\vbox to 0pt{\hsize 4.2in\vss \noindent T\textsc{he} technique discussed on the left, works well on paths where the points on one or both of the paths are close together, so that the unit subpaths are short; But it is possible to create quite long paths of unit \mpl{length} and these may intersect each other more than once, like so: $$\includegraphics{intersection-only-two}$$ Here the two paths $A$ and $B$ are Bézier splines of with \mpl{length=1}, so the normal \MP\ algorithm is only ever going to give you one of the intersections. In the diagram above, the red circle marks the point given by \mpl{A intersectiontimes B}. We can try reversing the first path, and in this case you get the point marked in blue, but what about the one in the middle? The most reliable approach is to take a copy of one of the paths, and snip it off at the intersection and try again until there is nothing left to snip. $$\includegraphics{intersection-all-three}$$ The three points marked here were captured like this: \begin{code} pair P[]; numeric n; n=0; path R; R := A; % take a copy of A forever: R := R cutbefore B; % snip where we cross B exitif length cuttings = 0; % stop if nothing was cut P[incr n] = point 0 of R; % capture the point R := subpath (epsilon, infinity) of R; % nudge along endfor \end{code} This technique also works on paths with \mpl{length} greater than one, so you may prefer it as your general “get all the intersections” approach. Note that the \mpl{cutbefore} macro is defined using \mpl{intersectiontimes}. \kern 6.5pt }} \subsection{Parallel and orthogonal or whatever}\label{sec:parallel} Given five known points --- $A$, $B$, $C$, $D$, and $E$ --- \MP\ can find the point $F$ on the line $A \to B$, so that $E \to F$ is parallel to $C \to D$ like this: \mpic{0pt}{parallel} \begin{code} F = whatever[A, B]; % F is on the line A..B E-F = whatever * (C-D) % E..F || C..D \end{code} In the second line the expressions \mpl{E-F} and \mpl{C-D} return \ variables and the equation with \mpl{whatever} says that they must be scalar multiples of each other. With the first equation, this is enough for \MP\ to work out where $F$ should go. Note that \mpl{whatever} can take any real value, positive or negative, so it does not matter whether you put \mpl{E-F} or \mpl{F-E}. Note also that for the same reason, while $F$ will lie on the \textit{line} through $A$ and $B$, it might not lie on the \textit{segment} from $A$ to $B$. But also note that you \textit{cannot} write the second equation as \begin{code} E-F * whatever = (C-D); % <--- gives an error \end{code} because you can only apply \mpl{whatever} to known quantities. \bigskip\noindent\llap{\nb}% To define a line perpendicular to $C\to D$ rather than parallel, then you can write: \begin{code} G = whatever[A, B]; E-G = whatever * (C-D) rotated 90; \end{code} and obviously the "90" can be adjusted to whatever angle you please, if you want something between parallel and orthogonal. \smallskip\noindent\llap{\nb}% To define the line through $E$ that is perpendicular to $A\to B$, you should just use $(A-B)$ instead of $(C-D)$. The diagram shows $H$, the point on $A\to B$ that is closest to $E$; you can (I trust) work out how to define that yourself. \smallskip\noindent\llap{\nb}% If you just need to compute the perpendicular distance from the point $E$ to a line $A\to B$, rather than defining the point $H$, then you can use Knuth's ‘slick’ formula: \begin{code} abs ypart ((E-A) rotated -angle (B-A)) \end{code} This effectively rotates $E$ about $A$ by the angle of the line, so that the problem is reduced to measuring the height of a point above the $x$-axis, which is what \mpl{ypart} does, of course. \moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent There are some limitations to what you can do with \MP's linear equations; for one thing you can't generally say things like \mpl{length(C-A) = 72}. If you want to find the two points on a line that are a given distance from an external point, it's often simpler to find the intersection points of the line with a suitably scaled and shifted circle, even if you don't actually then draw the circle. You can usually find the other point by reversing the circle.\par} \newpage \subsection{Drawing circles}\label{sec:circles} The canonical way to draw a circle in plain \MP\ is to use the pre-defined path \mpl{fullcircle} with a suitable transformation. \mpic{-12pt}{drawing-circles.pdf} The path is defined (in "plain.mp") using two \MP\ primitive commands: \begin{code} path fullcircle; fullcircle = makepath pencircle; \end{code} A \kw{pencircle} is the basic nib that is used to draw lines that digitize neatly; it represents a true circle of diameter 1, passing through the points $(\pm.5, 0)$ and $(0, \pm.5)$. When processed with \kw{makepath} it turns into a closed polygonal path with eight points that closely approximates a circle with diameter 1\unit{bp} centred on the point $(0, 0)$. To use it, you can scale it and shift it. To draw a circle with radius 2\unit{cm} at the point $(34, 21)$ you would do: \begin{code} draw fullcircle scaled 4cm shifted (34, 21); \end{code} Remember to scale before you shift, and that \id{fullcircle} has unit \textit{diameter}, not unit \textit{radius}. To draw a circle centred at point $A$ that passes through point $B$ [\red{I}] try: \begin{code} draw fullcircle scaled 2 abs (B-A) shifted A; \end{code} There are of course an infinite number of circles that you can draw through two points, but if the line between the two points is a diameter [\blue{II}], then you can do: \begin{code} draw fullcircle scaled abs (B-A) shifted 1/2[A,B]; \end{code} Finally three points define a unique circle [\green{III}]: \begin{code} vardef circle_through(expr A, B, C) = save o; pair o; o = whatever * (A-B) rotated 90 shifted 1/2 [A,B] = whatever * (B-C) rotated 90 shifted 1/2 [B,C]; fullcircle scaled 2 abs (A-o) shifted o enddef; \end{code} Plain \MP\ also defines \id{halfcircle} and \id{quartercircle}, as the appropriate subpaths of \id{fullcircle}, both starting at point 0 (3 o'clock). Curiously, this differs from \MF\ where \id{quartercircle} is defined first, and the other two composed from it. The reference point of these two paths is the center of the complete circle of which they would be part; so if you did “\kw{draw} \id{quartercircle} \kw{shifted} $(34, 21)$;”, you would get an quarter-circle arc from $(34.5,21)$ to $(34,21.5)$. \newpage \subsection{Incircle and excircle of a triangle} The incircle of a triangle is the largest circle contained in the triangle. The centre of the incircle lies at the intersection of the internal angle bisectors. So we can use ideas from §\ref{sec:bisect} and §\ref{sec:intersect} to define a macro that returns the required path given points $A$, $B$, and $C$: \mxpic{-1in}{5in}{incircle} \begin{code} vardef incircle(expr A,B,C) = save a, b, m, t; pair a, b, m, t; a = A + unitvector (C-A) + unitvector (B-A); b = B + unitvector (A-B) + unitvector (C-B); m = whatever[A,a] = whatever [B,b]; t = whatever[A,B]; t-m = whatever * (B-A) rotated 90; fullcircle scaled 2 abs (t-m) shifted m enddef; \end{code} \bigskip\noindent The excircles of a triangle are the three circles lying outside the triangle and tangent to one edge and the extensions of the other two. The centres of each excircle lie at the intersection of one internal angle bisector and the external angle bisector of one of the other corners. To get the external angle bisector, all you have to do is reverse the direction of one of the \mpl{unitvector} calls: \mxpic{0pt}{5in}{excircle} \begin{code} vardef excircle(expr A,B,C) = save a, b, m, t; pair a, b, m, t; a = A + unitvector (C-A) - unitvector (B-A); b = B + unitvector (A-B) + unitvector (C-B); m = whatever[A,a] = whatever [B,b]; t = whatever[A,B]; t-m = whatever * (B-A) rotated 90; fullcircle scaled 2 abs (t-m) shifted m enddef; \end{code} \smallskip\noindent To get the other excircles, call the macro with the points in a different order. \newpage \subsection{Circumcircle of a triangle} The circumcircle of a triangle is the circle through the three corners, so if you already have the corners of your triangle as separate \ variables, you can use the \mpl{circle_through} macro from §\ref{sec:circles}. Or you can adapt the macro to take a single triangular path: \begin{smallcode}[xleftmargin=0pt, xrightmargin=-60pt] vardef circumcircle(expr T) = save m; pair m; m = whatever * (point 0 of T - point 1 of T) rotated 90 shifted point 1/2 of T = whatever * (point 1 of T - point 2 of T) rotated 90 shifted point 3/2 of T; fullcircle scaled 2 abs (point 0 of T - m) shifted m enddef; \end{smallcode} Note that as the diagram on the right shows,\mxpic{-2in}{4.6in}{circumcircle} the centre of the circumcircle is the intersection of all three of the perpendicular bisectors of sides, but for the purposes of drawing in \MP\ you only need to find the intersection of two of them. You could write \begin{smallcode}[xleftmargin=0pt, xrightmargin=-60pt] m = whatever * (point 0 of T - point 1 of T) rotated 90 shifted point 1/2 of T = whatever * (point 1 of T - point 2 of T) rotated 90 shifted point 3/2 of T = whatever * (point 2 of T - point 3 of T) rotated 90 shifted point 5/2 of T; \end{smallcode} but this does not add any more information to the equation for $m$, and \MP\ will sometimes give you an “inconsistent equation” error if your triangle is long and thin. \vfill \noindent \hey The marks that show line segments are equal were created by this macro. \begin{code} vardef mark_equal(expr a, b, n) = save m, s; numeric s; 2s = n - 1; picture m; m = image(for t=-s upto s: draw (down--up) scaled 2 rotated -13 shifted (t,0) withpen pencircle scaled 1/4; endfor); draw m rotated angle (b-a) shifted 1/4[a,b]; draw m rotated angle (b-a) shifted 3/4[a,b]; enddef; \end{code} Given the triangular \ $T$, the macro was used like this: $\longrightarrow$\vadjust{\moveright5.5in\vbox to 0pt{\vss \begin{code} mark_equal(point 0 of T, point 1 of T, 1); mark_equal(point 1 of T, point 2 of T, 2); mark_equal(point 2 of T, point 0 of T, 3); \end{code}}} \newpage \subsection{The nine-point circle of a triangle} The orthocentre of a triangle is the point is the intersection of the three altitudes, shown as point $D$ below. The point $N$, half-way from $D$ to the circumcentre $M$ is the centre of the remarkable nine-point circle which passes through the bases of the three altitudes and bisects the six line segments $AB$, $AC$, $AD$, $BC$, $BD$, and $CD$.\vadjust{\moveright5.2in\vbox to 0pt{\hsize 4in\vskip-80pt\noindent \begin{smallcode} pair A, B, C, D, N, M, p, q, r; A = origin; B = 377 dir 10; C = 233 dir 70; % pedal points (not labelled) p = whatever[B, C]; A - p = whatever * (B-C) rotated 90; q = whatever[C, A]; B - q = whatever * (C-A) rotated 90; r = whatever[A, B]; C - r = whatever * (A-B) rotated 90; D = whatever[A, p] = whatever[B, q]; N = 1/4(A + B + C + D); % remarkably... M = D rotatedabout(N, 180); % M is also the circumcentre path circumcircle, nine_point_circle; nine_point_circle = fullcircle scaled 2 abs(N - 1/2[A, B]) shifted N; circumcircle = fullcircle scaled 2 abs(M - A) shifted M; draw nine_point_circle withcolor 3/4 red; draw circumcircle withcolor 1/2[3/4 blue, white]; drawoptions(dashed evenly scaled 1/4 withcolor 1/2); draw 1/2[A,B] -- M -- 1/2[B, C]; draw 1/2[C,A] -- M -- D; draw A -- p; draw B -- q; draw C -- r; % show the nine points with small circle markers drawoptions(withpen pencircle scaled 1/4); draw fullcircle scaled 2 shifted 1/2[A, B]; draw fullcircle scaled 2 shifted 1/2[A, C]; draw fullcircle scaled 2 shifted 1/2[A, D]; draw fullcircle scaled 2 shifted 1/2[B, C]; draw fullcircle scaled 2 shifted 1/2[B, D]; draw fullcircle scaled 2 shifted 1/2[C, D]; draw fullcircle scaled 2 shifted p; draw fullcircle scaled 2 shifted q; draw fullcircle scaled 2 shifted r; drawoptions(); draw A--B--C--cycle; dotlabel.llft("$A$", A); dotlabel.rt("$B$", B); dotlabel.ulft("$C$", C); dotlabel.urt("\ $D$", D); dotlabel.llft("$M$", M); dotlabel.llft("$N$", N); \end{smallcode}\vss}} $$\includegraphics[width=\textwidth]{nine-point-circle}$$ \newpage \subsection{Lines tangent to a point on a path} \MP\ represents paths internally as a sequence of nodes. Each node consists of three pairs: the pre-control point, the point itself, and the post-control point. \mpic{0pt}{tangents-on-path}% For a given path $p$ you can extract these points at time $t$ with these operators: \begin{code} precontrol t of p point t of p postcontrol t of p \end{code} Unless you explicitly set them differently, \MP’s curve fitting will make these three points co-linear, so you can draw a tangent at point $t$ with \begin{code} draw precontrol t of p -- postcontrol t of p; \end{code} The length of the tangent line drawn like this depends on the size and shape of the curve, but it is somewhat arbitrary. So you may prefer to extract a \ representing the tangent at point $t$ with \begin{code} pair d; d = postcontrol t of p - precontrol t of p; \end{code} In fact, this is so useful that "plain.mp" provides \mpl{direction} as a shorthand: \begin{smallcode}[xleftmargin=0pt, xrightmargin=-20pt] vardef direction expr t of p = postcontrol t of p - precontrol t of p enddef; \end{smallcode} which can save you some typing. But the clever bit is that $t$ does not have to be a whole number. If you set $t=\frac14$ (say), \MP\ works out the corresponding fractional control points, so that you can use \mpl{direction t of p} to get a tangent at any point. The vector pairs returned have the right direction, but still have rather arbitrary magnitudes, so the usual idiom is something like this: \begin{smallcode} path s; s = origin -- 36 unitvector(direction t of p); drawarrow s shifted point t of p; \end{smallcode} or the snippet shown on the right $\longrightarrow$ \newpage \subsection{Lines tangent to a circle}\label{sec:tangent-times} The techniques of the preceding section can be used to add a tangent line to a given point on a circular path, but not to find the tangent lines from a given point outside a circle. To do this, you need to adapt the standard geometrical construction: for a given circle $C$ and a point $p$, find the midpoint of $p$ and the center of $C$; draw a semicircle through $p$, centred on this midpoint; the tangent point is where the semicircle intersects $C$. % \mpic{-110pt}{tangents-point-to-circle.pdf} Given a suitable \mpl{path C} and \mpl{pair p} you can do this: \begin{code} pair o, m, t, t'; o = center C; m = 1/2[o, p]; t = C intersectionpoint halfcircle zscaled (p-o) shifted m; t' = C intersectionpoint halfcircle zscaled (o-p) shifted m; \end{code} No parentheses are needed around the second path, because \mpl{intersectionpoint} is defined with \mpl{secondarydef}. \medskip\noindent Things are a little more complicated if you want the points as times along the path $C$ and you care about which tangent point is which. Here is a routine that returns the tangent points from $p$ as two times $a$ and $b$ on $C$, with $b$ adjusted so that $b > a$ in all cases regardless of the relative rotation of $C$ and $p$. This means that \mpl{subpath (a, b) of C} is always the “long way round” C, on the opposite side from $p$, and \mpl{subpath (a, b-8) of C} is always the shorter segment. \begin{code} vardef tangent_times(expr C, p) = % return the two times on C that correspond % to the external tangents from p to C save o, a, b, G, H; pair o; numeric a, b; path G, H; o = center C; H = halfcircle zscaled (p-o) shifted 1/2[o, p]; G = halfcircle zscaled (o-p) shifted 1/2[o, p]; (a, whatever) = C intersectiontimes H; (b, whatever) = C intersectiontimes G; (a, b if b < a: + 8 fi) enddef; \end{code} Note the elegant syntax here; if \mpl{z} is a \ then the operation \mpl{zscaled z} is equivalent to \mpl{scaled abs z rotated angle z}. \vpic{-200pt\noindent Here is the macro in action. Having obtained the two times $a$ and $b$ from the macro, the dashed line was drawn along a path that was composed with: \vrule depth 20pt width 0pt height 2pt \mpl{p -- subpath (a,b) of C -- cycle} }{tangent-times-on-circle} \newpage \subsection{Lines tangent to two circles (exterior)}\label{sec:adjust-times} The same \mpl{tangent_times} macro can be reused to find the tangents that touch two circles, using an approach like this: \mwpic{-12pt}{tangents-two-circles-exterior} \begin{code} path A, B; A = fullcircle scaled 144; B = fullcircle scaled 60 shifted (200, 140); numeric R, r; R = abs (point 0 of A - center A); r = abs (point 0 of B - center B); path C; numeric t, u; C = fullcircle scaled (2R-2r) shifted center A; (t, u) = tangent_times(C, center B); draw A withpen pencircle scaled 2 withcolor 3/4[blue, white]; draw B withpen pencircle scaled 2 withcolor 3/4[blue, white]; draw subpath (t, u) of A -- subpath (u-8, t) of B -- cycle; \end{code} Here $A$ and $B$ are the two circles you want to connect, and $A$ is larger than $B$. $R$ is the radius of the larger, $r$ of the smaller. $C$ is an auxiliary circle centred at the same point as $A$ and scaled so that its radius is $R-r$. If we then find the tangent points on $C$ from the center of $B$, the points we want are the corresponding points on $A$ and $B$. \medskip\noindent This works well, provided that none of three circles $A$, $B$, or $C$ has been rotated (that is that point 0 is at 3 o'clock in all of them). But this may not always be the case. For example, you might have written \begin{code} B = fullcircle scaled 60 shifted 240 right rotated 36; \end{code} and then point $t$ of $B$ would \textit{not} correspond to point $t$ of the auxiliary circle. So to make the code above more general you have to adjust the tangent times to take account of the relative rotation of the circles. \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vskip-24pt\noindent \begin{code} vardef adjust_time(expr tt, AA, BB) = tt + 1/45 angle (point 0 of AA - center AA) - 1/45 angle (point 0 of BB - center BB) enddef; \end{code} \vss}} The in the figure $t$ was adjusted to $t'$ for $A$ and $t''$ for $B$, using the routine shown on the right. This routine shows the relationship between \mpl{angle} and points around a circle: $360^\circ = 8\:\hbox{points}$. \newpage \subsection{Lines tangent to two circles (interior)} To find the interior tangents, you just need to add the smaller radius rather than subtract it, and add 4 to the times on the smaller circles, so that they are on the other side: $$\includegraphics[width=\textwidth]{tangents-two-circles-interior}$$ \bigskip\noindent The complete code for this is shown on the right. It uses the same routines given above; \mpl{tangent_times} from section \ref{sec:tangent-times}, and \mpl{adjust_time} from section \ref{sec:adjust-times}. \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent \begin{smallcode} path A, B; A = fullcircle scaled 144 rotated uniformdeviate 360; B = fullcircle scaled 60 shifted 240 right rotated 36; numeric R, r; R = abs (point 0 of A - center A); r = abs (point 0 of B - center B); path C; C = fullcircle scaled (2R+2r) shifted center A; % NB +ve numeric t, t', t'', u, u', u''; (t, u) = tangent_times(C, center B); t' = adjust_time(t, C, A); u' = adjust_time(u, C, A); t'' = adjust_time(t + 4, C, B); % Note the plus fours u'' = adjust_time(u + 4, C, B); draw A withpen pencircle scaled 2 withcolor 3/4[blue, white]; draw B withpen pencircle scaled 2 withcolor 3/4[blue, white]; draw C withpen pencircle scaled 1 withcolor 3/4[blue, white]; draw subpath (t', u') of A -- subpath (u'', t'') of B -- cycle; draw center B -- subpath (t, u) of C -- cycle dashed evenly; draw center B -- point t'' of B dashed withdots scaled 1/2; draw center B -- point u'' of B dashed withdots scaled 1/2; draw point t of C -- point t' of A dashed withdots scaled 1/2; draw point u of C -- point u' of A dashed withdots scaled 1/2; dotlabel.ulft(btex $t$ etex, point t of C); dotlabel.lrt (btex $t'$ etex, point t' of A); dotlabel.lrt (btex $t''$ etex, point t'' of B); dotlabel.lrt (btex $u$ etex, point u of C); dotlabel.ulft(btex $u'$ etex, point u' of A); dotlabel.ulft(btex $u''$ etex, point u'' of B); drawdot center B withpen pencircle scaled dotlabeldiam; drawoptions(withcolor 1/2[blue, white]); label.urt(btex $A$ etex, point 1/2(t'+u'- 7.6) of A); label.rt (btex $B$ etex, point 1/2(t''+u''- 2) of B); label.urt(btex $C$ etex, point 1/2(t+u-8) of C); drawoptions(); \end{smallcode}\vskip -1in }} \subsection{Axis of similitude}\label{sec:axosim} \bigskip \noindent\hbox to \textwidth{\includegraphics[scale=0.92]{axis-of-similitude}\hss} \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent Given three circles taken in pairs, you can use the techniques of the preceding sections to find the three points where the common external tangents intersect (shown here as $E_{12}$, $E_{31}$, and $E_{23}$) and the three points where the common internal tangents intersect ($I_{12}$, $I_{31}$, and $I_{23}$). These points have a pleasing collinearity. The line common to the three $E$ points is known as the \textit{Axis of Similitude}. The drawing is left as an exercise for the reader, except to note that if $r_1$ and $r_2$ are \mpl{numeric} variables representing the radius of the circles centred at the \mpl{pair} variables $C_1$ and $C_2$, then we have: $$\vbox{\openup3pt\halign{\hfil$#$&${}=#$\hfil\cr E_{12}&({r_1\over r_1 - r_2})[C_1, C_2];\cr I_{12}&({r_1\over r_1 + r_2})[C_1, C_2];\cr }}$$ which is a bit quicker than working out all the tangent points.}} \newpage \subsection{Inversion, pole, and polar}\label{sec:inversion} Inversion in a circle is a generalization of reflection in a line. \mpic{-68pt}{pole-and-polar} It is useful for certain constructions in geometry, and easy to implement as a macro \MP. For given circle, and a given point $P$ lying outside the circle, the inverted point $P'$ lies inside the circle at the intersection of the line from $P$ to the centre of the circle, and the line between the tangent points [§\ref{sec:tangent-times}] from $P$, shown here as $Q$ and $R$.\rlap{\quad$\longrightarrow$} But $OPQ$ and $OQP'$ are similar triangles, so $r/OP=OP'/r$ and so $OP' = r^2/OP$, and since $P'$ must lie on the line through $O$ and $P$, this is enough to define a macro directly to find $P'$ given $P$, $O$, and $r$: \begin{code} P' = O + unitvector(P-O) scaled r * r / abs (P-O); \end{code} But examining \mpl{plain.mp} shows that \mpl{unitvector} is a macro defined like this: \begin{code} vardef unitvector primary z = z/abs z enddef; \end{code} which suggests this alternative (safer) approach: \begin{code} vardef invert(expr P, O, r) = save s; numeric s; s = r / abs (P-O); O + (P-O) * s * s enddef; \end{code} This works well provided that $|P| > \frac1{180} r$, which is usually the case, but you could also consider checking that $|t|>0$ and that $s$ was not too large. If it was more convenient to deal with the \ of the circle of inversion instead of the centre and the radius, you get the macro to work out the centre and the radius for you. \begin{code} vardef invert(expr P, C) = save o; pair o; o = 1/2[point 0 of C, point 4 of C]; save r; numeric r; r = abs (point 0 of C - o); save s; numeric s; s = r / abs (P - o); o + (P - o) * s * s enddef; \end{code} \vfill \moveright5.5in\vbox to 0pt{\vss\hsize 4in\noindent \noindent\llap{\nb}Inversion is reciprocal, so $P$ is the inverse of $P'$ above. Points on the circle of inversion invert to themselves. \smallskip \noindent\llap{\nb}For any given line, the \blue{\textit{pole}} of the line with respect to a circle, is the inverse of the point on the line closest to the centre of the circle. \smallskip \noindent\llap{\nb}For any given point, the \blue{\textit{polar}} of the point with respect to a circle, is the line through the inverse of the point perpendicular to the line through the point and the center of the circle of inversion. \smallskip \noindent\llap{\nb}The small dotted circle through $O$ and $P'$ above is the inversion of the whole polar line (infinitely extended).} \newpage \subsection{Radical axis and radical centre}\label{sec:radical} The \textit{radical axis} of two circles is the line, orthogonal to the line between the centres of the two circles which is the locus of points which have equal power with respect to both circles; that is the points from which the tangents to each circle are of equal length. A circle centred at any point on the axis, and drawn with radius equal to the length of the tangent will cut both circles at right angles. \medskip\noindent\centerline{\includegraphics{radical-axis}} \medskip\noindent In a system of three circles as shown, the \textit{radical centre} is the intersection of the three mutual radical axes. The tangents from this point to all three circles have the same length, so a circle with this radius cuts all three circles at right angles. \moveright5.5in\vbox to 0pt{\vss\hsize 4in\begin{smallcode} vardef radical_axis(expr ca, cb) = numeric t, d, ra, rb; ra = abs(center ca - point 0 of ca); rb = abs(center cb - point 0 of cb); d = abs(center cb - center ca); 2t = 1 + (ra+rb) / d * (ra-rb) / d; (up -- down) scaled 89 rotated angle (center cb - center ca) shifted t[center ca, center cb] enddef; beginfig(1); path c[], a[]; z1 = origin; z2 = 233 right rotated 4; z3 = 209 right rotated -42; c1 = fullcircle scaled 202 shifted z1; c2 = fullcircle scaled 106 shifted z2; c3 = fullcircle scaled 62 shifted z3; a1 = radical_axis(c1, c2); a2 = radical_axis(c2, c3); a3 = radical_axis(c3, c1); z0 = whatever [point 0 of a1, point 1 of a1] = whatever [point 0 of a2, point 1 of a2]; numeric t; (t, whatever) = tangent_times(c1, z0); drawoptions(withpen pencircle scaled 1 withcolor 3/4[blue, white]); draw c1; draw c2; draw c3; drawoptions(withcolor 3/4[blue, white]); draw z1 -- point t of c1 dashed evenly; drawoptions(withpen pencircle scaled 1/4); draw z1 -- z2 -- z3 -- cycle; drawoptions(); draw a1; draw a2; draw a3; drawoptions(withcolor 2/3 red); draw fullcircle scaled 2 abs (point t of c1 - z0) shifted z0; draw z0 -- point t of c1 dashed evenly; drawdot z0 withpen pencircle scaled dotlabeldiam; drawoptions(withcolor 1/4[blue, white]); drawdot z1 withpen pencircle scaled dotlabeldiam; drawdot z2 withpen pencircle scaled dotlabeldiam; drawdot z3 withpen pencircle scaled dotlabeldiam; label.urt(btex $C_1$ etex, point 1 of c1); label.urt(btex $C_2$ etex, point 1 of c2); label.rt (btex $C_3$ etex, point 0 of c3); endfig; \end{smallcode}\vskip -1in} \newpage \subsection{Circles tangent to other circles} \bigskip \noindent\hbox to \textwidth{\includegraphics[height=\textheight]{apollonius}\hss} \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent The classical Problem of Apollonius is to find a circle tangent to three others. All of the approaches are rather involved, but Gergonne's is probably the simplest to follow in \MP. \smallskip\noindent For three given circles \blue{$C_1$, $C_2$, and $C_3$}, you first find the external \blue{axis of similitude} [§\ref{sec:axosim}]; then find the \textcolor{carrot}{poles} [§\ref{sec:inversion}] of this line with respect to each of the three circles; and thirdly find the \textcolor{squash}{radical centre} [§\ref{sec:radical}]. \smallskip\noindent The lines from the radical centre through each of the three poles cut each circle in two places. These six points show the tangent points for the two \red{tangent circles}, and you can draw the circles using the three point circle technique [§\ref{sec:circles}]. \smallskip\noindent {\small The drawing is also left as an exercise for the reader, although you can find my version in the source code for this document. You might like to try to make a more robust version or to find all the other tangent circles.} }} \newpage \subsection{Coordinate geometry examples} \kern-\baselineskip \vpic{-24pt}{desargues} \kern-.5\baselineskip \begin{code}[xleftmargin=0pt, xrightmargin=-72pt] beginfig(1); z.P = 200 up rotated 21; z.A = 100 left rotated -21; z.B = origin; z.C = 90 right rotated 42; z.A' = 3/8[z.P, z.A]; z.B' = 1/2[z.P, z.B]; z.C' = 5/8[z.P, z.C]; z.R = whatever [z.A, z.B] = whatever [z.A', z.B']; z.S = whatever [z.B, z.C] = whatever [z.B', z.C']; z.T = whatever [z.C, z.A] = whatever [z.C', z.A']; path t[]; t1 = z.A--z.B--z.C--cycle; t2 = z.A'--z.B'--z.C'--cycle; fill t1 withcolor 7/8[red, white]; fill t2 withcolor 7/8[blue, white]; draw t1 withcolor 1/2 white; draw t2 withcolor 1/2 white; drawoptions(dashed withdots scaled 1/2); draw z.P--z.A; draw z.P--z.B; draw z.P--z.C; drawoptions(dashed evenly scaled 1/2); draw z.B--z.R--z.B'; draw z.C--z.S--z.C'; undraw subpath (1/4, 3/4) of (z.C'--z.T) withpen pencircle scaled 5; draw z.C--z.T--z.C'; \end{code} \moveright 384pt \vbox to 0pt{\vss \begin{code}[xleftmargin=0pt, xrightmargin=-72pt] drawoptions(withcolor 2/3 red); draw 9/8[z.S,z.R] -- 9/8[z.R,z.S]; picture pp; pp = thelabel("perspectrix", origin); draw pp shifted 7 down rotated angle (z.S-z.R) shifted 1/2[z.R, z.T]; dotlabel.urt("perspector", z.P); drawoptions(); dotlabel.lft (btex $A$ etex, z.A); dotlabel.llft(btex $B$ etex, z.B); dotlabel.lrt (btex $C$ etex, z.C); dotlabel.lft (btex $A'$ etex, z.A'); dotlabel.llft(btex $B'$ etex, z.B'); dotlabel.bot (btex $C'$ etex, z.C'); label.rt(btex Desargues' Theorem etex, (x.C', 1/2(y.P+y.C'))); endfig; \end{code} \vskip -42pt} \newpage \moveright5.5in\vbox to 0pt{\vskip10pt\includegraphics[width=4.2in]{trisection-triangles}\vss} \vskip-\baselineskip \begin{code}[xleftmargin=0pt, xrightmargin=-80pt] randomseed := 2485.81543; vardef measured_angle(expr p, o, q) = (angle (p-o) - angle (q-o)) mod 360 enddef; beginfig(1); picture T; for i=0 upto 1: for j=0 upto 1: clearxy; T := image( z1 = (120 + uniformdeviate 21, 0); z2 = (120 + uniformdeviate 21, 0) rotated 120 rotated 21 normaldeviate; z3 = (120 + uniformdeviate 21, 0) rotated 240 rotated 21 normaldeviate; numeric a, b, c; a = measured_angle(z3, z1, z2); b = measured_angle(z1, z2, z3); c = measured_angle(z2, z3, z1); z4 = whatever [z1, z2 rotatedabout(z1, 1/3 a)] = whatever [z2, z3 rotatedabout(z2, 2/3 b)]; z5 = whatever [z2, z3 rotatedabout(z2, 1/3 b)] = whatever [z3, z1 rotatedabout(z3, 2/3 c)]; z6 = whatever [z3, z1 rotatedabout(z3, 1/3 c)] = whatever [z1, z2 rotatedabout(z1, 2/3 a)]; fill z4--z5--z6--cycle withcolor 3/4[red + 1/2 green, white]; draw z4--z5--z6--cycle; draw z1 -- z4 -- z2 -- z5 -- z3 -- z6 -- cycle dashed withdots scaled 1/4; draw z1 -- z2 -- z3 -- cycle; ); draw T shifted (200i, 240j); endfor endfor label.rt(btex \vbox{\halign{#\hfil\cr The trisectors of each angle\cr in any given triangle form a\cr central equilateral triangle.\cr}} etex, (24, 128)); endfig; \end{code} \newpage \kern-\baselineskip \vpic{1in}{projections} \mpexternal[xleftmargin=0pt]{projections-code.mp} \newpage \moveright5.5in\vbox to 0pt{\hsize4in\noindent This needs an \mpl{invert} macro, such as the one from [§\ref{sec:inversion}]. \smallskip\noindent \includegraphics[width=288pt]{arbelos} \vskip 1.414in\noindent \begingroup \raggedleft\fontsize{8}{10}\selectfont\textsf{% One must also recognize that any attempt to illustrate geometry\\ involves a basic fallacy. For example, a straight line is unbounded\\ and infinitely thin and smooth, while any illustration is unavoidably\\ of finite length, of positive thickness, and rough edged.\\[2pt] — Benoit Mandelbrot, \textsl{The Fractal Geometry of Nature}} \par\endgroup \vss} \begin{smallcode}[xleftmargin=0pt, xrightmargin=-72pt] beginfig(1); pair A,B,C; A = origin; C = 244 right; B = 7/8[A, C]; path c[]; c1 = fullcircle scaled 2 abs(A-C); % large circle for the inversions c2 = fullcircle scaled abs(A-C) shifted 1/2[A,C]; c3 = fullcircle scaled abs(A-B) shifted 1/2[A,B]; c4 = fullcircle scaled abs(B-C) shifted 1/2[B,C]; c5 = invert(c4,c1); numeric d; d = abs(point 0 of c5 - point 4 of c5); % diameter of c5 drawoptions(withcolor 3/4 white); draw c4; draw c5; draw invert(subpath(0, 3/2) of c2, c1); draw invert(subpath(0, 3/2) of c3, c1); drawoptions(); draw subpath(-1/4,1) of c1 withcolor 3/4[1/2 red,white]; label.bot("\textit{circle of inversion}", point -1/4 of c1) withcolor 1/4[1/2 red, white]; for i=1 upto 72: path c, c'; c = c5 shifted (0, i*d); c' = invert(c, c1); if i < 5: drawoptions(withcolor 3/4 white); draw c; draw origin -- center c; fill fullcircle scaled dotlabeldiam shifted center c; fill fullcircle scaled dotlabeldiam shifted center c'; drawoptions(); fi draw c' withpen pencircle scaled 1/4 withcolor 2/3 blue; endfor forsuffixes $=2,3,4: draw subpath (0,4) of c$ withpen pencircle scaled 1/4 withcolor 2/3 blue; endfor draw A--C; dotlabel.lft("$A$", A); dotlabel.llft("$B$", B); dotlabel.rt("$C$", C); endfig; \end{smallcode} \newpage \section{Trigonometry functions}\label{trig} \MP\ provides only two basic trigonometry functions, "sind" and "cosd". This lack appears to be a deliberate design; in general it's much easier to use the "rotated" and "angle" functions than to work out all the sine, cosines and arc-tangents involved in rotating parts of your picture. But if you really want the `missing' functions they are not hard to implement. First you might want versions that accept arguments in radians instead of degrees. For this you need to know the value of $\pi$, but this is not built into plain \MP. If you are using the default number system then it's enough to define it to five decimal digits,% \vadjust{\moveright 384pt\vbox to 0pt{\kern-144pt \begin{code} numeric pi; % approximate value pi := 3.14159; % measure round a circular arc... pi := 1/4 arclength (quartercircle scaled 16); % up to 32 digits of precision pi := 3.1415926535897932384626433832795; % as many digits as are needed... vardef getpi = numeric lasts, t, s, n, na, d, da; lasts=0; s=t=3; n=1; na=0; d=0; da=24; forever: exitif lasts=s; lasts := s; n := n+na; na := na+8; d := d+da; da := da+32; t := t*n/d; s := s+t; endfor s enddef; pi := getpi; % conversions vardef degrees(expr theta) = 180 / pi * theta enddef; vardef radians(expr theta) = pi / 180 * theta enddef; % trig functions that expect radians vardef sin(expr theta) = sind(degrees(theta)) enddef; vardef cos(expr theta) = cosd(degrees(theta)) enddef; % inverse trig functions vardef acosd(expr a) = angle (a,1+-+a) enddef; vardef asind(expr a) = angle (1+-+a,a) enddef; vardef acos(expr a) = radians(acosd(a)) enddef; vardef asin(expr a) = radians(asind(a)) enddef; % tangents vardef tand(expr theta) = save x,y; (x,y)=dir theta; y/x enddef; vardef atand(expr a) = angle (1,a) enddef; \end{code} \vss}} but if you are using one of the new number systems you might want more digits of precision. In fact there's no harm in always defining these extra digits; even when you are using the default "scaled" number system, \MP\ will happily read as many extra digits of $\pi$ as you supply, before it rounds the value to the nearest multiple of $1\over65536$ (which turns out to be $3.14159$). The same applies to the "double" number system, but the "binary" and "decimal" number systems will give you an error if you supply more digits that the default precision. So in general it's best to use no more than 32 digits. It's also possible, but not really worth the trouble, to define a routine to calculate $\pi$ to the current precision.\rlap{\raise1ex\hbox{\ $\smash{\nearrow}$}} However you define it, once you are armed with a value for $\pi$ you can then define functions to convert between degrees and radians, and some more `normal' versions of sine and cosine. There's no built-in $\arccos$ or $\arcsin$ function but each is very easy to implement using a combination of the "angle" function and the Pythagorean difference operator. \MP\ does have built-in functions for tangents; but they are called "angle" and "dir" and they are designed for pairs. So $\kw{angle}\,(x,y)=\arctan(y/x)$ while $\kw{dir}\,30$ gives you the point $(x,y)$ on the unit circle such that $\tan 30^{\circ} = y/x$. You can use these ideas to define tangent and arctan functions if you really need them, but often "angle" and "dir" are more directly useful for drawing. You should also be aware that the tangent function shown here does not check whether $x=0$; if this is an issue, then add something like this at the appropriate point: $$\kw{if}\,x=0\!:\id{infinity}\: \kw{else}\!: y/x \kw{fi}$$ \newpage \section{Traditional labels and annotations}\label{sec:trad-labels} \moveright384pt\vbox to 0pt{\hsize 4.2in\vss\textcolor{blue}{\itshape This section describes labels and annotations in what can be called the traditional \MP\ environment, where your figures are compiled with "mpost". The section after this describes labels \& annotations in the newfangled (but better) world of "lualatex" and the "luamplib" package.}\par\kern 16pt} \noindent \MP\ does not draw text directly; but it provides two different mechanisms to turn some text into a \, which can then be treated like any other; saved as a variable, drawn directly, or transformed in some way with a scaling, a reflection, or a rotation. The first mechanism is described below, the other in §\ref{btex}. \subsection{Simple strings in PostScript fonts with \texttt{infont}}\label{infont} The first mechanism is the primitive binary operation "infont". As explained in section~8.3 of the \MP\ manual, it takes two strings as arguments: the left hand argument is the string of text to be printed; the right hand argument is the name of the font to use; and the result is a "picture" primary.\vadjust{ \moveright384pt\vbox to 0pt{\kern -126.5 bp \hsize 4.2in\noindent To find the name of a suitable font, you have to consult your local "psfonts.map" file, and probably the PSNFSS documentation. Here are a few of the many fonts available on my local \TeX\ installation; the name to use with "infont" is in the first column. $$\includegraphics{trad-font-samples}$$ The text example in the first line of this table was produced with \begin{smallcode} draw "Hand in glove 42" infont "pagk8r" shifted (124,144); \end{smallcode} Note that in PostScript terms each of these font names refers to a combination of three files: an encoding that maps the characters you type to the glyphs in the font; a font metrics file that defines the sizes of the virtual boxes surrounding these glyphs; and a set of PostScript routines that actually draw them. In a \TeX\ installation these combinations are defined in a font map file, usually called "psfonts.map". If you run "mpost" with the "-recorder" switch it will write an extra log file (with a ".fls" extension) that lists the names of all the files used in a job. The actual font map file in use will be one of these. You can then browse it to find a definitive list of the font names you can use with your local \MP. \vss}} To make a suitable string you can enclose your text in double quotes to make a string token, or to refer to a \ variable, or do one of these: \begin{itemize} \item Concatenate two other strings with \mpl{&}. \item Use \mpl{substring (a,b) of s} to get a substring of string \mpl{s}. \item Use \mpl{min(a,b,...)} or \mpl{max(a,b,..)} to find the lexicographically smallest (or largest) string in the list \mpl{a,b,...}. The list must have at least two entries, and they must all be strings. \item Use \mpl{char} to convert a numeric expression to the corresponding ASCII code; the numeric expression is rounded to the nearest integer modulo 256. \item Use \mpl{decimal} to get a string representing the value of a numeric expression. \item Apply \mpl{str} to any suffix (and hence to any variable). You get back a string representation of the suffix or variable name. \item Use \mpl{readfrom} to read one line from a file as a string. \item Use \mpl{fontpart} to extract the name of the font used in a picture created with \mpl{infont} --- the string will be empty if there's no text element in the picture. \item Use \mpl{textpart} to get the text used in a picture created by \mpl{infont} --- the string will be empty if there's no text element in the picture. \end{itemize} \newpage \subsubsection{Character sets used by \texttt{infont} to set text}\label{sec:charsets} Standard \MP\ is configured to accept as input only space and the usual 94 visible ASCII characters (that is the characters numbered 32 to 126 in the tables at the right), but you can use any 8-bit characters as the payload of a string. However, plain \MP\ is set by default to use "cmr10", the familiar Computer Modern typeface developed by Knuth for \TeX, and unfortunately, this is encoded using the \TeX\ text font encoding (also known as `OT1', and as shown in the first table in Appendix~F of the {\sl \TeX book}). \mpic{-108pt}{trad-font-tables} From the point of view of using "infont" to make simple labels, this means that the characters for space and seven other characters ("< > \ _ { | }") are in the wrong place. You are likely to notice this first if you try to set a label with two words; the space will come out as a small diagonal stroke accent that is used in plain \TeX\ to make the characters Ł and ł, used in Polish and other Slavic languages. To fix this you should change the default font at the start of your program: \begin{code} defaultfont := "texnansi-lmr10"; % for Computer Modern Roman \end{code} If you want "cmss10", use "texnansi-lmss10" and so on. The encoding is shown on the right. The characters printed in black correspond to the widely used ISO Latin~1 encoding. If you want to use one of the standard PostScript fonts listed on the previous page, then the encoding to use is either "8y" to get the same "texnansi" arrangement or "8r" to get the arrangement shown in the lower table. Choosing a font with one of these encodings means that if you use Windows code page 1252 or ISO Latin 1 as the encoding for your text editor, you can create labels with accented characters using "infont" and without resorting to "btex" \dots\ "etex". But if you are using UTF-8 characters (as many of us are now), then you have to do some extra work to get them printed correctly with "infont". A solution is shown on the next page. In the normal course of labelling a drawing, it is always possible to use "btex" \dots\ "etex" to produce your accented characters as discussed in section \ref{btex} below; but it may be that you are using \MP\ to represent data and labels supplied from some other program or a website. In this case it can be useful to be able to work with at least a subset of UTF-8 input. \newpage \subsubsection{Mapping a subset of UTF-8 for \texttt{infont}} UTF-8 is a way of representing 16-bit Unicode characters with sequences of 8-bit characters. So your UTF-8 aware editor may show you an é but \MP, knowing nothing about UTF-8, will see this as é. But you can write a fairly simple routine to decode a commonly-used subset of UTF-8.\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip -9.5pt\parindent 0pt \def\item{\leavevmode\llap{•~}} \item You can extend this idea to cope with other UTF-8 characters, including those that use three bytes. The UTF-8 page on Wikipedia shows you how it works. Essentially you look at the values of the next 2 or 3 characters and then pick the appropriate character in your encoding with "char". But your output is still, of course, limited to the 256 characters in your encoded font. \item If you get tired of writing "decode", you could define a short cut with a shorter name. You could even write it as a primary without parentheses like this: \begin{code} def U primary s = if string s: decode(s) fi enddef; \end{code} which would let you write: \begin{code} label.rt(U"café à la möde", (x,y)); \end{code} \item However, there's no point in making any of this too elaborate. If you really want proper Unicode support you should use \MP\ with Lua\TeX. (See below in §\ref{sec:neo-labels}). \vss}} \begin{code}[xrightmargin=-10pt] vardef decode(expr given) = save a,i,s,out; string s, out; numeric a, i; out = ""; i=0; forever: i := i+1; s := substring (i-1,i) of given; a := ASCII s; if a < 128: elseif a = 194: i := i+1; s := substring (i-1,i) of given; elseif a = 195: i := i+1; s := char (64 + ASCII substring (i-1,i) of given); else: s := "?"; fi out := out & s; exitif i >= length given; endfor out enddef; \end{code} Use it with "infont" like this: \verb|decode("café") infont "ptmr8r"| to produce a normal "picture" that can be passed to \mpl{draw} or saved as usual.\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip -9.5pt \noindent The fragment on the left produces: $$\includegraphics{utf8}$$ The \texttt{label} macro automatically calls \texttt{infont} with the current value of \texttt{defaultfont}; notice how it also adds some extra space. \vss}} \begin{code} draw "café noir £2.50" infont "pncr8r"; draw decode("café noir £2.50") infont "pncr8r" shifted 12 down; defaultfont := "pncr8r"; label.rt("café noir £2.50", 24 down); label.rt(decode("café noir £2.50"), 36 down); \end{code} Note that you can't just use \mpl{draw} with a string variable; you have to use "infont" to turn the string into a picture. On the other hand, "label" calls "infont" automatically, but you must explicitly set the default font, preferably to one with an encoding that is compatible with ISO Latin~1. \newpage \subsubsection{Typographical minus signs with \texttt{infont}} If you are producing labels for a numeric reference scale, like the axis of a chart, it is convenient to be able to write a loop like this: \begin{code} for x=1 upto 3: label.bot(decimal x, (x*cm, 0)); endfor \end{code} to produce your labels, however if $x$ is negative this does not come out so well, because the first character of the string produced by \mpl{decimal -1} is an \mpl{ASCII 45}, which is the hyphen character. What we need is the mathematical minus sign instead; this is what you get with \mpl{btex $-1$ etex} of course, but that's harder to put in a loop with traditional \MP. Instead you can do this:\vadjust{\moveright5.5in\vbox to 0pt{\vss\hsize4in $$\includegraphics{minus}$$ \vss}} \begin{code} string minus_sign; minus_sign := char 143; % if you are using the texnansi encoding minus_sign := char 12; % if you are using the 8r encoding for x = -3 upto 3: label.bot(if x<0: minus_sign & fi decimal abs(x), (x*cm, 0)); endfor \end{code} Note that this does not work with the default encoding used in "cmr10" because there is no minus sign available in that font. Plain TeX uses "char 0" from "cmsy10". \subsubsection{Bounding boxes and clipping with \texttt{infont}} Once the encoding is fixed, the other two parts of a PostScript font are the font metrics and the programs that draw the actual glyphs. The font metrics define the width of each character and provide a kerning table to adjust the space between particular pairs.\vadjust{\moveright5.5in\vbox to 0pt{\vss\hsize4in $$\includegraphics{infont-example}$$ }} This means that certain characters will overlap each other or stick out beyond the bounding box of the picture produced by "infont". This is not normally a problem unless the picture happens to be at the edge of your figure. In the first example observe how the last letter sticks out to the right; in the second a wider baseline has been added to prevent this. If you want this effect, but you don't want to see the baseline, then draw it using the colour \mpl{background}. \subsubsection{But what about the \texttt{label} command?} As a convenience, the plain \MP\ format provides a "label" macro that automatically turns strings into pictures for you using whatever font name is the current value of "defaultfont" and scaled to the current value of "defaultscale".\vadjust{\moveright5.5in\vbox to 0pt{\vss\hsize4in \noindent The "label" macro is defined (essentially) to do this: \begin{code} def *label(expr s, z) = draw s if string s: infont defaultfont scaled defaultscale fi shifted z enddef; \end{code} plus some clever code to align the label for you. }} \newpage \subsubsection{Bounding boxes and alignment with \texttt{infont}}\label{textsize} \label{infontbbox} To allow you to align a text label on a specific point, \MP\ provides five unary operators to measure the bounding box of a picture; they are shown in \textcolor{red!67!black}{red} in the diagram, and you can use them to measure the width, depth, and height of a textual picture. You can also work out the location of the baseline of the text or the x-height, provided you know how much your picture has been shifted. The easiest way to do this is to measure the picture \textit{before} you shift it.\vadjust{\moveright5.5in\vbox to 0pt{\vss\hsize4in $$\includegraphics[width=4in]{infont-annotated}$$ \vss}} \begin{code} picture pp; pp = "proof" infont "pplri8r"; \end{code} Here the picture \id{pp} is created with the origin of the text sitting at coordinates $(0,0)$; then you can get the dimensions like this \begin{code} wd = xpart urcorner pp; ht = ypart urcorner pp; dp = ypart lrcorner pp; \end{code} In this particular case you will find that you have $wd=20.47292$, $ht=7.19798$, and $dp=-2.60017$. The depth is negative because the descenders on the \textdemo{\textit{p}} and the \textdemo{\textit{f}} in the chosen font stick down below the base line. The height is greater than the x-height, because the \textdemo{\textit{f}} also sticks up, so you need to make another measurement: \begin{code} numeric xheight; xheight = ypart urcorner ("x" infont "pplri8r"); \end{code} Armed with these measurements you can align your text labels neatly so that they are all positioned on the base line or vertically centred on the lower case letters regardless of any ascenders or descenders. To draw your label left-aligned with its origin at position $(x,y)$ you just need to use: \kw{draw} \id{pp} \kw{shifted} $(x,y)$. To draw it right-aligned, you subtract \id{wd} from the $x$-coordinate: \kw{draw} \id{pp} \kw{shifted} $(x-wd,y)$. Or to centre it, subtract $1/2wd$. To center it vertically on the lowercase letters, subtract $1/2\id{xheight}$ from the $y$-coordinate. You might of course like to wrap these adjustments up in your own convenient macro to help you maintain consistency in a diagram with many labels. Alternatively you can adjust the bounding box of your textual picture and then use it with "label" as normal. Assuming \id{wd} is set to the width of your picture and \id{xheight} is set correctly for the current font, then \begin{code} setbounds pp to unitsquare xscaled wd yscaled xheight; \end{code} will make the "label" alignment routines ignore any ascenders or descenders. \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in \vss \small \noindent\llap{\nb}Beware that if the resulting label is right at the edge of your drawing then any parts of the text that stick out of the adjusted bounding box will be clipped. See also §\ref{sec:rotated-boxes} for more on what happens if you rotate the text.}} \newpage \subsubsection{Setting Greek letters with \texttt{infont}} \leavevmode\hbox{} $$\includegraphics[width=0.5\textwidth]{greek-homer}$$ While it's technically possible to set the whole of Homer's \textsl{Iliad} using the Greek fonts available to \mpl{infont}, it's probably not a great use of time; on the other hand you might want to label parts of a diagram with Greek letters, and for single Greek letters \mpl{infont} is more than adequate. The Greek letters for Computer Modern are in the maths-italic font "cmmi10", which uses the encoding shown on p.\thinspace 430 of \textsl{The \TeX{}book}. For historical reasons there's no omicron available, so you are supposed to use the $o$~character instead. Fortunately you are unlikely to need more than the first few, and it's quite easy to remember that $"char 11"=\alpha$, $"char 12"=\beta$, and so on. Producing the upper case letters is a bit more of a fiddle with this encoding as you need to know which ones use a Roman letter form; for details examine the program on the right, or check the table in §\ref{euler} that shows Herman Zapf's elegant Euler font, available as "eurm10". This makes a refreshing change for some diagrams.\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\kern-164pt \begin{code} beginfig(1); string ab, AB; ab = ("" for i=11 upto 23: & char i endfor & "o" for i=24 upto 33: & char i endfor); AB = ("AB" & char 0 & char 1 & "EZH" & char 2 & "IK" & char 3 & "MNO" & char 4 & char 5 & "P" & char 6 & "T" & char 7 & char 8 & "X" & char 9 & char 10); draw ab infont "cmmi10"; draw AB infont "cmmi10" shifted 12 down; draw ab infont "eurm10" shifted 32 down; draw AB infont "eurm10" shifted 44 down; endfig; \end{code} \centerline{\includegraphics{greek-default-encoding}} \begin{code} string ab, AB; ab = "abgdezhjiklmnoxprstufqyw"; AB = "ABGDEZHJIKLMNOXPRSTUFQYW"; \end{code} \centerline{\includegraphics{greek-gfs-encoding}} \vss}} \medskip\noindent If you have fonts installed from the Greek Font Society, then you get a wider choice, and a slightly more modern encoding. All of the plain letters are available in the normal ASCII positions, so you do not have to muck about with "char xx" so much. However in recent versions there is no character you can use as a word space, so if you want to set Greek text rather than individual letters, see §\ref{sec:neo-otf}. \vbox to 0pt{\centerline{\includegraphics{porson}}\vss} \newpage \subsection{Setting text with \texttt{btex ... etex}}\label{btex} As soon as you need anything complicated in a label, like multiple fonts, multiple lines, or mathematics, you will find it easier to switch from "infont" to the "btex ... etex" mechanism that calls \TeX\ to create your textual picture. In fact you might prefer to use \TeX\ for all your labels, even simple strings, for the sake of consistency. The only downside is that this mechanism is a little bit slower. The "btex" mechanism produces a textual picture just as "infont" does with a height, width, and depth that you can measure, and adjust, as discussed in section~\ref{infontbbox}. And again, just like "infont" you can either use \mpl{draw} to place the resulting picture directly, or pass it to the "label" macro. What you need to be aware of is that \MP\ places everything you put between the "btex" and "etex" into an "\hbox{...}" and processes it with plain \TeX. This has several implications: on the positive side you have easy access to italics and bold letters, mathematical formulae, symbols like "$\alpha$", and anything else you can normally put in an "\hbox{}"; but there are some restrictions especially if you want to do anything more than produce a simple single-line label in the default Computer Modern type face. The next few sections deal with some of the things you might want to do. \subsubsection{Producing display maths} One of the obvious restrictions that \TeX\ imposes in restricted horizontal mode is that you can't use "$$ ... $$" to produce display maths. This means that the various mode-sensitive constructs like $\sum$ and $\int$ will come out in their smaller forms. And your fractions will look like they are $3\over4$ size. If you want them big, then the solution is simple: just add "\displaystyle" at the beginning of your formula $\longrightarrow$\vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent \begin{code} ... label(btex $\displaystyle \int_0^t 3x^2\, dx$ etex, (x,y)); ... \end{code} }} \subsubsection{Getting consistent baselines for your labels} As already discussed §\ref{infontbbox}, you can fiddle with the bounding box of a text picture to make the \mpl{label} macro line things up on a common baseline, but there is a much easier way with "btex" and "etex". Plain \TeX\ provides a "\strut" command that inserts an invisible rule that sticks up 8.5pt above the baseline and 3.5pt below. If you put one of these in each of the your labels, then they will all have the same vertical size and will all line up neatly:\quad\mpl{label(btex \\strut a etex, origin);} \subsubsection{Multi-line text labels} Another consequence of the "hbox" feature is that there is no automatic text wrapping done for you, but again you can work round this easily because \TeX\ lets you nest a "\vbox" inside an "\hbox". This gives you proper paragraph-like wrapping but you will almost certainly need to adjust the line length, justification, and indentation in order to get a satisfactory result \rightarrow \vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vskip -42pt\noindent \begin{code} ... label(btex \vbox{\hsize 2in\parindent 0pt\raggedright An extended caption or label that will be set as a small paragraph with automatic hyphenation and line-wrapping. } etex, z0); ... \end{code}\vss }} \medskip\noindent You may only need the full power of \TeX's paragraph making system occasionally though: more usually you will just have one or two lines in each label, and you might be quite happy to control the line breaks manually. In this case it's helpful to wrap a little tabular structure around your text. Here's how to define something suitable in plain \TeX. First you need to define a suitable macro at the start of your figure \begin{code} verbatimtex \def\s#1{\let\\\cr\vbox{\halign{\hfil\strut ##\hfil\cr#1\crcr}}} etex \end{code} then you can write labels like this: \begin{code} ... label(btex \s{Single line} etex, z1); label(btex \s{Longer text split\\onto a new line} etex, z2); ... \end{code} Notice how you can still use the macro with single lines, you just get a one-line table as it were. Note also that the definition of "\s" as given will centre each line of the text under the one above. If you want them left aligned or right aligned, omit one of the "\hfil" commands. \mpic{-160pt}{split-labels} The three examples from this page are typeset over here \rightarrow\break The small red circle show the reference points and the pale blue lines the bounding boxes of the pictures that \MP\ gets back from \TeX. You can of course achieve the same effects using \LaTeX\ tabular structures, but then you have to use the "-tex=latex" option to run \MP. \smallskip\noindent \textbf{Note}: In case it's not obvious, if you want text wrapping or tabular arrangements as discussed here, you need to use \texttt{btex ... etex} to set your labels. There's no text wrapping with "infont". On the other hand if all of your labels are in "infont" but you just want one extra that has two lines, you can split the text into two separate labels and position them independently. \newpage \subsubsection{Dynamic labels}\label{sec:old-and-dynamic} If you are a maven of programming language syntax you may have noticed that "btex ... etex" fits into the type system that \MP\ inherits from \MF\ as a "picture" and not as a "string". Effectively, "btex" and "etex" act as a special pair of quotation marks that create a picture; however the contents are used verbatim, so that the whole construction is a syntactical atom. This means that you \textbf{cannot} write this sort of thing: \begin{code} for i=0 upto 4: % this won't work label(btex "$p_" & decimal i & "$" etex, (10i,0)); endfor \end{code} Given this input \MP\ would attempt to get \TeX\ to typeset \begin{code} \hbox{"$p_" & decimal i & "$"} \end{code} which would probably result in a `Misplaced alignment tab character' error. To get round this problem, \MP\ provides a general mechanism to write out a string to a file, and then read the file back in. This is the mechanism used by the "TEX()" macro that is provided alongside "plain.mp". This allows you to write: \begin{code} input TEX ... for i=0 upto 4: label(TEX("$p_" & decimal i & "$"), (10i,0)); endfor \end{code} This works because the TEX macro is expecting a "string" so the normal string concatenation rules are applied. The macro wraps the result with "btex" and "etex", writes them out to a file, and then reads the file in again so that \MP\ gets the correct contents to pass to \TeX. The only trouble with this is that it makes \MP\ open a file, write to it, close it, and then read it in again for each label one at a time; this means that it's very slow. The example on the right shows how to speed things up, by using the same file for all the labels and only writing it once. The "write" command is a \MP\ primitive, and "EOF" is defined in "plain.mp".% \vadjust{\moveright5.5in\vbox to 0pt{\vss\hsize4in\noindent \begin{code} path c; c = fullcircle scaled 100; draw c withcolor .67 red; for i=0 upto 7: fill fullcircle scaled 3 shifted point i of c; z[i] = point i of c scaled 1.15; write "label(btex $p_" & decimal i & "$ etex,(" & decimal x[i] & "," & decimal y[i] & "));" to ".mplabels"; endfor write EOF to ".mplabels"; input ".mplabels"; \end{code} $$ \includegraphics{dynamic-labels} $$ Note that you can't use "decimal" on a "pair" variable, but you can save the pair as a "z"-variable and then use the "x" and "y" syntax. The scaling trick used here only works because "c" is centred on the origin. If "c" were drawn elsewhere, you would have to write: \begin{code} ... point i of c shifted -center c scaled 1.15 shifted center c ... \end{code} }} \newpage \subsection{Matching fonts}\label{sec:fonts} Despite the apparent restriction of using plain \TeX\ it is almost always possible to match the font and format of an enclosing \LaTeX\ document. The simplest approach is to use the plain \TeX\ font mechanism with the names from "psfonts.map". \begin{code} verbatimtex \font\rm=ptmr8r\rm etex \end{code} Adding this at the top of your \MP\ program will set your text in Times New Roman, although any maths will still be set using Computer Modern. To fix this, all you have to do is to redefine all the maths fonts in all sizes you need; this is not really that hard but it is a fiddle to get all the details right. Fortunately the wonderful "font-change" package has done it all for you for a large range of fonts; with this package installed you can use \begin{code} verbatimtex \input font_times etex \end{code} instead, and all of your \TeX\ labels, including bold letters, italics, small caps, and mathematics will be set in Times New Roman.\vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent Here are some samples of the fonts available in the "font-change" package. For full details, and especially details about using AMS symbols, see the package documentation. $$\includegraphics{trad-font-changes}$$ }} If you still can't get your labels to match, you can force \MP\ to use \LaTeX\ instead of plain \TeX. You need to use the "-tex" command line switch: \begin{code} mpost -tex=latex \end{code} and also load the packages you need in a "verbatimtex" block at the top of your file\rlap{\ $\longrightarrow$}\vadjust{\moveright 5.5in\vbox to 0pt{\hsize 4in\raggedright \vskip -42pt \noindent \begin{smallcode} verbatimtex \documentclass{article} \usepackage{mathpazo} \usepackage{xcolor} \begin{document} etex \end{smallcode} Note that the "\documentclass" and the "\begin{document}" lines are required, but \MP\ is smart enough to add an "\end{document}" for you.\vss}} Plain "mpost" needs an old-fashioned ".dvi" file to work with, so you can only use an engine that still produces one, like "latex" or "elatex", and not any of the more modern engines, like "pdflatex". Generating the labels takes a little bit longer because you have to load rather more `infrastructure' for \LaTeX, and you are limited to whatever font packages you have that work with the traditional \LaTeX\ engine. For a more modern approach, read on into section \ref{sec:neo-labels}. \newpage \subsection{Setting verbatim listings}\label{sec:verbatim} \textsc{There is a good chance} that you will never need to set a verbatim listing in a \MP\ drawing, but if you do there are a couple of things to think about. The issue about setting text verbatim with \TeX\ is that turning off the control characters can be tricky, so if you have text for a label with characters that are special in \TeX\ like the backslash or the underscore, then the simplest thing to do is to avoid \TeX\ completely and use \mpl{infont} instead. \mpic{-36pt}{verbatim-with-infont} \begin{code} string s; s = "\TeX\ sets maths like this $e=mc^2$"; draw ("1. " & s) infont defaultfont; draw ("2. " & s) infont "texnansi-lmr10" shifted 20 down; draw ("3. " & s) infont "cmtt10" shifted 40 down; draw ("4. " & s) infont "texnansi-lmtt10" shifted 60 down; \end{code} But as you can see, (1) this is a bit of a disaster with the default font "cmr10" because it does not have all the glyphs in the usual ASCII positions (as noted above §\ref{sec:charsets}). The solution is to use the version of the font with the "texnansi" encoding (2), but you probably want it in the monofont (3) and as you can see "cmtt10" has the “visible space” character instead of a regular space. If this is not what you want then use the alternative encoding (4). If you want more than this, then you really need to use \LaTeX\ to process the label, as discussed in §\ref{sec:fonts}, and load the appropriate preamble. \rightarrowfill\break \vadjust{\moveright5.5in\vbox to 0pt{\vskip -72pt\begin{smallcode} prologues := 3; outputtemplate := "%j.eps"; verbatimtex \documentclass{article} \usepackage{listings} \newcommand\mpstyle{\lstset{language=Metapost, basicstyle=\ttfamily, columns=fullflexible, keepspaces=true, showstringspaces=false}} \lstnewenvironment{code}[1][]{\mpstyle\lstset{#1}}{} \begin{document} etex beginfig(1); picture P; P = thelabel(btex \vbox{\begin{code} % special operators vardef incr suffix $ = $:=$+1; $ enddef; vardef decr suffix $ = $:=$-1; $ enddef; def reflectedabout(expr w,z) = % reflects about the line w..z transformed begingroup transform T_; w transformed T_ = w; z transformed T_ = z; xxpart T_ = -yypart T_; xypart T_ = yxpart T_; % T_ is a reflection T_ endgroup enddef; \end{code}} etex, origin); fill bbox P withcolor (1,1,31/32); draw P; draw bbox P; endfig; end. \end{smallcode}\vss}} \bigskip $$\includegraphics[width=0.9\textwidth]{verbatim-listing}$$ %% \subsubsection{Getting full access to your system fonts} %% %% If you want full access to all of your system fonts you can %% approach the problem the other way round and use one of the various means to include %% \MP\ graphics as part of your \LaTeX\ source code. These include "gmp" for %% pdf\LaTeX, "luamplib" for lua\LaTeX, and the whole Context system. The great %% advantage of these systems is that all of your \MP\ labels directly inherit the %% environment of the parent document, and give you access to all your system fonts and %% full Unicode support -- the only disadvantages are that it's not so fast or simple as plain \MP\ %% and you have to compile every graphic everytime you compile the document. It is of course always possible to %% use these systems to produce standalone PDF graphics that you can then include in a %% more conventional \TeX\ document. The example on the right shows how; in this case %% the text uses the fonts set in the \LaTeX\ preamble.\vadjust{\moveright5.5in\vbox to %% 0pt{\hsize 4in\vss\noindent %% Here is a version of the Lua logo, with a Unicode accent for show. %% $$\includegraphics[scale=0.7]{lulu.pdf}$$ %% produced with "luamplib": %% \begin{smallcode} %% \documentclass[margin=5mm]{standalone} %% \usepackage{fontspec} %% \setmainfont{TeX Gyre Heros} %% \usepackage{luamplib} %% \begin{document} %% \begin{mplibcode} %% beginfig(1); %% color lemon, midnight; lemon = (1,1,1/2); midnight = (0,0,1/2); %% %% fill unitsquare shifted -(1/2,1/2) scaled 4cm withcolor lemon; %% fill fullcircle scaled 3cm withcolor midnight; %% draw fullcircle scaled 3.7cm dashed evenly scaled 2 withcolor .5 white; %% %% fill fullcircle scaled 8mm shifted (0.7cm,0.7cm) withcolor white; %% fill fullcircle scaled 8mm shifted (1.4cm,1.4cm) withcolor midnight; %% %% label.bot(btex Luã etex scaled 2.8,origin) withcolor white; %% endfig; %% \end{mplibcode} %% \end{document} %% \end{smallcode} %% }} \newpage \section{Modern labels and annotations}\label{sec:neo-labels} This section is a re-working of the previous section, that attempts to show how much nicer it is to handle labels in the new world of "luamplib". If this is all new to you, you probably should start by doing "texdoc luamplib" on your system and reading the documentation provided with the package. In order to use these newfangled facilities you need to create your \MP\ diagrams inside a \TeX-wrapper as explained above in §\ref{sec:sa-lua-flow}. \medskip\noindent The first thing to say is that everything in the preceding section will continue to work more or less the same when you use "luamplib" with Lua\LaTeX. It is designed to be backwards-compatible, so that existing \MP\ programs using "infont" and "btex" \dots\ "etex" will continue to work without change. The only differences are: that the "TEX()" macro is re-implemented with internal library functions so that it no longer uses temporary files, and is therefore very much faster; and it is easier to integrate your drawings into \LaTeX\ because you no longer need to muck about with \mpl{verbatimtex} blocks. So the example code shown on the right,\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip-160pt \begin{texcode} \documentclass[border=5mm]{standalone} \usepackage{fontspec} \setmainfont{TeX Gyre Pagella} % <-- note chosen font \usepackage{luamplib} \begin{document} \begin{mplibcode} \end{texcode} \vskip-\baselineskip \begin{smallcode} beginfig(1); for x = 0 upto 1: draw (80x,16) -- (80x, -68) withcolor 3/4[red, white]; endfor for y = 0 upto 3: draw (0, -20y) -- (160, -20y) withcolor 3/4[red, white]; endfor string s; s = "Hand gloves"; draw s infont defaultfont shifted (0, 0); draw s infont "phvr8r" shifted (0, -20); draw TEX(s) shifted (0, -40); draw btex Hand gloves etex shifted (0, -60); dotlabel.urt(s, (80, 0)); dotlabel.urt(s infont "phvr8r", (80, -20)); dotlabel.urt(TEX(s), (80, -40)); dotlabel.urt(btex Hand gloves etex, (80, -60)); endfig; \end{smallcode} \vskip-\baselineskip \begin{texcode} \end{mplibcode} \end{document} \end{texcode}\vss}} will produce this: $$\includegraphics{neo-labels.pdf}$$ Note that "defaultfont" is still "cmr10" with the encoding that has the small stroke (that plain \TeX\ uses for the \L\ character) instead of a space, and that you can still use PostScript fonts like "phvr8r". But also notice that the "TEX()" macro and the "btex" \dots\ "etex" construction have picked up the font set by the \LaTeX\ wrapper. As you can see they produce exactly the same output; "TEX()" is generally more useful because you can pass a primary string variable as an argument, which makes it easier to construct dynamic labels. "TEX()" also has the synonym "textext()" for compatibility with ConTexT. You can use either name, as you prefer. \smallskip\noindent But this isn't the clever bit\dots \clearpage \subsection{The magic of the \texttt{textextlabel} option}\label{ttlabel} The clever bit is that "luamplib" allows us to turn on the "TEX()" behaviour by default, so that you can just use plain strings with the \mpl{label()} macro, and have them automatically processed through \LaTeX. All you have to do is add this to the preamble: \begin{texcode} \mplibtextextlabel{enable} \end{texcode} If you add this line to the example from the previous page,\vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip-80pt \begin{texcode} \documentclass[border=5mm]{standalone} \usepackage{fontspec} \setmainfont{TeX Gyre Pagella} \usepackage{luamplib} \mplibtextextlabel{enable} % <--- added option \begin{document} \begin{mplibcode} \end{texcode} \vskip-\baselineskip \begin{smallcode} beginfig(1); for x = 0 upto 1: draw (80x,16) -- (80x, -68) withcolor 3/4[red, white]; endfor for y = 0 upto 3: draw (0, -20y) -- (160, -20y) withcolor 3/4[red, white]; endfor string s; s = "Hand gloves"; draw s infont defaultfont shifted (0, 0)0 draw s infont "phvr8r" shifted (0, -20); draw TEX(s) shifted (0, -40); draw btex Hand gloves etex shifted (0, -60); dotlabel.urt(s, (80, 0)); dotlabel.urt(s infont "phvr8r", (80, -20)); dotlabel.urt(TEX(s), (80, -40)); dotlabel.urt(btex Hand gloves etex, (80, -60)); endfig; \end{smallcode} \vskip-\baselineskip \begin{texcode} \end{mplibcode} \end{document} \end{texcode} \vskip 58pt \centerline{\red{$\star$ All the examples in the rest of this section $\star$}} \centerline{\red{assume that you have set \texttt{\textbackslash mplibtextextlabel}}} \vss}} you get this output: $$\includegraphics{neo-labels-tte.pdf}$$ As you can see, they all come out the same. When the magic option is enabled, "luamplib" redefines the primitive binary operator \mpl{infont}. Ordinarily, this command takes two strings (the text you want to show, and the name of the font to use) and produces a picture object consisting of the text typeset in the given font. $$\ \mathbin{"infont"} \ \longrightarrow \$$ With the option enabled, the right hand \ argument (which names the font) is completely ignored, and the left hand \ argument (the text to show) is passed to the "TEX()" macro. The result is still a \ of course, but instead of a simple rendering in a single font, the string will have been passed through \LaTeX, so it can include maths, bold text, or any arbitrary typesetting constructions. Note that even with the option enabled, \MP\ will not let you pass a \ to \mpl{draw}. You have to put \mpl{infont "somefont"} after the string to get the magic to work; the nice thing is that the \mpl{label()} macros do this for you. If you experiment a bit, you will find that even though the font name argument is completely ignored, you can't leave it out; you have to give at least an empty string: \mpl{draw "my text" infont ""}. However if you find yourself writing this, you probably should try \mpl{draw TEX("my text")} instead. \subsection{Using Unicode and matching style with OTF fonts}\label{sec:neo-otf} If you read "texdoc luamplib" carefully, you will see that you \textit{can} use all these new facilities with plain Lua\TeX, but this chapter is about using them with Lua\LaTeX, and in particular it assumes some familiarity with the packages "fontspec" and "unicode-math" that provide complete support for Unicode and OTF fonts; you need this familiarity in order to use "luamplib" properly. \mpic{1cm}{unicode} You also need an editor that will handle Unicode. \MP\ still restricts you to using printable ASCII in your source code, except within a string literal or a "btex" \dots\ "etex" picture literal. So it becomes very easy to write this sort of label: \begin{smallcode} label("café noir £2.50", origin); \end{smallcode} or even whole paragraphs that use Unicode: \begin{smallcode} label(btex \vbox{\hsize 4in Nous étions à l'Étude, quand le Proviseur entra, suivi d'un \textit{nouveau} habillé en bourgeois et d'un garçon de classe qui portait un grand pupitre. Ceux qui dormaient se réveillèrent, et chacun se leva comme surpris dans son travail. \par} etex, 40 down); \end{smallcode} But you also need a font that actually supports the Unicode characters you use. The default Latin Modern font used by Lua\LaTeX\ has a good range for English and most European languages, but is a bit lacking in (say) polytonic Greek. So you will need to define a suitable font in your preamble, and turn it on in your labels. \begin{texcode} \usepackage{fontspec} \newfontface\polytonic{GFS Porson} \end{texcode} then a box like this with proper polytonic Homeric Greek source \begin{smallcode} label(btex \vbox{\polytonic\halign{#\hfil\cr ... (polytonic greek source in UTF8 that won't show up in the Latin Modern Typewriter font being used here) ... \cr}} etex, 120 down); \end{smallcode} will produce the first few lines of the Iliad (just in case you wanted them). Essentially if you can produce something in \LaTeX, you can produce exactly the same in \MP\ using "luamplib" (but see also §\ref{sec:verbatim}). \newpage \subsection{Multi-line labels} It is a rule of syntax in \MP\ that a string token has to be given all on one line. So if you have very long labels, or paragraphs of text, then you have to split them up into separate shorter string tokens: \begin{code} label("\vbox{\hsize 4in It is a truth universally acknowledged," & " that a single man in possession of a good fortune," & " must be in want of a wife.\par}", origin); \end{code} taking care to include the necessary spaces, which can get fiddly. \mpic{-15mm}{multi-line-labels} But this is where the "btex" \dots\ "etex" construction comes into play, even with "luamplib". As we saw in the preceding section the construction fits into the \MP\ syntax scheme as a special pair of quotation marks that produces a \. Unlike regular string token, a "btex" \dots\ "etex" picture token can span several lines of source code, so you can (more easily) write long \TeX\ labels like this: \begin{code} label(btex \vbox{\hsize 4in It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife. \par} etex, 128 down); \end{code} Thanks to the backward compatibility of the implementation, this works very well even when you have "mplibtextextlabel" enabled. You also have full access to your \LaTeX\ environment, so you can get tables in the same way in \MP\ using environments like "tabular": \begin{code} label(btex \begin{tabular}{c} A way to get simple\\ two line labels \end{tabular} etex, 256 down); \end{code} But recall that whatever you ask the \mpl{TEX()} macro to typeset like this is going into a restricted horizontal mode box; so don't try to use floating environments like "table" or "figure". And if you want automatic paragraph wrapping, you will have to wrap your text in a suitable "\vbox", as shown above. \subsection{Display maths} Because the \mpl{TEX()} macro typesets everything in restricted horizontal mode, you cannot use "$$ .. $$" to create display maths directly. This is not a \TeX\ \textit{v} \LaTeX\ issue, it is just that for compatibility with plain \MP\ (and common sense), the designers of "luamplib" chose to typeset labels into horizontal-mode boxes This is usually what you want. If you prefer large integral operators (etc) in your labels, then you should either add "\displaystyle" at the beginning of your formula $\longrightarrow$\vadjust{\moveright5.5in\vbox to 0pt{\hsize 4in\vss\noindent \begin{code} ... label("$\displaystyle \int_0^t 3x^2\, dx$", z0); ... label("\vbox{\hsize 2in $$\int_0^t 3x^2\, dx$$}", z1); ... \end{code} }} \\ or wrap the formula in a "\vbox" with a suitable "\hsize". Using "\displaystyle" is probably simpler. \subsection{Typographical minus signs and other dynamic labels} This is really easy with "mplibtextextlabel" enabled, because we can assemble a string on the fly using standard \MP\ syntax:\mpic{0pt}{simple-number-line} \begin{code} draw (left--right) scaled 2in withcolor 2/3 red; for i=-4 upto 4: dotlabel.top("$" & decimal i & "$", (32i, 0)); endfor \end{code} The normal operator precedence rules ensure that the string argument to \mpl{dotlabel} is assembled before it is passed to the \mpl{TEX()} macro. The individual parts of the string you assemble do not have to be valid bits of \TeX\ in themselves; they only have to make sense once they are actually passed to the macro. With "luamplib" there are no slow external files being used, so the complexities used above [§\ref{sec:old-and-dynamic}] to label points around a circle can be simplified without sacrificing speed:\mpic{-80pt}{simple-circle-labels} \begin{code} path C; C = fullcircle scaled 100; draw C withcolor 2/3 red; for i=0 upto 11: drawdot point 2/3 i of C withpen pencircle scaled dotlabeldiam; label("$p_{" & decimal i & "}$", point 2/3 i of C scaled 1.17); endfor \end{code} \smallskip\noindent\nb But note that you can't do this string concatenation with "btex" \dots\ "etex"; although they might appear to be special quotation marks, they produce a \, and \mpl{&} only works with strings or paths. \newpage \subsection{Drawing on an external image}\label{sec:extimage} One of the limitations of the way that plain "mpost" uses \TeX\ is that any "\special" commands are removed from the intermediate file that \MP\ translates into a \ variable. Hence, in particular, you cannot use "\includegraphics" in a \TeX\ label. Fortunately, "luamplib" removes this limitation, so it is now possible to annotate images using the full array of \MP\ tools. $$\includegraphics[width=360pt]{marked-up-photo}$$ The source is shown on the right. \vadjust{\moveright5.5in\vbox to 0pt{\vskip-3.75in\hsize 4in\raggedright\noindent \begin{texcode} \documentclass[border=1mm]{standalone} \usepackage{luamplib} \usepackage{graphicx} \usepackage{fontspec}\setmainfont[Scale=0.6]{Helvetica} \mplibtextextlabel{enable} \begin{document} \begin{mplibcode} \end{texcode} \begin{smallcode} beginfig(1); draw btex \includegraphics[width=5in]{glenshiel.jpg} etex; if false: for i=1 upto 36: draw (origin -- 180 up) shifted (10i, 0) withcolor if i mod 10 = 0: red else: 1/2 fi; endfor for i=1 upto 18: draw (origin -- 360 right) shifted (0, 10i) withcolor if i mod 10 = 0: red else: 1/2 fi; endfor fi vardef callout@#(expr t, p, o) = save T; picture T; T = thelabel.@#(t, p+o); draw T; drawarrow p+o -- p cutbefore bbox T; enddef; ahangle := 20; ahlength := 2; drawoptions(withpen pencircle scaled 1/4 withcolor 1/2 blue); callout.top("Sgurr na Ciste Dubhe", (80, 96), (-10, 20)); callout.top("Sgurr nan Spainteach", (100, 91), (6, 12)); label.top("\tiny Cuillin Ridge, Isle of Skye", (140, 81)); label.top("Sgurr na Carnach", (190, 90)); label.top("Sgurr Fhuaran", (282, 94)); label.bot("\itshape View looking west ...", point 5/2 of bbox currentpicture shifted 4 down); endfig; \end{smallcode} \begin{texcode} \end{mplibcode} \end{document} \end{texcode} \vss}} The two loops commented out with \mpl{if false:} will add a grid on top of the photo like this: $$\includegraphics[width=200pt]{marked-up-photo-with-grid}$$ This makes it easier to find the appropriate coordinates for your annotations. \newpage \section{Working with pictures} \MP\ inherits the mechanism of \ variables directly from \MF, except that the contents of these variables are a bit more complex. The system keeps track of the active picture in a variable called \mpl{currentpicture}, which can be copied to your own variables, or manipulated in various useful ways. In \MF\ the contents of the variable is a pattern of pixels for a font, in \MP\ the contents are vector graphics commands. This section reviews some of the things you can do with a \ variable — including putting one in a frame (see §\ref{sec:pictureframe}) like so\rlap{\ $\longrightarrow$} \mpic{-96pt}{youth} \bigskip\noindent Plain \MP\ provides two built-in \ variables: \mpl{nullpicture}, which is empty, and \mpl{currentpicture}, which accumulates the results of drawing commands. When you compile your program, the \mpl{beginfig} macro will set \mpl{currentpicture} to blank, and the \mpl{endfig} macro will make \MP\ write the accumulated contents of the picture to an output file, usually as PostScript. You can also do these things yourself at any point in a program, using these macros from "plain.mp": \begin{code} def clearit = currentpicture := nullpicture enddef; def shipit = shipout currentpicture enddef; \end{code} \smallskip\noindent When you are creating a diagram with several independent elements, it is often helpful to save the \mpl{currentpicture} in a \ variable and start again. In fact it is so useful that plain \MP\ includes an \mpl{image} macro that uses the magic of macro grouping to make the process a bit easier. \begin{code} vardef image(text t) = save currentpicture; picture currentpicture; currentpicture := nullpicture; t; currentpicture enddef; \end{code} The general idea is that you declare a variable and then save a drawing into it: \begin{code} picture P; P = image(...); \end{code} and then you have a picture element that can be manipulated or copied as needed. The rows of decorative beads in the frame on the right were created like this. \newpage \subsection{Creating and transforming pictures} After you have declared a variable with \mpl{picture P;} you can give it some contents in a number of ways: \begin{itemize} \item \mpl{P = nullpicture;} --- this makes $P$ empty. \item \mpl{P = currentpicture;} --- save a copy of your current picture (if any). \item \mpl{P = image(... MP tokens ...);} --- capture some drawing commands. \item \mpl{P = "string" infont "font-name";} --- capture an image of "string" set in the given font. \item \mpl{P = btex ... TeX tokens ... etex;} --- capture the result of passing some arbitrary tokens through \TeX. \item \mpl{P = TEX("string");} --- capture the result of passing some arbitrary string of tokens through \TeX, using the "TEX" macro. \end{itemize} You can read more about the details of type setting in §\ref{sec:trad-labels} and §\ref{sec:neo-labels}, but the point here is that the results are normal \ variables that you can manipulate and use like any other. You can apply any of the normal \MP\ transformations to a picture, so it can be slanted, scaled, rotated, or shifted like any \ or \. Each picture has a reference point that is the position of the origin for pictures created with \mpl{image} or by saving \mpl{currentpicture} directly, and is usually the bottom left-hand corner of a typeset picture created by \TeX. So to add three copies of $P$ to your current picture, you could do: \begin{code} for i=1 upto 3: draw P shifted (20i, 0); endfor \end{code} and \MP\ will add copies of $P$ with the reference points shifted to $(20,0)$, $(40,0)$, and $(60,0)$. A selection of other transformations is shown on the right $\longrightarrow$ \vadjust{\moveright5.5in\vbox to 0pt{\hsize4in\vskip-240pt\centerline{\includegraphics[width=4in]{twister}}\par \centerline{\textsl{\small The reference point for each compass is the small dot in the middle.}} \vss}} \smallskip\noindent If you need to measure the size of your picture, you can get the coordinates of the corners with the built-in corner commands, and do some arithmetic like this: \begin{code} (wd, ht) = urcorner P - llcorner P; \end{code} You also get \mpl{ulcorner}, \mpl{lrcorner}, and \mpl{center}; plus \mpl{bbox} which returns the rectangular path round the four corners, expanded by the current value of \mpl{bboxmargin}. (See also §\ref{sec:rotated-boxes}). \newpage \subsection{Clipping and bounding boxes} Once you have got your \ variable, and possibly transformed it, the main thing you can do with it is to use \mpl{draw} to add it to the current picture. But there are two other commands that are sometimes helpful that allow you to alter the apparent size of the picture. \begin{itemize} \item $\kw{setbounds}\ \ \kw{to}\ \$ \item $\kw{clip}\ \ \kw{to}\ \$ \end{itemize} Both commands set the boundary of your picture to the arbitrary path expression, and then the \mpl{clip} command also erases all of the picture that lies outside the boundary. (Note that this is not the same as setting the bounding box. The arbitrary path does not have to be a rectangle; after either of these commands the bounding box will be the rectangle that fits around the arbitrary path). \MP\ inherits the \mpl{clip} command from PostScript; there is no equivalent in \MF. It can be useful as an alternative to \mpl{buildcycle}, but it is most commonly used for trimming a repeating pattern to a particular shape. The usual approach is to define a particular shape, $s$, then draw your pattern over a large area that covers the shape, and finally call \mpl{clip currentpicture to s} to trim the pattern to the shape. This is best done after you define all your shapes, but before you draw any others or add any labels. The example on the right shows this approach in action. You can apply \mpl{clip} to any picture, so you might prefer to capture your pattern in \ variable with \mpl{image}, apply \mpl{clip} to that, and then \mpl{draw}. This works nicely if you want to repeat the clipped image. \vadjust{\moveright 5.5in\vbox to 0pt{\hsize 4.2in \vss \noindent\includegraphics[width=4in]{shady-circles} \medskip \begin{smallcode} path c, C; numeric r; r = 60; c = fullcircle scaled 2r shifted (-r, 0); C = fullcircle scaled 4r shifted (2r, 0); numeric t, u; (t, whatever) = C intersectiontimes C shifted (center c - center C); (u, whatever) = c intersectiontimes (point t of C -- center c); path s; s = subpath (0, u) of c -- subpath (t, 4) of C -- cycle; for i=0 upto r: draw (left--right) scaled 2r rotated -42 shifted (3i, 0) withpen pencircle scaled 1/4 withcolor 2/3 blue; endfor clip currentpicture to s; draw c; draw C; draw center c -- center C -- point t of C -- cycle; \end{smallcode} \vskip -126pt}} You can also use this technique to fill with a gradient: just reduce the gap between each line and use the index variable to blend between two colours. Something like \mpl{withcolor (i/r)[blue, white]} in the example shown. \vfill\noindent \hey Why would you ever want to use \mpl{setbounds}? Mainly to help with aligning type set labels, as discussed in §\ref{infontbbox}, or if you want to make boundaries of different picture elements consistent in order to line them up more easily. Or perhaps to set a margin for the whole image by using something like this just before the \mpl{endfig}. \begin{code} setbounds currentpicture to bbox currentpicture; \end{code} This has the effect of adding a \mpl{bboxmargin} wide strip all round. \newpage \subsection{Bounding boxes of transformed pictures}\label{sec:rotated-boxes} When you rotate a text label, or otherwise transform a picture, the corner-points also change, but not quite in the way you might think. It turns out that the \mpl{bbox} is always a rectangle aligned to the edges of your page. Effectively, the corners are determined \textit{after} any transformation, and the \mpl{center} is strictly the intersection of the lines between opposite corners.\mpic{-68pt}{corners} You will notice this if you use the technique given on p.\thinspace29 of the \MP\ manual to draw a label on a coloured (or erased) background; if you have rotated the label, the \mpl{bbox} may be larger than you want. One solution is to define your label untransformed and then apply the transformation twice: first when you fill the bounding box and again when you draw the label, for example: \begin{code} picture p; p = thelabel.top("Correctly", origin); unfill bbox p rotated 30 shifted z0; draw p rotated 30 shifted z0; \end{code} \vfill \subsection{Using pictures to assemble a complex diagram} If you have a diagram with several independent parts, like the comparison above then there is a useful general technique: declare a subscripted \ variable, and then use \mpl{image} to draw each part separately. The advantage of this is that you do not have to worry about where the \mpl{origin} is, which often makes a drawing simpler (for example because you can use \mpl{rotated} rather than \mpl{rotatedaround}). Once you have created all the parts you can then add them to the final image using \mpl{draw} as shown on the right $\longrightarrow$ \vadjust{\moveright 396pt\vbox to 0pt{\hsize 4in \vskip -81pt \noindent The illustration above was drawn using this general sub-picture technique, approximately like this: \begin{code} picture P[]; P1 = image( % first drawing... ); P2 = image( % second drawing... ); draw P1 shifted 100 up; draw P2 shifted 100 down; \end{code} \vss}} Sometimes it is more convenient to use \mpl{label} to place the pictures, taking advantage of the automatic alignment provided. Note also that, unless you have explicitly filled them with \mpl{white} colour, the blank parts of each picture are really transparent so you can overlap them when appropriate. \newpage \subsection{Adding a caption to the current picture} When you have finished a complicated picture, you may want to add a caption or some other label which would look neat if it were exactly centred at the bottom of the everything else. You could keep track of exactly how wide and deep you have made the picture to do this, but there is an easier way, that will adjust itself automatically if you change the contents of the picture later. \begin{code} beginfig(1); % ... complete drawing that needs a caption ... label.bot("This picture needs a label at the bottom", point 1/2 of bbox currentpicture); endfig; \end{code} Through the automatic alignment routines in \mpl{label}, this will produce a label neatly centred at the bottom. If it is too close you can either set a larger \id{bboxmargin} or use something like: \begin{code} label.bot("This picture needs a label at the bottom", point 1/2 of bbox currentpicture shifted 42 down); \end{code} Note that in both cases the addition of the label will move the corner points of the picture, so that the bounding box will have been expanded to include the new label. You can use this feature to add a series of centered labels. But if this is not what you want, perhaps because you want to add two labels side by side at bottom, then you can “freeze” the current bounding box like this: \begin{code} picture bb; bb = bbox currentpicture; label.bot("Left label", point 1/4 of bb); label.bot("Right label", point 3/4 of bb); \end{code} \noindent The path returned by \mpl{bbox} has four points starting at the lower left and proceeding clockwise like a \mpl{unitsquare}. So \mpl{point 1/2 of bbox currentpicture} is half way between lower left and lower right, while \mpl{point 5/2 of bbox currentpicture} is half-way from upper right to upper left. Note that the path is defined even if the current picture is empty. If you call \mpl{bbox currentpicture} at the start of a picture you will get a square path centered on the origin and scaled to $2 \id{bboxmargin}$. \moveright5.5in\vbox to 0pt{\hsize 4in \vss \noindent Here is an example. $$\includegraphics[width=4in]{double-angle}$$ The labels at the bottom were added like this: \begin{smallcode} label.bot("$\triangle ACD \sim \triangle ABC$", point 1/2 of bbox currentpicture shifted 24 down); path bb; bb = bbox currentpicture shifted 12 down; label.bot(btex \vbox{....} etex, point 1/4 of bb); label.bot(btex \vbox{....} etex, point 3/4 of bb); \end{smallcode} The second call to \mpl{bbox currentpicture} gets the bounding box that includes the first centered label.} \newpage \subsection{Drawing pictures with various colours and pens} Consider the \ with different colours and pens in the example here $\longrightarrow$ \vadjust{\moveright5.5in\vbox to 0pt{\vskip -1.5\baselineskip \begin{smallcode} numeric s; s = 21; path alpha; alpha = ((-2s, s) {right} .. halfcircle rotated -90 scaled 2s shifted (2s, 0) .. {left} (-2s, -s)) shifted (s*left); vardef overdraw(expr a, b, r, P, shade) = linecap := butt; undraw subpath (a+r, b-r) of P withpen pencircle scaled 2; draw subpath (a, b) of P withcolor shade; enddef; picture cb; cb = image( draw alpha withcolor 2/3 red; undraw alpha rotated 180 withpen pencircle scaled 2; draw alpha rotated 180 withcolor 2/3 blue; overdraw(0.21, 0.36, 0.02, alpha, 2/3 red); overdraw(0.67, 0.86, 0.02, alpha, 2/3 red); overdraw(3.4, 4.3, 0.1, alpha, 2/3 red); overdraw(5.4, 5.6, 0.02, alpha, 2/3 red); overdraw(5.4, 5.6, 0.02, alpha rotated 180, 2/3 blue); ); \end{smallcode} \vskip 48pt\noindent \begin{minipage}{4in} \begin{itemize} \item Example 1 shows that by default \mpl{draw} uses the colours and pens defined in the picture \item Examples 2, 3, and 4 show what happens if you change the pen, or the colour, or both. \item Example 5 shows you how to make a bagel in \MP. \item Example 6 shows you the slightly tricky syntax to extract the paths, pens, and colours from the \ and adjust them as needed. \end{itemize} \end{minipage} \vss}} With this captured in a \ variable, you can \mpl{draw} it with different colours and pens to obtain a variety of effects: $$\includegraphics[width=\textwidth]{draw-picture.pdf}$$ The picture is supposed to represent a fancy knot (a “Carrick bend”), and to show the red and blue strands crossing each other. The \mpl{overdraw} macro tries to do this by undrawing with a thick pen, then redrawing the upper strand on top. \newpage \subsection{Simulating transparency} Filling with transparent colour can sometimes be a very effective graphic technique, but the underlying technical implementation is often dauntingly complex. Plain \MP\ provides no colour model that directly supports transparency for any output format, so if you need it you will have to resort to layering and managing the colour blending yourself. This page presents an example of the basic technique, that can be adapted to more general purpose macros as required. The technique is included in this section, because it involves more manipulation of \ variables. \vadjust{\moveright5.5in\vbox to 0pt{\vskip -128pt $$\includegraphics[width=3in]{fake-transparency}$$ Omitting the simple grid, this drawing was produced like this: \begin{smallcode} % Large A label.urt("A" infont defaultfont scaled 8, origin) withcolor 1/4 green; % An arbitrary shape path shape; shape = (superellipse(right, up, left, down, 0.81)) shifted 1/2 right scaled 30 rotated 30; % Parameters alpha = 5/8; % alpha: 0=invisible, 1=opaque color filler; filler = .95[red,white]; picture fg, bg; bg = currentpicture; % capture the current drawing fg = image( for e within bg: % redraw everything in blended color draw e withcolor alpha[colorpart e, filler]; endfor % and add some decorations draw shape withpen pencircle scaled 2 withcolor 3/4; draw subpath (2.718, 3.1415) of shape shifted - center shape scaled 7/8 shifted + center shape withpen pencircle scaled 2 withcolor white; ); clip fg to shape; % now clip the fg drawing to the shape fill shape withcolor filler; % fill the shape draw fg; % and put the fg drawing on top draw shape withcolor 3/4 blue; % make a nice edge \end{smallcode} \vss}}% The two useful tools in the plain \MP\ kit bag are: \begin{itemize} \item The ability to loop through all the elements of a picture \item The ability to blend colours using the mediation syntax \end{itemize} The example drawing on the right consists of a regular grid and a text picture, with a bubble drawn over the top. The bubble can be made to look transparent like this: \begin{enumerate} \item Define the shape that you want to be transparent, decide on how opaque you want it, and the colour to use. \item Capture the current drawing in a \ variable. \item Loop over all the elements in that picture, redrawing each one with a blended color, and capture all this in another \. \item Add some decoration; here there is an internal margin, and a hint of a reflection line to make it look shiny. \item Clip the new blended-colour picture to the shape. \item Fill the shape with the filler colour. \item Draw the blended-colour parts on top. \item Finally, add a neat edge (if needed). \end{enumerate} As you may appreciate, with this approach, you need to do the transparent parts after you have drawn everything else in your drawing. \newpage \subsection{Adding a background and other post-processing}\label{backgrounds} The \ capture technique provides a simple way to add a background or do other post-processing on your drawing. The advantage is that you do not have to work out the size of your drawing before you start. \moveright5.5in\vbox to 0pt{\vskip -43pt Here is an example that adds graph paper behind a drawing. $$\includegraphics{graph-paper}$$ \begin{smallcode} input colorbrewer-rgb path C; C = fullcircle scaled 120 shifted 12 up rotated 6; for t=0,1.2,4: draw center C -- point t of C withcolor Blues 8 8; endfor draw C withcolor Reds 8 8; dotlabel.urt("Start", point 0 of C); vardef grid(expr ll, ur, grid_unit) = save llx, lly, urx, ury, G; numeric llx, lly, urx, ury; (llx, lly) = ll; (urx, ury) = ur; picture G; G = image( for x = floor(llx / grid_unit) + 1 upto floor(urx / grid_unit): draw (x * grid_unit, lly) -- (x * grid_unit, ury); endfor for y = floor(lly / grid_unit) + 1 upto floor(ury / grid_unit): draw (llx, y * grid_unit) -- (urx, y * grid_unit); endfor fill fullcircle; % <-- show the origin ); G enddef; picture P; P = currentpicture; currentpicture := nullpicture; drawoptions(withpen pencircle scaled 1/4); draw grid(llcorner P, urcorner P, 1mm) withcolor Blues 8 1; draw grid(llcorner P, urcorner P, 10mm) withcolor Blues 8 2; drawoptions(); draw P; \end{smallcode} \vss} \smallskip\noindent You could add a subtle off-white background fill like this: \begin{smallcode} picture P; P = currentpicture; fill bbox P withcolor (1,1,31/32); draw P; \end{smallcode} Or you can be more ambitious, as shown in the example on the right \rightarrowfill\break In general, you draw any background you want, like this: \begin{smallcode} picture P; P = currentpicture; currentpicture := nullpicture; % do complex background drawing... clip currentpicture to bbox P; draw P; \end{smallcode} Or you can do things like make automatic adjustments to the scale. If you wanted to be sure that your drawing was not more than 5 inches wide, you could try this just before the \mpl{endfig}: \begin{smallcode} numeric wd; wd = xpart (urcorner currentpicture - llcorner currentpicture); if wd > 360: currentpicture := currentpicture scaled (360/wd); fi \end{smallcode} \bigskip\noindent If you wanted to apply one of these changes to all the figures in your "mpost" input file then you can use the hook provided by plain \MP: \begin{smallcode} extra_endfig := "picture P; P = currentpicture;" & "fill bbox P withcolor (1,1,31/32); draw P;"; \end{smallcode} The definition of \mpl{endfig}, includes the line \mpl{scantokens extra_endfig;} so that any contents of the string variable \mpl{extra_endfig} are automatically processed before the figure is produced. If you are using "luamplib" then you can use the alternative hook that it provides so that you do not even have to type \mpl{endfig}: \begin{smallcode} \everyendmplib{picture P; P = currentpicture; fill bbox P withcolor (1,1,31/32); draw P; endfig;} \end{smallcode} \newpage \subsection{Adding a ruler} \textsc{If you wish} to check the dimensions of your drawing, it can be useful to add a temporary ruler that shows you the dimensions of the bounding box like this: $$\includegraphics{icosahedron}$$ The red rulers were added by putting \mpl{input ruler-cm} at the end of the figure. \vadjust{\moveright5.5in\vbox to 0pt{\vss\hsize 4in\raggedright\noindent Here is the implementation of "ruler.mp": \begin{code} % add a ruler along the left hand and lower edges % of the bounding box of the currentpicture path B; B = bbox currentpicture; for s=0, 1: path p; numeric a; pair o; p = subpath (0, 1) of if s=0: reverse fi B; a = arclength p; o = if s=0: left else: down fi; for i=0 upto 3: exitif not known u[i]; for j=0 upto floor(a/u[i]): pair t; t = point arctime j*u[i] of p of p; draw (origin -- (6 - 2i) * o) shifted t; if i=0: label(decimal j, t shifted 12 o); fi endfor endfor draw p; endfor \end{code} The inner loop draws successively shorter lines at each of the minor units, and numbers at the major units. \vss}} They are drawn round the bounding box, set here with the default margin of 2\unit{bp}. The "ruler-cm.mp" file looks like this: \begin{code} numeric u[]; u0 = 1 cm; u1 = 1 mm; drawoptions(withcolor 0.54 red); input ruler drawoptions(); \end{code} and there is a companion "ruler-inch.mp" file that looks like this: \begin{code} numeric u[]; u0 = 1 in; u1 = 1/4 in; u2 = 1/12 in; drawoptions(withcolor 3/4 blue); input ruler drawoptions(); \end{code} The idea is that you set a subscripted variable \mpl{u[]} to a number of unit sizes where you want markers and then call \mpl{input ruler}. \newpage \subsection{Adding a border}\label{pics-border} \textsc{In most documents} the drawings look just fine without any decoration, but sometimes you might want to add emphasis or pick out part of a drawing. The examples here can be applied to \mpl{currentpicture} or any other \ variable.\vadjust{\moveright 396pt\vbox to 0pt{\hsize 4in\vskip -42pt $$\includegraphics{border.pdf}$$ \begin{smallcode} % don't take this one too seriously... vardef rope expr c = save hemp, s, w, n, A, a, b; color hemp; hemp = 1/256 (224, 202, 169); numeric s, w, n, A; A = arclength c; s = A/floor(A/2); w = -1; n = -1; path a[]; for t=0 step s until A + 1: a[incr n] = (0,+w) rotated angle direction arctime t-3/2s of c of c shifted point arctime t-3/2s of c of c .. (0,+w) rotated angle direction arctime t-1/2s of c of c shifted point arctime t-1/2s of c of c .. (0,-w) rotated angle direction arctime t+1/2s of c of c shifted point arctime t+1/2s of c of c .. (0,-w) rotated angle direction arctime t+3/2s of c of c shifted point arctime t+3/2s of c of c; endfor image(for i=1 upto n: path b; b = buildcycle(a[i-1], reverse a[i]); fill b withcolor hemp; draw b withpen pencircle scaled 1/8; endfor) enddef; interim bboxmargin := 16; draw rope rounded_corners bbox currentpicture; \end{smallcode}\vss}} $$\vbox{\halign{$\vcenter{\hbox{\includegraphics[width=150bp]{#}}}$&\quad$\vcenter{\hbox{#}}$\cr border-shadow& \begin{smallcode} picture P; P = currentpicture; fill bbox P shifted (3,-3) withcolor 3/4; unfill bbox P; draw bbox P; draw P; \end{smallcode}\cr border-dashed& \begin{smallcode} vardef rounded_corners expr p = for i=1 upto length p: subpath (i-15/16, i-1/16) of p .. endfor cycle enddef; interim bboxmargin := 16; draw rounded_corners bbox currentpicture dashed evenly scaled 3/4; \end{smallcode}\cr }}$$ \newpage \subsection{Adding a frame}\label{sec:pictureframe} As promised at the start of this section, here is the code for the picture frame drawn round Raphael's young man. \begin{code} input picture_frame beginfig(1); picture F; F = thelabel(TEX("\includegraphics{youth.jpg}"), origin); draw F; draw frame bbox F; endfig; \end{code} All the heavy lifting is done by "frame" macro defined in "picture_frame.mp" $\longrightarrow$ \vadjust{\moveright5.2in\vbox to 0pt{\hsize 4in\vskip-184pt \begin{smallcode} vardef frame expr P = save base, side, f, t, u, xx; picture base, side; path f; numeric t, u, xx; % work out some measurements t = arclength subpath (0,1) of P; u = arclength subpath (1,2) of P; xx = max(t, u) + 2 pf_wd; f = unitsquare xscaled xx yscaled pf_wd; % convenience / nonce function vardef paint_strip(expr y, wd, shade) = draw subpath (0, 1) of f shifted (0, if y < 0: pf_wd + fi y) withpen pencircle scaled wd withcolor shade enddef; base = image( % background colour fill f withcolor gold; % grey strips paint_strip(2, 3, 5/4 grey); paint_strip(3.5, 1/4, grey); paint_strip(5, 1/4, 1/2[gold, dark]); paint_strip(-6.5, 1/4, 1/2[gold, dark]); paint_strip(-6, 1/4, 1/2[gold, dark]); paint_strip(-2, 2, 5/4 grey); % spatter with random spots for i=0 upto 4 * arclength(subpath (0,1) of f): fill fullcircle scaled uniformdeviate 3/4 shifted (uniformdeviate xx, uniformdeviate pf_wd) withcolor dark; endfor % decorative balls for x = 2 step 3 until xx: draw ball shifted (x, 2); endfor ); % make two trapezium shapes side = base; clip side to (pf_wd, 0) -- (pf_wd + u, 0) -- (2 pf_wd + u, pf_wd) -- (0, pf_wd) -- cycle; clip base to (pf_wd, 0) -- (pf_wd + t, 0) -- (2 pf_wd + t, pf_wd) -- (0, pf_wd) -- cycle; % arrange the pieces around path P image( draw base rotated 180 shifted point 1 of P shifted (+pf_wd, 0); draw base rotated 0 shifted point 3 of P shifted (-pf_wd, 0); draw side rotated 90 shifted point 0 of P shifted (0, -pf_wd); draw side rotated 270 shifted point 2 of P shifted (0, +pf_wd); ) enddef; \end{smallcode} \vss}} \noindent This macro also needs some colours: \begin{smallcode} color gold, dark, grey; gold = 1/256(243, 197, 127); dark = 1/256(144, 87, 50); grey = 1/256(156, 147, 138); \end{smallcode} a picture of a small silvery-gold ball: \begin{smallcode} picture ball; ball = image(for i=0 upto 16: fill interpath(i/16, fullcircle scaled 10, fullcircle scaled 3 shifted (-2, 2) ) withcolor (i/16)[gold, 15/16 white]; endfor) scaled 1/4; \end{smallcode} and an internal variable that defines the width of the frame: \begin{smallcode} newinternal pf_wd; pf_wd := 21; \end{smallcode} The macro takes a rectangular path $P$ as an argument, and makes a thin rectangle $f$ that is scaled to the desired width and the longer of the two sides of the path. This thin rectangle is then decorated with background colour, strips of colour to suggest depth, a random spatter-pattern, and a row of little balls. The macro then makes two trapezium shaped copies of the decorated rectangle, pieces them together around $P$, and returns the result as a \. \newpage \section{Annotations} \textsc{In some awkward corners}, you may find that you just can't get your label in the right place with \mpl{dotlabel} even if you adjust \mpl{labeloffset}. In these cases there are two simple techniques you can use. First, you could separate drawing the dot from placing the label; given a point $P$ you can try:\mpic{0pt}{callout} \begin{code} drawdot P withpen pencircle scaled dotlabeldiam; label("$P$", P shifted 10 dir 68); \end{code} Using \mpl{dotlabeldiam} ensures that your dots match any others done with \mpl{dotlabel}. Secondly, if that's not enough, use a temporary pair to create a call out line: \begin{code} z0 = P + 20 dir -20; draw z0 -- P cutafter fullcircle scaled 8 shifted P withpen pencircle scaled 1/4; label.rt("\textit{pole}", z0); \end{code} If you want to do this sort of thing often, then it might be worth making a macro. It is hard to write anything completely general, but see §\ref{sec:extimage} for an example. \medskip\noindent \textsc{You might also want} to mark a straight line between two points. \vadjust{\moveright5.3in\vbox to 0pt{\hsize 4.2in \begin{smallcode} vardef do_brace(expr a,b,m,r) = save d, e, n, bb; numeric d, n; pair e; path bb; n = 1/2 m; d = angle (b-a); e = up scaled m rotated d shifted r[a,b]; bb = ((origin {0,n} .. {right} (abs n,n)) rotated d shifted a -- ((-abs n,-n){right} .. {0,n} origin {0,-n} .. {right}(abs n,-n)) rotated d shifted e -- ((-abs n,n){right} .. {0,-n} origin) rotated d shifted b ) shifted (up scaled n rotated d); draw bb withpen pencircle yscaled .6 xscaled .1666 rotated d; point 3 of bb enddef; label.lrt("Here",do_brace(z1, z2, -12, 3/4)); \end{smallcode} Note that, as well as drawing the braces, the macro uses the grouping provided by \mpl{vardef} to return the mid point so that you can put a label next to it. \vss}} The simplest way to do this is just to use \mpl{drawdblarrow} on a copy of your straight path shifted to one side, like so: \begin{code} drawdblarrow (z1--z2) shifted (12 up rotated angle (z2-z1)); \end{code} If you combine this with temporarily setting \mpl{ahangle:=180}, you get the simple dimension line shown in blue. $$\includegraphics{braces}$$ The red braces are a more complex variation on this theme $\longrightarrow$ \newpage \section{Line caps and line joins} The PostScript language defines parameters that affect how the ends of each line are drawn and how lines are joined together. Plain \MP\ provides access to these parameters through internal variables called "linecap" and "linejoin"; it sets both of them to the value "rounded" at the start of each job. \mpic{0pt}{line-caps-and-joins} The figure on the right shows the affect of the different settings, using an exaggerated line width of 2 points (instead of the usual 0.5 points). Some observations to note: \begin{itemize} \item When $\id{linecap}=\id{squared}$ then \kw{drawdot} produces diamond-shaped dots, even when you are drawing with the default circular pen. \item When $\id{linecap}=\id{butt}$ then \kw{drawdot} produces invisible dots. They still count towards the bounding box of the picture but there's no mark on the page. \item When $\id{linecap}=\id{squared}$ then \kw{drawarrow} produces some unpleasant results; even when $\id{linejoin}=\id{mitered}$, you can still see small jaggies on the slopes of the arrows. \item The arrows are nice and sharp when $\id{linejoin}=\id{mitered}$, but they over shoot the mark slightly. \item If you zoom in, you can see the effect of $\id{linejoin}$ on the corners of the grey box as well as on the arrow heads, but you might not notice the difference when the picture is printed unless you have a very high resolution printer. \item This drawing was done with \mpl{pencircle scaled 2}, so that the dots would be easy to see. This does make the arrows drawn with the default line modes (rounded caps and rounded joins) looks a bit fat; they look better with the usual \mpl{pencircle scaled .5}. \end{itemize} There is one more PostScript parameter affecting line joins. \MP\ makes it available as "miterlimit" and it affects how much a mitered join is allowed to stick out at each corner. Plain \MP\ sets "miterlimit=10;" which is correct for nearly all drawings. If you set "miterlimit:=0;" then the mitered line join mode becomes more or less the same as the beveled mode. \newpage \section{Plotting functions}\label{func} \textsc{A selection} of graphs of mathematical functions is presented in this section, taken from real examples collected over several years. For data visualizations, see §\ref{dviz}. As ever in this document, the focus is on plain \MP; the plain format provides no built-in facilities for graphs so you have to do everything from scratch; but on the other hand there are no new macros or commands to learn, you get full control of what goes on the page, and you will not spend hours scratching your head wondering how to adjust the axis labels. \subsection{Making axes} You can start by drawing a simple set of axes.\mpic{-124pt}{plain-axes} \begin{smallcode} path xx, yy; xx = (left -- right) scaled 130; yy = (down -- up) scaled 80; drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); \end{smallcode} Here the axes are scaled arbitrarily to 130\,pt and 80\,pt, but you will probably find it useful to set consistent units, and express sizes in terms of them. Purely from habit, I use $u$ for the horizontal unit and $v$ for the vertical unit. This makes it more convenient when you want to add a grid and/or a number scale.\mpic{-16pt}{numbered-axes} \vskip -12pt \vbox to 0pt{ \begin{smallcode} numeric u, v; u = 40; v = 29; path xx, yy; xx = (3/2 left -- 5 right) scaled u; yy = (3/2 down -- 4 up) scaled v; for x=-1, 1, 2, 3, 4: draw yy shifted (x * u, 0) withcolor 7/8; % grid draw (down--up) shifted (x * u, 0); % ticks label("$" & decimal x & "$", (x * u, -8)); endfor for y=-1, 1, 2, 3: draw xx shifted (0, y * v) withcolor 7/8; % grid draw (left--right) shifted (0, y * v); % ticks label("$" & decimal y & "$", (-10, y * v)); endfor drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); \end{smallcode}\vss} \newpage \subsection{Drawing linear functions} \textsc{For simple} linear graphs, you just need to define two points and draw a line between them; it is tempting to try to make some generalized macro to do this, but it is hard to make something completely general, so for most graphs it is easier just to specify two points and use \mpl{draw}; often it is handy to making your line longer than you need, then trim it using \mpl{cutbefore} and/or \mpl{cutafter} so that it fits neatly. \vadjust{\moveright 384pt\vbox to 0pt{\hsize 4in\vskip -100pt\begin{smallcode} numeric u, m, m', b, b'; u = 1.44cm; b = 3.6u; b' = b + 1/2 u; m = -1; m' = 3/4 m; path xx, yy; xx = (left -- 5 right) scaled u; yy = xx rotated 90; numeric minx, maxx; path ff, gg; minx = xpart point 1/16 of xx; maxx = xpart point 15/16 of xx; ff = (minx, minx * m + b) -- (maxx, maxx * m + b); gg = (minx, minx * m' + b') -- (maxx, maxx * m' + b'); z0 = point 0.4 of ff; z1 = point 0.54 of ff; z1 0 = whatever [point 0 of gg, point 1 of gg]; x1 0 = x0; z1 1 = whatever [point 0 of gg, point 1 of gg]; x1 1 = x1; forsuffixes @=0, 1: draw (x@, 0) -- z@ -- (0, y@) dashed evenly scaled 3/4; draw z@ -- z1 @ -- (0, y1 @) dashed withdots scaled 1/2; label.bot("$x_{" & decimal @ & "}$", (x@, 0)); label.lft("$y_{" & decimal @ & "}$", (0, y@)); label.lft("$y'_{" & decimal @ & "}$", (0, y1 @)); endfor draw ff withcolor 2/3 red; draw gg withcolor 3/4 blue; drawarrow xx; drawarrow yy; label.rt("$x$", point 1 of xx); label.top("$y$", point 1 of yy); dotlabel.urt("$b$", (0, b)); dotlabel.urt("$b'$", (0, b')); draw thelabel("slope: $m=" & decimal m & "$", 7 up) rotated angle (1, m) shifted point 2/3 of ff; draw thelabel("slope: $m'=" & decimal m' & "$", 7 up) rotated angle (1, m') shifted point 2/3 of gg; \end{smallcode}\vss}} $$\includegraphics[width=0.84\textwidth]{linear-graph.pdf}$$ But in this example it was easier to calculate them using $y=mx+b$. Note also that spaces are allowed in suffixes, which makes the loop a bit simpler. \newpage In this second example of a linear function, the emphasis of the diagram was on the angles at the $x$-axis made by the two lines, so the lines were defined using \mpl{rotated}, \mpl{shifted}, and \mpl{cutbefore} instead. \vadjust{\moveright 384pt\vbox to 0pt{\hsize 4in\vskip -24pt\begin{smallcode} path ell, tee, arc; ell = (left--right) scaled 10u rotated theta shifted P cutbefore xx; tee = (left--right) scaled 10u rotated psi shifted P cutbefore xx; arc = subpath (1.6, 3.2) of halfcircle rotated -180 shifted 1/2 up scaled 10u shifted P rotatedabout(P, psi); % the rest of the points then follow... Q = ell intersectionpoint subpath (1.5, 3) of arc; H = P + whatever * dir psi; xpart H = xpart Q = xpart M; ypart M = ypart N = 0; xpart N = xpart P; L = point 0 of ell; T = point 0 of tee; % now get on with the drawing draw arc dashed withdots scaled 1/4 withcolor 1/2 red; draw P--N dashed withdots scaled 1/2; draw Q--M dashed withdots scaled 1/2; drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); drawoptions(withcolor 2/3 blue); draw fullcircle scaled 32 shifted T cutafter tee; draw fullcircle scaled 28 shifted L cutafter ell; label("$\psi$", 24 right rotated 1/2 psi shifted T); label("$\theta$", 20 right rotated 1/2 theta shifted L); drawoptions(); % trim the function lines neatly path boundary; z1 = point .95 of xx; z2 = point .95 of yy; boundary = z1--(x1,y2)--z2; draw ell cutafter boundary; draw tee cutafter boundary; % and finally label the points. label.bot("$T$", T); label.bot("$L$", L); label.bot("$N$", N); label.bot("$M$", M); dotlabel.ulft("$P$", P); dotlabel.lrt("$Q$", Q); dotlabel.lrt("$H$", H); \end{smallcode}\vss}} $$\includegraphics[width=\textwidth]{angles-lines.pdf}$$ The lines are both trimmed to a convenient path (\id{boundary}) when they are drawn.\vadjust{\moveright296pt\vbox to 0pt{\vskip 80pt\begin{mplibcode}beginfig(0);drawarrow origin {right} .. {dir 70} 42 dir 60; label.lft("\small \dots continues", origin); endfig;\end{mplibcode}\vss}} \begin{smallcode} numeric u; u = 1cm; path xx, yy; xx = (2 left -- 10 right) scaled u; yy = (down -- 7 up) scaled u; numeric theta, psi; psi = 28; theta = 50; pair P, Q, H, N, M, T, L; P = (4u, 3u); \end{smallcode} \newpage \subsection{Making curves for functions with a loop} \textsc{To plot a function} you can construct a suitable path using an in-line \kw{for} loop like this: \begin{code} vardef f(expr x) = x ** 2 enddef; path ff; ff = (for x = minx step s until maxx - s: (x, f(x)) .. endfor (maxx, f(maxx))) xscaled u yscaled v; \end{code} provided you have first defined variables \id{minx} and \id{maxx} to represent the domain of $x$, and worked out appropriate values for horizontal and vertical units, $u$, and $v$ so that the range of $f(x)$ fits neatly on your graph. The loop above also uses a variable $s$ to control the number of points used to define the path.\mwpic{-180pt}{func-powers} The figures on the right show that over the domain $-3$ to $3$ a step of $\frac12$ gives enough points for \MP's Bezier curve fitting routines to draw the functions $x^2$ and $x^3$ accurately, but that you need a step size of $\frac18$, and hence four times as many points, for $x^6$ and $x^7$. On modern machines it does not really hurt to calculate dozens of points, but a step size that generates 1000s of points will be slow to compile. \bigskip\noindent There are two other techniques to improve the shape of the curve produced by these loops: you can increase the tension between each point by using \mpl{...} or \mpl{--} instead of \mpl{..} in the loop; and if you know how to differentiate your function, you can add a direction at each step using the $\{\\}$ syntax: \begin{code} vardef f(expr x) = x ** 2 enddef; vardef fp(expr x) = 2x enddef; % NB "fp" because "f'" is illegal path ff; ff = (for x = minx step s until maxx - s: (x, f(x)){1, fp(x)} .. endfor (maxx, f(maxx))) xscaled u yscaled v; \end{code} \vfill \noindent \hey However in general it is simpler just to increase the number of samples by making a smaller step size. \newpage \subsection{Making curves for functions from path pieces}\label{sec:pathpieces} \textsc{In some situations}, you might find it easier to stich together various \ pieces to make your curve. This can be especially elegant if there is a symmetry in the path. For example:\mwpic{-48pt}{func-reflection} \begin{code} path ff, negative_ff; ff = (1,1) for x = 3/2 step 1/2 until 6: ... (x, 1/x) endfor; ff := reverse ff reflectedabout(origin, dir 45) & ff; ff := ff scaled 24; negative_ff = ff reflectedabout(origin, dir -45); draw ff withcolor 2/3 red; draw negative_ff withcolor 2/3 red; \end{code} \smallskip\centerline{\small (Omitting code for the axes, the grid, and the dots at each \mpl{point} of the paths).} \smallskip \noindent \begin{itemize} \item Notice that you can update the path using the assignment operator “\mpl{:=}”. \item You need to \mpl{reverse} the reflected portion so that the two ends coincide. \item The two path segments are spliced together with \mpl{&}. You could use a path join like \mpl{..} instead, but then the joined path would have an extra \mpl{point} at \mpl{(1,1)}. \item Notice also how the vertical part has the same equal spacing of points as the more horizontal part. \end{itemize} Reflection of a function in the line at 45° gives the inverse of the function, which is especially useful for $y=1/x$, but it applies to functions generally. So if you want to plot $y=\sqrt x$ it may be easier to define a path for $y=x^2$ and then reflect it. This is particularly useful if you want to plot, say, $y=\sqrt[3]x$, over a domain that includes negative numbers, because \MP\ will not calculate reciprocal powers of negative numbers.\mwpic{-60pt}{func-cuberoot} The curve in this chart was created by reflecting the line $y=x^3$. \newpage \subsubsection{Exponential and logarithm functions by reflection} \textsc{A further example} of creating paths by transformation.\mpic{-36pt}{func-exponential} \begin{smallcode} numeric u; u = 42; path xx, yy; xx = (-3u, 0) -- (5u, 0); yy = xx rotated 90; path ee, ll, nn; numeric minx, maxx, s; minx = -3; maxx = 1/256 mlog(4.5); s = 1/4; ee = (for x = minx step s until maxx - s: (x, mexp(256x)){1, mexp(256x)} ... endfor (maxx, mexp(256 maxx)){1, mexp(256 maxx)}) scaled u; ll = ee reflectedabout(origin, dir 45); nn = (for x=1 step s until 4-s: (x, 1/x) ... endfor (4, 1/4)) scaled u; nn := reverse nn reflectedabout(origin, dir 45) & nn; draw unitsquare xscaled mexp(256) scaled u withcolor 7/8; draw unitsquare yscaled mexp(256) scaled u withcolor 7/8; path T[]; numeric p; p = directiontime dir 45 of ee; T1 = (precontrol p of ee -- postcontrol p of ee) shifted - point p of ee scaled 1/2 u shifted point p of ee; T2 = (precontrol p of ll -- postcontrol p of ll) shifted - point p of ll scaled 1/2 u shifted point p of ll; drawoptions(withpen pencircle scaled 1/4 withcolor 1/2); draw T1; draw T2; draw interpath(1/2, T1, T2) dashed evenly; drawoptions(); draw nn; label.urt("$1/x$", point 0 of nn); draw ee withcolor 2/3 blue; label.top("$e^x$", point infinity of ee); draw ll withcolor 3/4 red; label.top("$\ln(x)$", point infinity of ll); drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); dotlabel.lft("$e$", (0, mexp(256) * u)); dotlabel.bot("$e$", (mexp(256) * u, 0)); dotlabel.ulft("$1$", (0, u)); dotlabel.lrt("$1$", (u, 0)); \end{smallcode} \moveright6in\vbox to 0pt{\vss\noindent If you prefer more ‘normal’ functions, you can define: \begin{smallcode} vardef exp(expr x) = mexp(256x) enddef; vardef log(expr x) = 1/256 mlog(x) enddef; \end{smallcode}} \newpage \subsection{Functions using trigonometric functions} \textsc{As noted} in §\ref{trig}, \MP’s built-in trigonometric functions work in degrees, this example shows how you might use them in a graph.% \vadjust{\moveright5in\vbox to 0pt{\vskip-24pt\begin{code} numeric u, pi; u = 50; pi = 3.141592653589793; path xx, yy; xx = (3.5 left -- 3.6 right) scaled u; yy = (1.1 down -- 1.2 up) scaled u; path ss; ss = origin for t=1 upto 360: -- (t, sind(t)) endfor; ss := ss shifted 360 left & ss; ss := ss xscaled (pi/180) scaled u; draw ss cutbefore yy shifted point 0 of xx cutafter yy shifted point 1 of xx withcolor 3/4 blue; draw ss shifted (-1/2 pi * u ,0) cutbefore yy shifted point 0 of xx cutafter yy shifted point 1 of xx withcolor 2/3 red; drawoptions(dashed withdots scaled 1/4); draw ((1/4 pi, 0) .. (1/4 pi, sind(45))) scaled u; draw ((1/2 pi, 0) .. (1/2 pi, sind(90))) scaled u; draw ((3/4 pi, 0) .. (3/4 pi, sind(135))) scaled u; drawoptions(); drawarrow xx; label.rt("$t$", point 1 of xx); drawarrow yy; label.top("$u(t)$", point 1 of yy); for i=-4, -3, -2, -1, 1, 2, 3, 4: draw (down--up) scaled 2 shifted (pi * i/4 * u, 0); label.bot(pi_quarters(i), (pi * i/4 * u, -2)); endfor \end{code}\vss}} $$\includegraphics[width=\textwidth]{func-sines}$$ For this diagram, the sine wave path ("ss", shown in \blue{blue}) needs to have two complete cycles, so it is constructed in stages. First the section from the origin to $2\pi$ is created in a loop; with 360 steps, you can use \mpl{--} and still get a smooth path. Secondly the cycle is duplicated by splicing itself to a shifted copy. Thirdly it is $x$-scaled to radians, and then scaled in both directions to the chosen unit size, and drawn chopped off to the width of the $x$-axis. The cosine path is the same path, shifted $\frac12\pi$ left, drawn in \red{red}, and chopped off to fit the same width. The fancy fraction labels were produced with this subroutine: \begin{smallcode} vardef pi_quarters(expr n) = save s, f, q; string s, f; numeric q; s = if n < 0: "-" else: "" fi; q = abs(n); if q mod 4 = 0: f = if q > 4: decimal 1/4 q else: "" fi; elseif q mod 2 = 0: f = "\frac{" & decimal 1/2 q & "}{2}"; else: f = "\frac{" & decimal q & "}{4}"; fi "$\scriptstyle" & s & f & "\pi$" enddef; \end{smallcode} \newpage \subsection{Manipulating functions} \textsc{This second example} with trigonometric functions shows one way to add two functions, by combining the \MP\ paths themselves.% \vadjust{\moveright5in\vbox to 0pt{\vskip-24pt\begin{code} numeric u, pi; u = 50; pi = 3.141592653589793; path xx, yy; xx = (3.5 left -- 4 right) scaled u; yy = (1.2 down -- 1.3 up) scaled u; path ss, tt, uu; ss = origin for x=1 upto 360: -- (x, sind(x)) endfor; tt = origin for x=1 upto 360: -- (x, 1/2 sind(3x)) endfor; uu = origin for x=1 upto 360: -- (x, ypart point x of ss + ypart point x of tt) endfor; forsuffixes $=ss, tt, uu: $ := $ shifted 360 left & $; $ := $ xscaled (pi/180) scaled u; $ := $ cutbefore yy shifted point 0 of xx cutafter yy shifted point 1 of xx; endfor draw ss withcolor 1/2[blue, white]; draw tt withcolor 1/2[red, white]; draw uu withcolor 1/4 green; label.top("$f(x)=sin(x)$", point 290 of ss); label.bot("$g(x)=\frac12 sin(3x)$", point 295 of tt); label.urt("$f(x) + g(x)$", point 350 of uu); drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); for i=-6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7: draw (down--up) scaled 2 shifted (pi * i/6 * u, 0); label.bot(pi_sixths(i), (pi * i/6 * u, -2)); endfor \end{code}\vss}} $$\includegraphics[width=\textwidth]{func-addition-of-sines}$$ Notice how the same extension, scaling, and trimming operations can be applied to all three paths using a \mpl{forsuffixes} loop. Note that you can use any regular variable name for the loop index; you don't have to use \mpl{$}, but like \mpl{@} it is a valid variable name in \MP, and it looks a bit like a placeholder marker in other languages. Note that you need to start with the first point of the path outside the loop so that you don't end up with a dangling \mpl{--} path connector. Using \mpl{origin} is just a short cut for writing \mpl{(0, sind(0))}. If you were plotting a different function this would not work. For example, \mpl{(0, cosd(0))} is \mpl{(0,1)}. \bigskip\noindent \hey The missing \mpl{pi_sixths} macro is left as an exercise for the reader. Hint: you can adapt the \mpl{pi_quarters} on the previous page, allowing for halves, thirds, and sixths instead of halves and quarters. \newpage \subsection{Focus on a specific region of a function} \textsc{This visual proof} required a large $y$-axis scale.\mwpic{-24pt}{func-epi-v-pie} The axes are separated to show the discontinuity in scales, and that the origin is not on the chart.\enlargethispage\baselineskip \begin{smallcode}[xleftmargin=0pt] numeric minx, maxx, s, u, v; minx = 13/8; s = 1/16; maxx = 19/4; u = 89; v = 3072; def f(expr x) = 1/256 mlog(x) / x enddef; path ff, xx, yy; ff = for x=minx step s until maxx-s: (x, f(x)) .. endfor (maxx, f(maxx)); ff := ff xscaled u yscaled v; xx = origin -- right scaled (maxx-minx) scaled u; yy = origin -- up scaled 0.09v; xx := xx shifted point 0 of ff shifted 20 down; yy := yy shifted point 0 of ff shifted 20 left; numeric pi, e, fpi, fe; pi = 3.141592653589793 u; fpi = f(3.141592653589793) * v; e = 2.718281828459045 u; fe = f(2.718281828459045) * v; path ee, pp; ee = (e, ypart point 0 of xx) -- (e, fe) -- (xpart point 0 of yy, fe); pp = (pi, ypart point 0 of xx) -- (pi, fpi) -- (xpart point 0 of yy, fpi); draw ee dashed withdots scaled 1/4 withcolor 2/3 red; draw pp dashed withdots scaled 1/2 withcolor 2/3 red; draw ff withcolor 3/4 blue; drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); for x=2 upto 4: draw (down--up) scaled 2 shifted (x * u, ypart point 0 of xx); label.bot("$" & decimal x & "$", (x * u, ypart point 0 of xx - 2)); endfor for y=31 upto 38: draw (left--right) scaled 2 shifted (xpart point 0 of yy, y/100*v); endfor for y=32, 35, 38: label.lft("$" & decimal (y/100) & "$", (xpart point 0 of yy-2, y/100*v)); endfor \end{smallcode} \moveright384pt\vbox to 0pt{\vss\hsize 4in\begin{smallcode} drawoptions(withcolor 1/2 red); label.bot("$e$", point 0 of ee shifted 4 down); label.lft("$1/e$", point 2 of ee shifted 2 left); label.bot("$\pi$", point 0 of pp shifted 4 down); label.lft("$\ln\pi/\pi$", point 2 of pp shifted 2 left); drawoptions(withcolor 2/3 blue); label.urt("$\displaystyle y={\ln x\over x}$", point 42 of ff); drawoptions(); label("\dots\ hence\enspace $e^\pi > \pi^e$.", (4u, 0.38v)); \end{smallcode}} \newpage \subsection{Approximate function diagrams} \textsc{Sometimes} you may need to plot a function that does not have a simple mathematical definition. You can use \MP’s normal path definitions to make a likely looking approximation.\mwpic{-48pt}{func-stress} \begin{smallcode}[xleftmargin=0pt, xrightmargin=-140pt] z1 = 377 right; z2 = 233 up; path ff; ff = origin .. (72, 144){1,2} .. (84, 144) .. (96, 144){1,1} .. (220, 220){right} .. (370, 160){2,-1.3}; for t=2, 4, 4.9: draw point t of ff -- (xpart point t of ff, y2 + 6) dashed evenly scaled 1/2; endfor label.top("Strain hardening", (1/2 (xpart point 2 of ff + xpart point 4 of ff), y2)); label.top("Necking", (1/2 (xpart point 4 of ff + xpart point 4.9 of ff), y2)); path rr; rr = point 0.4 of ff -- (xpart point 0.8 of ff, ypart point 0.4 of ff) -- point 0.8 of ff; draw rr; label.bot("Run", point 1/2 of rr); label.rt("Rise", point 3/2 of rr); vardef pin_label@#(expr p, a, b)= draw a -- b cutbefore fullcircle scaled 8 shifted a withpen pencircle scaled 1/4 withcolor 1/2 white; label@#(p, b); enddef; pin_label.lrt("Yield strength", point 1.2 of ff, point 2 of ff + (8, -18)); pin_label.bot("Ultimate strength", point 4 of ff, point 4 of ff + (4, -24)); pin_label.bot("Fracture", point 5 of ff, point 5 of ff + (-8, -18)); draw ff withpen pencircle scaled 1 withcolor 2/3 blue; clip currentpicture to unitsquare scaled 400; % clip thick pen at origin drawdblarrow z1 -- origin -- z2; label.ulft("Strain, $\epsilon$", z1); label.urt("Stress, $\sigma$", z2); label("$\displaystyle\hbox{Young's modulus} = \hbox{Slope} = {\hbox{Rise}\over\hbox{Run}}$", 1/2 z1 shifted 36 up) withcolor 2/3 blue; \end{smallcode} \newpage \subsubsection{Taming Bezier paths with controls} \textsc{It takes some} practice to translate a sketch of a curve into a smooth path. Plain \MP\ inherits from \MF\ a useful \id{flex} macro, that takes a list of \s (any number of them) and produces a pleasing path through them. As Knuth says in the \mfbook: “The idea is to specify two endpoints, $z_1$ and $z_n$, together with one or more intermediate points where the path is traveling in the same direction as the straight line from $z_1$ to~$z_n$; these intermediate points are easy to see on a typical curve, so they are natural candidates for key points.” For example: \begin{code} draw flex(z1,z2,z3) & flex(z3,z4,z5) flex(z5,z6,z7) & flex(z7,z8,z9,z1) & cycle; \end{code} (with appropriate definitions of the points), produces this: \lower 12pt\hbox{\smash{\begin{mplibcode} beginfig(0); z1=(0,509); z2=(-14,492); z3=(-32,481); z4=(-42,455); z5=(-62,430); z6=(-20,450); z7=(42,448); z8=(38,465); z9=(4,493); draw flex(z1,z2,z3) & flex(z3,z4,z5) & flex(z5,z6,z7) & flex(z7,z8,z9,z1) & cycle; for i=1 upto 9: draw z[i] withpen pencircle scaled 2 withcolor red; endfor currentpicture := currentpicture scaled 0.7071 rotatedabout(z3, -20); endfig; \end{mplibcode}}} \bigskip\noindent \textsc{Another approach} is just to define the end-points and some control points, and then define a path that is shaped by the control points but does not actually go through them. Consider this program:\mwpic{-20pt}{func-pulse} \begin{code} vardef pulse(expr w, h, d) = for i=0 upto 4: x[i] = w/4 * i; endfor y0 = y1 = 0; y3 = y4 = d; y2 = h; z0 .. 1/2[z0, z1] .. controls z1 .. 1/2[z1, z2] .. controls z2 .. 1/2[z2, z3] .. controls z3 .. 1/2[z3, z4] .. z4 enddef; draw pulse(300, 100, -40); \end{code} This produces the smooth blue line shown on the right. A second copy of the line is shown below, decorated with the three control points $z_1$, $z_2$, and $z_3$ in red, and showing the six points of the path as small black circles. You can tweak this curve by adjusting the controls left or right, or changing the mediation parameters so that the points on the path are closer to one control point than the other. \newpage \subsection{Parametric plots} \textsc{If you want to plot} one function against another, then you can make each coordinate a function of an independent variable. All functions can be converted, trivially, to this form: \begin{code} vardef f(expr x) = x enddef; vardef g(expr x) = sind(x) enddef; % or whatever function ... path ff; ff = for t = mint step s until maxt - s: (f(t), g(t)) .. endfor (f(maxt), g(maxt)); \end{code} But you can make more complicated curves, for example curves that can have more than one value for $y$ for a given $x$, if you change $f(x)$ and $g(x)$ appropriately. The first example\mwpic{-24pt}{func-lemniscate} shows the lemniscate of Bernoulli and was drawn like this: \begin{smallcode} numeric a, c; c = 128; a = sqrt(2) * c; vardef f(expr x) = a * cosd(x) / (1 + sind(x) ** 2) enddef; vardef g(expr x) = f(x) * sind(x) enddef; numeric mint, maxt, s; mint = 0; s = 30; maxt = 360; path p; p = for t = mint step s until maxt - s: (f(t), g(t)) ... endfor cycle; draw p withcolor 3/4 blue; path xx, yy; xx = (left -- right) scaled 200; yy = (down -- up) scaled 64; drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); dotlabel.bot("$F_1$", c * left); dotlabel.bot("$F_2$", c * right); \end{smallcode} Although sometimes, especially when you know the domain is 0° to 360° and that the path is cyclic, it is simpler to write the two expressions directly in the loop:\mwpic{-108pt}{func-parametric} \begin{smallcode} path p; p = for t = 0 upto 360: (144 cosd(3t), 89 sind(2t)) ... endfor cycle; draw p withcolor 2/3 red; \end{smallcode} which produces this Lissajous curve $\longrightarrow$ \newpage \subsubsection{Parametric plots with polar coordinates: Maurer roses} \textsc{Instead of} defining separate functions for the $x$ and $y$ coordinates in a parametric plot, it is sometimes convenient to use \MP’s polar coordinate notation (discussed in §\ref{polar}). The family of “rose” plots, based on $r=\cos(n\theta)$, is easy to do in this way. Here is a Maurer rose, based on $r=\cos(2\theta)$ and connecting every 29th point on the curve.\mpic{-24pt}{func-maurer-rose} \begin{code} numeric n; n = 2; path r; r = (for t=0 upto 360: cosd(n * t) * dir t ... endfor cycle) scaled 150; numeric d; d = 29; path k; k = for t = 0 upto 360: point d * t mod 360 of r -- endfor cycle; draw k dashed withdots scaled 1/8 withpen pencircle scaled 1/4 withcolor 1/2[blue, white]; draw r withcolor 2/3 red; path xx, yy; % you might not need the axes... xx = (left -- right) scaled 160; yy = (down -- up) scaled 160; drawarrow xx; label.rt("$x$", point 1 of xx); drawarrow yy; label.top("$y$", point 1 of yy); \end{code} Different values of $n$ and $d$ give an endless variety of patterns. But note that if your choice of $d$ exceeds $2^{15}/360 \simeq 91$ you will need to use "-numbersystem=double" to avoid arithmetic overflow. \newpage \section{Drawing plane curves} {\textsc{“Plane curves offer} a rich \dots\ field of study which may be approached from a quite elementary level. Anyone who can draw a circle with a given centre and a given radius can draw a cardioid or a limaçon. Anyone who can use a set square can draw a parabola or a strophoid” \hfill — \textsl{A Book of Curves}, E.\@ H.\@ Lockwood\parfillskip0pt\par} \subsection{Parabola} \textsc{The simplest way} to get a parabola curve is to plot $y=x^2$ over $-1 \le x \le 1$ and then transform as required (see next page), but it can be illuminating to follow more traditional constructions, such as that shown on the right.\mwpic{-180pt}{curves-parabola} \vadjust{\moveright7.2in\vbox to 0pt{\hsize 200pt\noindent The idea here is that you put the right angle of your set square on the vertical axis with the short side touching $S$, and then draw the long side. If you do this in enough places, the edges form a parabola. In the \MP\ code here, the intersection of each ray with the one before is captured as variable $t$ and then added one at a time to the \ \id{parabola}, (using a neat trick at the beginning). \vss}} \begin{smallcode}[xleftmargin=0pt] pair A, S; A = origin; S = 66 right; path parabola, last; for q = -144 step 8 until 144: pair Q; Q = (0, q); path ray; ray = (origin -- unitvector(S - Q)) scaled 300 rotated if q < 0: - fi 90 shifted Q; draw S -- ray withcolor 7/8; if known last: pair t; t = whatever[point 0 of ray, point 1 of ray] = whatever[point 0 of last, point 1 of last]; parabola := if known parabola: parabola .. fi t; fi last := ray; endfor draw parabola withcolor 3/4[red, white]; for t=0 upto length parabola: draw point t of parabola withpen pencircle scaled 3/2 withcolor red; endfor draw (up--down) scaled 300; dotlabel.lft("$A$", A); dotlabel.rt("$S$", S); \end{smallcode} \newpage \subsubsection{Parabola from directrix and focus} \textsc{The classical definition} of the parabola is the locus of points that are equidistant from a given line (the \textit{directrix}, shown as $A\to B$ on the right) to a given focus point (shown as $S$).\mpic{-24pt}{curves-parabola-directrix} Each point on the parabola path is related to each point, and you can construct an equilateral parallelogram at each point as shown. This leads to a macro that generates a parabola given two \ variables to define the directrix and another to define the focus: \begin{code} vardef parabola(expr A, B, S) = save m, q, n, parabola; pair n; % n = nearest point to S on A--B n = whatever[A, B]; n - S = whatever * (A-B) rotated 90; path parabola; for t=0 step 1/64 until 1: pair m, q; m = 1/2[S, t[A, B]]; q = whatever[S, n]; q - m = whatever * (S - m) rotated 90; parabola := if known parabola: parabola -- fi q reflectedabout(S, m); endfor parabola enddef; \end{code} \subsubsection{Parabola from $y=x^2$ and $dy/dx=2x$} Alternatively you could define a “unit parabola” like this: \begin{code} path ff; ff = (-1, 1){1, -2} .. (-1/2, 1/4){1, -1} .. (0, 0){right} .. (1/2, 1/4){1, 1} .. (1, 1){1, 2}; \end{code} and then — using the points defined above, where $o$ is the mid-point of $n\to S$ — scale it and place it like this: \begin{code} draw ff scaled 4 abs(S-o) rotated angle (B-A) shifted o; \end{code} \newpage \subsection{Hyperbola} \textsc{The traditional construction} for the hyperbola is identical to the construction for the parabola given above, except that the base line is a circle rather than a straight line.\mwpic{-48pt}{curves-hyperbola-construction} As a result, the shape of the curve changes depending on the radius of the base circle, unlike the parabola. The curve is bounded by the two asymptotes, which are the lines from the centre of the circle $O$ through the tangent points from the focus $S$. When the ratio of $OS/OA = \sqrt2$, the asymptotes are at right angles. You can also draw the hyperbola as the function $y=1/x$ (as shown in §\ref{sec:pathpieces}), which can be transformed to any desired shape. The untransformed function is shown on the bottom left, with the focus $S$ at the point $(\sqrt2, \sqrt2)$. If the desired angle between the asymptotes is $2\alpha$, the transformation can be created like this: \begin{code} numeric alpha; alpha = 34; transform t; origin transformed t = origin; right transformed t = dir -alpha; up transformed t = dir alpha; \end{code} This can be applied to the hyperbola curve itself and to the axes. But the focus will remain at the same distance from the origin, as shown below right. $$\includegraphics[width=0.9\textwidth]{curves-hyperbola-function}$$ \newpage \subsection{Ellipse} \textsc{You can draw an ellipse} in \MP\ by scaling the standard \mpl{fullcircle} path by a different amount in each direction. By convention, the $y$-axis is the minor axis of an ellipse.\mwpic{-24pt}{curves-ellipse} The ellipse shown on the right, was defined like this: \begin{code} path ellipse; ellipse = fullcircle scaled 320 yscaled 5/8 rotated 13; \end{code} Then the lengths of the semi-major axes, $a$ and $b$, were extracted like this: \begin{code} numeric a, b; 2a = abs (point 4 of ellipse - point 0 of ellipse); 2b = abs (point 6 of ellipse - point 2 of ellipse); \end{code} If you already had $a$ and $b$, then you could use them directly to scale your ellipse; the following snippet would produce the same elliptical path: \begin{code} numeric a, b; a = 160; b = 100; path ellipse; ellipse = fullcircle xscaled 2a yscaled 2b rotated 13; \end{code} \bigskip\noindent The “eccentricity”, $e$, of the ellipse is the ratio between the distance from the centre to each focus and the semi-major axis, $a$. By definition, the distance from $F_1$ to $T$ to $F_2$ is constant as $T$ moves round the ellipse and is equal to $2a$. Hence when $T$ lies on the minor axis, you have $TF_1=a$, and so $a^2 = b^2 + a^2e^2$, and $e^2=1-b^2/a^2$: \begin{code} numeric e; e = 1 +-+ b/a; % the Pythagorean difference operator \end{code} The focus points can then be found like this: \begin{code} z0 = 1/2[point 0 of ellipse, point 4 of ellipse]; z1 = e[z0, point 0 of ellipse]; z2 = e[z0, point 4 of ellipse]; \end{code} \vfill \moveright 384pt\vbox to 0pt{\vss The tangent and the normal at $T$ were added like this: \begin{code} numeric t; t = 1.732; draw (left--right) scaled 21 rotated angle direction t of ellipse shifted point t of ellipse; draw (1/2 down--up) scaled 21 rotated angle direction t of ellipse shifted point t of ellipse; \end{code}} \newpage \subsubsection{Tangent from external point to ellipse} $$\includegraphics[width=\textwidth]{curves-ellipse-tangents}$$ To find the tangent points from an external point $A$ to an ellipse, the classical construction is to draw an arc centred at $A$ through one focus point, then draw a second arc centred at the other focus with radius $2a$. The intersection points, $P$ and $Q$, of these two arcs are the images of the first focus point in the required tangents (because $F_2TF_1=2a$ by definition, and $F_2P=2a$ by construction), and so the tangent points $T$ and $T'$ are the intersections of $F_2P$ and $F_2Q$ with the ellipse. \vfill\noindent There is no such direct construction for the nearest point on an ellipse to a given point, but you can use the macro \id{solve} to find it numerically. The blue arrow shows the shortest distance from $A$ to the ellipse. \vadjust{\moveright 384pt\vbox to 0pt{\vss \begin{smallcode} secondarydef a through b = begingroup; save d; numeric d; d = abs(a-b); (1+12/d)[b,a]--(1+12/d)[a,b] endgroup enddef; path ellipse; ellipse = fullcircle scaled 300 yscaled 5/8 rotated 13; z0 = 1/2[point 4 of ellipse, point 0 of ellipse]; numeric a, b, e; 2a = abs (point 4 of ellipse - point 0 of ellipse); 2b = abs (point 6 of ellipse - point 2 of ellipse); e = 1 +-+ b/a; z1 = e[z0, point 0 of ellipse]; z2 = e[z0, point 4 of ellipse]; z3 = 240 dir 25; path pp, qq; pp = fullcircle scaled 2 abs (z1 - z3) shifted z3; qq = fullcircle scaled 4a shifted z2; z4 = pp intersectionpoint qq; z5 = reverse pp intersectionpoint qq; numeric t, u; (t, whatever) = ellipse intersectiontimes (z2 -- z4); (u, whatever) = ellipse intersectiontimes (z2 -- z5); vardef f(expr x) = angle (z3 - point x of ellipse) + 90 > angle direction x of ellipse enddef; drawarrow z3 -- point solve f(0, t) of ellipse withcolor 2/3 blue; drawoptions(dashed evenly withcolor 7/8); draw point 0 of ellipse through point 4 of ellipse; draw point 2 of ellipse through point 6 of ellipse; drawoptions(withcolor 3/4); draw z4 -- z1 -- z5; draw z2 -- z4 -- z3 -- z5 -- cycle; draw point t of ellipse -- z1 -- point u of ellipse; drawoptions(); draw point t of ellipse -- z3 -- point u of ellipse withcolor 2/3 red; dotlabel.llft("$F_1$", z1); dotlabel.llft("$F_2$", z2); dotlabel.urt("$A$", z3); dotlabel.ulft("$P$", z4); dotlabel.lrt ("$Q$", z5); dotlabel.ulft("$T$", point t of ellipse); dotlabel.lrt("$T'$", point u of ellipse); draw ellipse; picture P; P = currentpicture; currentpicture := nullpicture; draw pp dashed withdots scaled 1/2; draw qq dashed withdots scaled 1/2; bboxmargin := 24; clip currentpicture to bbox P; draw P; \end{smallcode} \vskip -48pt}} \newpage \subsection{Cardioid} \textsc{To draw a cardioid by hand}, you can draw a base circle, mark a fixed point $A$ on it, and then draw a circle centred at any point $Q$ on the circle that passes through point $A$. If you then repeat this for many different positions of Q, the cardioid is the curve that encloses all the circles.\mpic{-24pt}{curves-cardioid-simple} But for \MP, you want only a single point $P$ from the circumference of each circle; this turns out to be the image of $A$ reflected in the tangent at each point $Q$, like so: $$\includegraphics[width=0.7\textwidth]{curves-cardioid-construction}$$ \vskip -84pt\noindent With a small step size $s$ and a base circle \id{base}, this suggests: \begin{smallcode} pair A; A = point 0 of base; path cardioid; cardioid = for t = 0 step s until length base: A reflectedabout(precontrol t of base, postcontrol t of base) .. endfor cycle; \end{smallcode} You can also show that $AP=2a(1+\cos\theta)$, where $a$ is the radius of the base circle and $\theta$ is the angle that $AP$ makes with the diameter through $A$, so you might use: \begin{smallcode} cardioid = for t=0 upto 360: 2a * (1+cosd(t)) * dir t .. endfor cycle; \end{smallcode} \newpage \subsection{Limaçon} \textsc{The limaçon can be seen} as a generalization of the cardioid, obtained by moving point $A$ off the base circle. \vadjust{\moveright356pt\vbox to 0pt{\vskip -20pt\noindent \rlap{\includegraphics[scale=0.833]{curves-limacon-simple}}\vss}} Here $A$ has been moved to the left, but each $P$ on the curve is still $A$ reflected in the tangent at each $Q$. The “hole” gets larger as $A$ moves away from the \id{base} circle; when $A$ touches the \id{base} the hole disappears and the curve becomes the cardioid, as before. Following this ruler-and-compasses approach, the red limaçon path in the figure here was generated from the \id{base} circle shown in blue. \begin{smallcode} pair A; A = 2[center base, point 0 of base]; path limacon; limacon = for t = 0 step s until length base: A reflectedabout(precontrol t of base, postcontrol t of base) .. endfor cycle; \end{smallcode} Or if you prefer a more trigonometrical approach: \begin{smallcode} limacon = for t=0 upto 359: 2a*(1+2cosd(t))*dir t .. endfor cycle; \end{smallcode} Here $2a$ is the diameter of the blue \id{base} circle. Note that if you use \mpl{sind}\\ instead of \mpl{cosd} you get the same curve rotated $90^\circ$. \vfill \noindent An alternative approach (due to Albrecht Dürer) is shown below. In this dia- \par\kern 2pt \vbox{\halign{#&\quad\vbox{\hsize=2.4in\noindent #}\cr $$\includegraphics{curves-limacon-durer}$$ &gram the base circle is divided into 12 parts like a clock face. At 1 o’clock, you draw a line segment of a given length parallel to the radius to 2 o’clock; at 2 you draw the same length segment parallel to 4 o’clock, and so on. The limaçon is the curve through the far ends of each segment (plus any intermediate points required). This approach of doubling the angles makes it more obvious that the limaçon goes round twice, as it were. The path was generated like this: \cr}} \smallskip \begin{smallcode} limacon = for t=0 upto length base-1: 42 dir angle point 2t of base shifted point t of base .. endfor cycle; \end{smallcode} \newpage \subsection{Astroid} \textsc{Readers of a certain age} may recall threading strings between pegs on a board to make the astroid. It is the envelope of a line of a given length drawn from $x$-axis to $y$-axis at all possible points.\mpic{-24pt}{curves-astroid} In \MP\ the simplest way to draw the astroid curve (and the “strings”) is to use a base circle and the points $A$ and $B$ at the ends of each line that have the $x$ part and $y$ part of each point $T$ round the base circle. $$\includegraphics[scale=0.8]{curves-astroid-construction}$$ Then the point $P$ on $A \to B$ that is closest to $T$ will lie on the astroid, so you can make the path with: \begin{smallcode} path astroid; astroid = for t=0 step 1/16 until 8: hide(pair a, b, p; a = (xpart point t of base, 0); b = (0, ypart point t of base); p = whatever[a, b]; p-point t of base = whatever * (a-b) rotated 90; ) p -- endfor cycle; \end{smallcode} Note that you need to use “\mpl{--}” so that the cusps stay neatly pointed.\marginpar{\vskip-38pt\small\noindent \llap{\hey\,}The geometry of the subtended angles shows that the length of the arc $T\to S$ equals the length of the arc from $T\to P$ on the quarter-sized circle through $T$ and $M$. So the astroid is also the path of a point on the smaller circle rolling around the inside of the base circle.} \newpage \subsubsection{Astroid and cousins} The geometry of the astroid also allows us to define a simple parametric equation for the point $P$. $$\includegraphics[scale=0.8]{curves-astroid-construction}$$ If the distance $OT = a$, then $OA = BT = a\cos\theta$. But then $BP = BT\,\cos\theta = a\cos^2\theta$, and the $x$-coordinate of $P = BP\,\cos\theta=a\cos^3\theta$. By a similar argument the $y$-coordinate is $a\sin^3\theta$, so the parametric equations for $P = (x, y)$: $$\centerline{$x=a\cos^3\theta$ \quad and \quad $y=a\sin^3\theta$}$$ This is used to make this rather psychedelic family of astroid cousins $\longrightarrow$ \moveright384pt\vbox to 36pt{\vss $$\includegraphics[scale=0.9]{curves-astroid-family}$$ \begin{smallcode} numeric a; a = 144; input colorbrewer-rgb for n=1 upto 7: path p; p = a * right for t=6 step 6 until 90: .. a * (cosd(t) ** n, sind(t) ** n) endfor; p := for i=0 upto 3: p rotated 90i & endfor cycle; fill p withcolor Oranges[9][n]; draw p; endfor \end{smallcode}} \newpage \subsection{Cycloid} \textsc{Cycloids} are the curves made by points on the circumference of a rolling wheel. In the first diagram the cycloid is drawn in red and the corresponding rolling wheel in blue. The main idea in this diagram is to make the whole drawing depend on just a few parameters; here there are two: the radius $r$ and the amount of rotation $θ$. If we make $r$ bigger, the drawing will be scaled up; if we change $θ$, the wheel will appear to have rolled along. \mpic{-66pt}{cycloids} \marginpar{\par\kern1in \begin{itemize} \item Near the beginning we define $\pi=3.14159265$, as there’s no such constant built in, but it makes the source more understandable to write "pi/180" instead of "0.017453". It would be nice to use the Greek letters themselves in the source, but \MP\ only lets you use plain ASCII characters, to you have to write "pi" instead. Later on "t" is used instead of $\theta$. \item The path of the cycloid $c$ is defined using an inline "for" loop. There’s a slight awkwardness to doing this as you have to repeat yourself either at the beginning or the end, because you can’t have a dangling "--" or ".." at the end of the path. With a closed path it’s easier because you can just put "--cycle" after the "endfor". The strange numbers here are because we are going from a rotation of $-100°$ to $+460°$; $360°$ corresponds to one hop of the cycloid. \item The axes are done in the usual way, except that we use "xpart" and the "point .. of .." notation to make the $x$-axis neatly line up with the ends of the cycloid path. \item To label points with dots but no text it’s convenient just to fill a circle scaled to "dotlabeldiam"; this internal parameter is the current size to be used for the dots in "dotlabel". \end{itemize}} \mpexternal[xleftmargin=0pt]{cycloids-code.mp} \noindent You can generalize the picture to make cycloids where the point tracing the cycloid is not on the circumference doing the rolling; the classic example is the wheel of the train with a flange. Here I have added $R$ to define the radius of an outer rim, while the wheel still rolls along a circle of radius $r$. \mpic{-40pt}{cycloids-extra} You might like to experiment with making $R $S$ is defined implicitly. It is sufficient to give equations for three non-collinear points, and \MP\ will work out the rest. In order to do this, you need to know the ratio of $x/a$, but by definition $a/b=b/x$, so $x=b^2/a$, hence $x/a=(b/a)^2$. The code shown sets $r=b/a$, and then uses $r^2$ as the required fraction along $a$. \smallskip\noindent\hey This construction also works for other triangles, but it looks more elegant with an isosceles with base angles of $72^\circ$ as shown. \par} \newpage \section{Eggs}\label{eggs} \textsc{Drawing bird's eggs} excites a curious fascination in some people. This section shows some possible ways to make eggs with \MP. The first few compass-and-ruler constructions are taken from Robert Dixon's \textsl{Mathographics}. They all follow the same basic idea of constructing the egg-shaped path from a series of circular arcs.\mnote{-16pt}{In these \MP\ implementations each egg path has 8 points starting with point 0 at “3 o’clock” like \mpl{fullcircle}.} \subsection{Euclidean egg} The first is made of four circular arcs, defined here as parts of circles $a$, $b$, $c$, \& $d$.\mwpic{0pt}{eggs-moss}\marginpar{\par\kern 3in \begin{itemize} \item "eggs-common.mp" defines the colours, and the \mpl{numbered_points} routine that is used to show the points of the "egg" path. \item Note that it is not necessary that the parts of the arcs touch; in fact it is better to join them with the \mpl{..} connector in case the ends are not close enough for you to use \mpl{&}. \item The rigmarole with saving the current picture, is to show a copy of the egg path with and without the construction lines. \end{itemize} } \begin{code}[xleftmargin=0pt] input eggs-common path a, b, c, d, egg; numeric r; r = 100; a = fullcircle scaled 2r; b = fullcircle scaled 4r shifted point 4 of a; c = fullcircle scaled 4r shifted point 0 of a; d = fullcircle scaled 2 abs (point 2 of a - point 1 of b) shifted point 2 of a; egg = subpath (0, 1) of b .. point 2 of d .. subpath (3, 4) of c .. subpath (5, 7) of a .. cycle; beginfig(1); fill egg withpen pencircle scaled 2 withcolor eggshell; picture P; P = currentpicture; drawoptions(withpen pencircle scaled 1/4 withcolor dark_eggshell); draw a; draw d; drawoptions(withpen pencircle scaled 1/4 withcolor 1/2); draw point 1 of egg -- point 4 of egg -- point 0 of egg -- point 3 of egg; draw egg; drawoptions(withpen pencircle scaled 2 withcolor 7/16); draw center a; draw center d; draw numbered_points(egg); drawoptions(); draw P shifted 240 right; endfig; \end{code} \newpage \subsection{Pythagorean egg} The centres of the arcs are determined by the 3-4-5 triangle at the origin.\mwpic{0pt}{eggs-thom} \begin{code} numeric r, a, b, t; a = 60; 4b = 3a; r = a ++ b; path base, cap, egg; base = subpath (4, 8) of fullcircle scaled 2(2r-b); cap = subpath (0, 4) of fullcircle scaled 2r shifted (0, a) cutbefore ((b, 0) -- (b, 2r)) cutafter ((-b, 0) -- (-b, 2r)); egg = point 4 of base {up} .. cap .. {down} base & cycle; % more naturally "base {up} .. cap .. {down} cycle" % but then point 0 would not be at 3 o'clock \end{code} Note that you can use $\to$ to create reasonably large circular arcs. The parts of the drawing for filling the egg, and showing the construction are similar to the first example. \subsection{A taller Pythagorean egg} A slightly different approach using a $\sqrt3$-$\sqrt4$-$\sqrt7$ triangle.\mwpic{20pt}{eggs-357} \begin{code} path base, cup, cap, egg; base = fullcircle scaled 200; z1 = point -2/3 of base; z2 = point 2/3 of base; z3 = point 10/3 of base; z4 = point 14/3 of base; z5 = 1/2[z2, z3]; z6 = 1/2[z4, z1]; numeric a, b; a = abs(z3 - z1) - abs(z4 - z6); b = abs(z3 - z1) - abs(z4 - z5); cup = subpath (4, 8) of fullcircle scaled 2a shifted z6; cap = fullcircle scaled 2b shifted z5 cutbefore (z5 -- 2[z4, z5]) cutafter (z5 -- 2[z1, z5]); egg = point 4 of cup {up} .. cap .. {down} cup & cycle; \end{code} \newpage \subsection{Golden section egg} An alternative construction.\mwpic{-10pt}{eggs-gold} \begin{code}[xleftmargin=0pt] path base, aa, bb; pair m, n, n'; base = fullcircle scaled 200; m = 1/2 point 0 of base; aa = halfcircle scaled 2 abs (point 2 of base - m) shifted m cutbefore (origin -- 1000 up); n = point infinity of aa; n' = n reflectedabout(up, down); bb = subpath (0, 2) of base shifted n cutafter (origin -- 1000 up); path dome, cap, cup, egg; dome = fullcircle scaled 2 (abs(n - point 0 of base) - abs(n - point 0 of bb)) shifted point infinity of bb; cap = dome cutbefore (point 4 of bb -- 2[n, point 4 of bb]) cutafter (point 4 of bb -- 2[n', point 4 of bb]); cup = subpath (4, 8) of base; egg = point 4 of cup {up} .. cap .. {down} cup & cycle; \end{code} \subsection{Four point egg} % eggs-four-point.mp So far all the eggs have been drawn with semi-circular big end, but this can be improved. To get a smoother curve, you can use four different sized arcs with four different centres of rotation to make up each side of the egg.\mwpic{-36pt}{eggs-four-point} \begin{code}[xleftmargin=0pt] path egg, a, b, c, d; a = fullcircle scaled 80; b = a scaled 2 shifted point 6 of a; c = halfcircle scaled 2 (abs(point 0 of a - point 5 of b) - abs(point 0 of a)); d = fullcircle scaled 2 abs(point 2 of a - point 2 of c) shifted point 2 of c; egg = point 0 of c {up} .. subpath (1,3) of d .. {down} point 4 of c .. subpath (5, 7) of b .. cycle; \end{code} \newpage \subsection{Five point egg} The next level of sophistication is to use five different arcs, but this is more complex and you lose the points at exactly E, N, W, and S.\mwpic{0pt}{eggs-five-better}\marginpar{\par\vskip 3in \noindent\hey Instead of defining and joining circular arcs, this construction defines the points for the egg and the desired directions at each point; all the work of making the circular arcs is left to the $\to$ connector. The six symmetrically-arranged rings $r_1$ to $r_6$ are used to define eight centres of rotation $o_1$ to $o_8$ which are either points on the rings or intersections of lines between them. Then eight directions $u_1$ to $u_8$ are defined at right angles to lines between pairs of centre points. Finally the handy \mpl{directionpoint} macro is used to find the points where the relevant circle is moving in that direction. To make the egg, these points are joined up with $\to$ constrained by the matching direction to make circular arcs.\\ \llap{$\longleftarrow$\ }{\small Like so.} } \begin{smallcode}[xleftmargin=0pt] numeric a; a = 56; path r[]; % the rings r1 = fullcircle scaled 2a shifted (0, -3/2 a); r2 = fullcircle scaled 2a shifted (0, -1/2 a); r3 = fullcircle scaled 2a shifted (0, +1/2 a); r4 = fullcircle scaled 2a shifted (0, +3/2 a); r5 = r2 rotatedabout(point 2 of r2, -60); r6 = r2 rotatedabout(point 2 of r2, +60); pair o[]; % the centres of rotation for each arc o1 = point 6 of r5; o2 = point 2 of r3; o3 = point 6 of r6; o4 = whatever[o3, point 2+4/3 of r2] = whatever[o2, point 2-4/3 of r1]; o8 = whatever[o1, point 2-4/3 of r2] = whatever[o2, point 2+4/3 of r1]; o6 = 1/2[point 2-4/3 of r1, point 2+4/3 of r1]; o5 = whatever[o6, point 2-4/3 of r3] = whatever[o4, point 2+4/3 of r1]; o7 = whatever[o6, point 2+4/3 of r3] = whatever[o8, point 2-4/3 of r1]; pair u[], t[]; % directions and points for the egg path u0 = (o8 - o1) rotated 90; t0 = directionpoint u0 of r6; u1 = (o2 - o1) rotated 90; t1 = directionpoint u1 of r4; u2 = (o2 - o3) rotated 90; t2 = directionpoint u2 of r4; u3 = (o4 - o3) rotated 90; t3 = directionpoint u3 of r5; u4 = (o5 - o4) rotated 90; u5 = (o6 - o5) rotated 90; u6 = (o6 - o7) rotated 90; u7 = (o7 - o8) rotated 90; t4 = directionpoint u4 of fullcircle scaled 2 abs (t3 - o4) shifted o4; t5 = directionpoint u5 of fullcircle scaled 2 abs (t4 - o5) shifted o5; t6 = directionpoint u6 of fullcircle scaled 2 abs (t5 - o6) shifted o6; t7 = directionpoint u7 of fullcircle scaled 2 abs (t6 - o7) shifted o7; path egg; egg = for i=0 upto 7: t[i] {u[i]} .. endfor cycle; \end{smallcode} \newpage \subsection{A superellipse egg} All this construction is a good exercise in ingenuity, but if you just want a simple quick egg path, then the \mpl{superellipse} macro gives you a \MP-specific option. All you need is this:\mwpic{-36pt}{eggs-super} \begin{code}[xleftmargin=0pt] path egg; egg = superellipse(right, 1.6 up, left, 1.2 down, 0.69); egg := egg scaled 100; \end{code} \vfill \centerline{\tiny [This space intentionally left blank]} \vfill \subsection{The perfect egg} The last word in egg curve perfection is the algebraic solution provided by the TDCC Laboratory in Japan [{\small \mpl{https://nyjp07.com/index_E.html}}].\mwpic{0pt}{eggs-perfect} \begin{code} path egg; egg = for t=-180 step 15 until 180 - eps: (0.78 cosd(1/4 t) * sind(t), -cosd(t)) .. endfor cycle; egg := egg scaled 128; \end{code} Note that, unlike all the others, this path has 24 points and the path starts at the top. You can draw it starting at 3 o’clock, and with only 8 points but the egg is slightly less perfect. Just replace the loop above with: \begin{code} egg = for t=90, 135, 180, -135, -90, -45, 0, 45: (0.78 cosd(1/4 t) * sind(t), -cosd(t)) .. endfor cycle; \end{code} \newpage \subsection{Egg kitsch} If you want eggs that look solid, then you can use \mpl{interpath}:\mpic{-24pt}{eggs-shaded} \begin{smallcode}[xleftmargin=0pt] path egg, spot; egg = (for t=-180 step 15 until 180 - eps: (0.78 cosd(1/4 t) * sind(t), -cosd(t)) .. endfor cycle) scaled 100; spot = fullcircle scaled 4 shifted 3/4 point 3 of egg; vardef fade_filled(expr egg, spot, dark, light, n) = image( for i = 0 upto n: fill interpath(i/n, egg, spot) withcolor ((i/n)**1/3)[dark,light]; endfor) enddef; beginfig(1); color a, b; a = 1/256(150, 100, 60); b = 1/256(256, 220, 180); draw fade_filled(egg, spot, a, b, 256) rotated -30; endfig; \end{smallcode} This works nicely with any of the "egg" paths defined in this section. And finally, if all that has made you feel peckish, then how about these?\mwpic{12pt}{eggs-fried} \begin{smallcode}[xleftmargin=0pt, xrightmargin=-24pt] path yolk, base; color cooked_egg_yolk, cooked_egg_white; cooked_egg_yolk = 1/256(216, 136, 49); cooked_egg_white = 1/256(235, 237, 233); vardef fried_egg(expr r) = save base, yolk; path base, yolk; yolk = for i=0 upto 17: (r + 1/8 normaldeviate) * dir 20i .. endfor cycle; base = for i=0 upto 17: (2r + 1/8r * normaldeviate) * dir 20i .. endfor cycle; base := base shifted (uniformdeviate r/2, uniformdeviate r/2); image( fill base withcolor cooked_egg_white; fill yolk withcolor cooked_egg_yolk; fill subpath (6.7, 9.6) of yolk scaled 0.8 -- subpath (9.6, 6.7) of yolk scaled 0.66 -- cycle withcolor 1/2[cooked_egg_yolk, white]; ) enddef; for i=0 upto 1: draw fried_egg(40) shifted 120 dir 120i; endfor \end{smallcode} %=============================================================== \newpage \section{Data visualizations}\label{dviz} \textsc{Graphs and other displays} that show data, rather than a mathematical function, are presented in this section, with a focus on illustrations for books and technical papers. Most of the examples here follow those developed in Edward Tufte's \textsl{The Visual Display of Quantitative Information}. \bigskip\noindent Most of them have a pale manilla background, which was added using the technique from §\ref{backgrounds}, like this: \begin{code} picture p; p = currentpicture; currentpicture := nullpicture; bboxmargin := 12; fill bbox p withcolor 1/32(32, 32, 31); draw p; \end{code} \newpage \subsection{Simple time lines} \noindent\mpic{144pt}{tufte-mpg}\marginpar{ \begin{itemize} \item The complete Lua\TeX\ document shows the use of "fontspec" to get the Palatino-like font, used in E.\@ Tufte's books. \item The data is stored as \ values in a \ variable. This only works if both data values are numeric. If the values are larger than 4096 you either need to scale them or use the "double" number system. \item Notice how the horizontal unit $u$ is set by measuring the width of a label using the technique discussed in §\ref{textsize}. And that you have to shift the data path left before applying the $x$-scaling to avoid overflow. \end{itemize} } \begin{texcode}[xleftmargin=0pt] \documentclass{standalone} \usepackage{luamplib} \usepackage{fontspec} \setmainfont[Numbers=OldStyle]{TeX Gyre Pagella} \begin{document} \mplibtextextlabel{enable} \begin{mplibcode} \end{texcode}\vskip -8pt \begin{smallcode}[xleftmargin=2pt] beginfig(1); path data, p; data = (1978, 18) -- (1979, 19) -- (1980, 20) -- (1981, 22) -- (1982, 24) -- (1983, 26) -- (1984, 27) -- (1985, 27.5); numeric u, v; u = xpart urcorner textext("1980\kern 0.75em"); v = 8; p = data shifted -(xpart point 0 of data, 0) xscaled u yscaled v; draw (xpart point 0 of p, 20) -- p -- (xpart point infinity of p, 20); draw (xpart point 0 of p, 0) -- (xpart point infinity of p, 0); for t=0 upto length p: numeric x, y; (x, y) = point t of p; undraw (x, y) withpen pencircle scaled 2 dotlabeldiam; draw (x, y) withpen pencircle scaled dotlabeldiam; label("\strut" & decimal ypart point t of data, (x, y + 8)); draw (x, 0) -- (x, 4); label("\strut" & decimal xpart point t of data, (x, 12)); endfor dotlabel.rt(btex \vbox to 6pt{\halign{\small #\hss\cr 13.7 mpg, average\cr for all cars on\cr road, 1978\cr}\vss} etex, (xpart point 0 of p, 13.7v)); dotlabel.lft(btex \vbox to 6pt{\halign{\small #\hss\cr 19.5 mpg, expected\cr average for all cars\cr on road, 1985\cr}\vss} etex, (xpart point infinity of p, 19.5v)); label.top(btex \vbox{\halign{\hss\textsc{#}\hss\cr required fuel economy standards:\cr new cars built from 1978 to 1985\cr}} etex, point 5/2 of bbox currentpicture shifted 21 up); endfig; \end{smallcode}\vskip -10pt \vbox to 0pt{\begin{texcode}[xleftmargin=0pt] \end{mplibcode} \end{document} \end{texcode}\vss} \newpage \subsection{Time line with minimal annotation} \noindent\mpic{120pt}{tufte-budget}\marginpar{ \begin{itemize} \item This one has an even sparser frame, and uses the \mpl{ahangle} trick to make the neat I-beam annotation mark. \item It is suggested that you resist the temptation to make very many special macros to do charts like this; the ideas here are mainly to show that \MP\ makes a good environment for following Tufte’s advice about charts: to maximize data ink, and minimize chart junk. \end{itemize}} \begin{smallcode}[xleftmargin=0pt] beginfig(1); path data, p; data = (1967, 311) -- (1968, 332) -- (1969, 372) -- (1970, 385) -- (1971, 385) -- (1972, 393) -- (1973, 387) -- (1974, 381) -- (1975, 387) -- (1976, 400) -- (1977, 380); numeric u, v; u = xpart urcorner textext("1980\kern 0.75em"); v = 1.414; p = data shifted -(xpart point 0 of data, 300) xscaled u yscaled v; draw p; for d = 300 step 20 until 400: numeric y; y = (d - 300) * v; label.lft("\strut\scriptsize\$\,\small" & decimal d, (-12, y)); draw (-8, y) -- (-12, y); if d > 370: draw (xpart point 3 of p, y) -- (xpart point infinity of p + 8, y) dashed evenly scaled 1/4 withpen pencircle scaled 1/4; fi endfor path a; a = (xpart point infinity of p + 21, (380 - 300) * v) -- (xpart point infinity of p + 21, (400 - 300) * v); interim ahangle := 180; interim ahlength := 2; drawdblarrow a withpen pencircle scaled 1/4; label("\small 5\%", point 1/2 of a shifted 12 right); for t=0 upto length p: numeric x, y; (x, y) = point t of p; undraw (x, y) withpen pencircle scaled 2 dotlabeldiam; draw (x, y) withpen pencircle scaled dotlabeldiam; draw (x, -8) -- (x, -12); label("\strut\small" & decimal xpart point t of data, (x, -20)); endfor label.urt(btex \vbox{\halign{\small #\hfill\cr Per capita\cr budget expenditure\cr in constant dollars\cr}} etex, (0, (410 - 300) * v)); endfig; \end{smallcode} \newpage \subsection{Time line with more complex dates} If the dates in your time line are more granular than years, then you need a better way to deal with them. This chart shows the £/€ exchange rate by month. $$\includegraphics[width=\textwidth]{tufte-currency}$$ The dates on the horizontal axis where transformed from calendar dates to a serial number using this routine: \begin{code} vardef base(expr Y, M, d) = save m, y; numeric m, y; if M < 3: m = M + 9; y = Y - 1; else: m = M - 3; y = Y; fi 365/1024 y + (floor(y/4) - floor(y/100) + floor(y/400) + floor((2+3m)/5) + 30m + d - 307) / 1024 enddef; \end{code} which allows you to add events like this: \begin{code} dotlabel.bot("Brexit vote", (base(2016, 6, 24) * u, 78 v)); \end{code} for suitable values of $u$ and $v$. \newpage \section{Commutative diagrams} \textsc{If you want lots} of complex bells and whistles on your commutative diagrams, then you probably want to use specialist tools like "tikz-cd" or "xypic", but if your needs are simpler, plain \MP\ is more than capable, and if you are already using it for other illustrations, there is one less thing to learn. Here are two examples to illustrate some general techniques. They may be familiar to readers of the manuals for the tools referred to above. $$ \includegraphics{tikzcd-example} \qquad \includegraphics{xypic-example} $$ The complete code used to generate the right-hand picture is shown on the right.\rlap{\rightarrow}% \vadjust{\moveright5.5in\vbox to 0pt{\kern-218pt \begin{smallcode} picture U, XY, X, Y, Z; z1 = -z2 = (-61, 42); U = thelabel("$U$", z1); XY = thelabel("$X\times_ZY$", origin); X = thelabel("$X$", (x2, 0)); Y = thelabel("$Y$", (0, y2)); Z = thelabel("$Z$", z2); forsuffixes @=U, XY, X, Y, Z: draw @; endfor ahangle := 20; vardef curved_connect@#(expr s, a, b, d) = save line, mark; path line; line = center a {d} .. center b; interim bboxmargin := 4; drawarrow line cutbefore bbox a cutafter bbox b; picture mark; mark = thelabel@#("$\scriptstyle " & s & "$", point 1/2 of line); interim bboxmargin := 1; unfill bbox mark; draw mark; enddef; vardef connect@#(expr s, a, b) = curved_connect@#(s, a, b, center b - center a) enddef; connect.bot("p", XY, X); connect.rt ("q", XY, Y); connect.top("g", Y, Z); connect.lft("f", X, Z); curved_connect.urt("x", U, X, right); curved_connect.llft("y", U, Y, dir -80); drawoptions(dashed withdots scaled 1/2); connect("(x,y)", U, XY); drawoptions(); \end{smallcode} \noindent\textit{\small This example assumes you are using "mplibtextextlabel" – §\ref{ttlabel}} \vss}} The approach taken for both examples is first to define the node labels as pictures placed as needed, and then write a special-purpose "connect" macro to make consistent arrows between the nodes, using \mpl{center}, \mpl{bbox}, \mpl{cutbefore}, and \mpl{cutafter} as appropriate. The $X\times_ZY$ example needs two variations. The "curved_connect" macro takes a string for the label, the two nodes to be connected, and the initial direction for the curved path to connect them. You can't have optional macro arguments in \MP\ but you can call macros from inside another macro, so a second simpler macro "connect" is defined to do straight connections. To avoid repetition, this macro simply calls "curved_connect" with the required direction from $a$ to $b$. For the $f^*E$ example, "connect" is simpler, because all the arrows are straight and there are no labels, but needs to allow for arrows crossing: \begin{smallcode} vardef connect(expr a, b) = save line; path line; interim bboxmargin := 4; line = center a .. center b cutbefore bbox a cutafter bbox b; cutdraw line withpen pencircle scaled 4 withcolor background; drawarrow line enddef; \end{smallcode} \newpage \section{Tilings and tessellations} \textsc{In mathematical terms}, a “tiling” is a countable set of tiles that cover the plane without gaps or overlaps.\footnote{Adapted from \textsl{Tilings and Patterns}, Branko Grünbaum \& G.\@ C.\@ Shephard, Freeman, 1987} This section loosely follows that idea, and presents some ideas and general techniques for creating tilings and other patterns or textures. You can make an effective grid by drawing repeated lines and then clipping to the size you want:\mpic{-42pt}{tiling-simple} \begin{code} for i = -10 upto 10: draw (left--right) scaled 200 shifted (0, 20i); draw (down--up) scaled 200 shifted (20i, 0); endfor clip currentpicture to fullcircle scaled 200; \end{code} but this is a bit limited. If you want to produce more interesting tilings, you need to define a unit shape or picture, and a pair of vectors to repeat it. \begin{code} path unit; pair u, v; color a, b; unit = unitsquare scaled 24; u = point 1 of unit - point 0 of unit; v = point 3 of unit - point 0 of unit; a = 3/4[red, white]; b = 3/4[blue, white]; for i=-5 upto 5: for j=-5 upto 5: fill unit shifted (i*u + j*v) withcolor if odd (i+j): a else: b fi; draw unit shifted (i*u + j*v); endfor endfor clip currentpicture to fullcircle scaled 200; \end{code} In tilings with more complex shapes you may find that using \mpl{fill} and \mpl{draw} in the same loop causes uneven lines because the fill overlaps part of the line. In these cases it is a good idea to duplicate the loops; use the first set for filling, the second for drawing. \newpage \subsection{Tiling with regular polygons}\label{sec:regtiling} \textsc{After tiling with squares}, the two simplest tilings are with triangles and hexagons\mwpic{-24pt}{tiling-hex-trig} (using the regular polygons from §\ref{polygons}). The basic loop is the same as the previous page except that the vectors $u$ and $v$ are now at 60° to each other (as shown in blue and red in the examples to the right). All of these examples where drawn with the same basic loop as before: \begin{code} for i = -n upto n: for j = -n upto n: draw P shifted (i * u + j * v); endfor endfor; \end{code} In the first row, $P$ was set to a simple polygon path: \begin{code} triangle = for i=0 upto 2: (0, 16) rotated 120i -- endfor cycle; hexagon = for i=0 upto 5: (0, 16) rotated 60i -- endfor cycle; \end{code} The vectors $u$ (in red) and $v$ (in blue) were defined as (for both tilings): \begin{code} u = point 0 of triangle - point 1 of triangle; v = u rotated -60; \end{code} To make the coloured versions, $P$ was defined as an appropriate \. For the triangular tiling, it looked like this: $\vcenter{ \begin{mplibcode} input colorbrewer-rgb path t, tt; t = for i=0 upto 2: (0,8) rotated 120i --endfor cycle; tt = t reflectedabout(point 2 of t, point 0 of t); beginfig(0); fill t withcolor Reds 8 2; fill tt withcolor Blues 8 2; draw t; draw tt; endfig; \end{mplibcode}}$ so that the tiling actually filled the plane. In the hexagonal tiling there are no gaps to fill, but in order to get a non-adjacent colouring, the unit picture was defined as three shifted copies of the hexagon each filled with a different color. The unit vectors were therefore scaled by $\sqrt3$ and rotated by 30° (as shown). The bottom row the unit pictures were replaced with drawings that connect the centre of each shape to the midpoint of each side (in red), like this: $$ \begin{mplibcode} path p[]; input colorbrewer-rgb p3 = for i=0 upto 2: (0, 14) rotated 120i -- endfor cycle; p6 = for i=0 upto 5: (0, 14) rotated 60i -- endfor cycle; picture P[]; for i=3,6: P[i] = image( for j=1 upto length p[i]: draw origin -- point j+1/2 of p[i] withcolor Reds 7 6; endfor draw p[i]); endfor beginfig(0); draw P3; draw P3 reflectedabout(point 0 of p3, point 2 of p3); draw P6 shifted (60, 3); endfig; \end{mplibcode} $$ This has the effect of connecting the centres of adjacent shapes in the tiling, which reveals that each tiling is the dual of the other. \newpage \subsection{Separating filling and drawing} \textsc{Repeating a unit image} can sometimes cause unwanted overlaps, so as noted above, the solution is to make a filler unit and a drawing unit and do the filling first and the drawing second. In this example\mwpic{-32pt}{arch-4-8-8} the drawing unit (the octagon) is simple so you can just draw that path instead of making another \ for it. \begin{smallcode} input colorbrewer-rgb path o, r[]; % o is the octagon, r[] are the "corners" o = (for i=0 upto 7: 21 dir 45i -- endfor cycle) rotated -90/4; pair t; t = whatever[point 0 of o, point 1 of o] = whatever[point 2 of o, point 3 of o]; r1 = subpath (1,2) of o -- t -- cycle; r2 = r1 rotated 90; r3 = r2 rotated 90; r4 = r3 rotated 90; picture filler; filler = image( filldraw r1 withcolor Reds 8 3; filldraw r3 withcolor Reds 8 3; filldraw r2 withcolor Blues 8 3; filldraw r4 withcolor Blues 8 3; filldraw o withcolor Purples 8 2; ); pair u, v; u = point 0 of o - point 5 of o; v = u rotated 90; beginfig(1); numeric n; n = 5; for i=-n upto n: for j=-n upto n: draw filler rotated ((i+j) mod 2 * 90) shifted (i*u + j * v); endfor endfor for i=-n upto n: for j=-n upto n: draw o shifted (i*u + j * v); endfor endfor \end{smallcode} Rotating every other \mpl{filler} allows you to get the alternate colours in the squares. \mpic{-60pt}{arch-4-8-8-parts}% Using \mpl{filldraw} ensures that there are no gaps between adjacent segments. \newpage \subsection{Tilings with more complex patterns} \textsc{The next example} also uses the square lattice,\mwpic{0pt}{arch-3-4-3-4} but the unit is more complicated, so the drawing needs two \ variables, one for the colour fill and a second for the grid. \begin{smallcode} input colorbrewer-rgb path s[], t[]; s1 = unitsquare scaled 21 rotated 15; s2 = s1 rotated 150; t1 = subpath (4, 3) of s1 -- point 1 of s2 -- cycle; t2 = t1 reflectedabout(point 1 of t1, point 2 of t1); t3 = t1 rotated 150; t4 = t1 rotated 210; picture color_unit, grid_unit; color_unit = image( fill s1 withcolor Oranges 8 1; fill s2 withcolor Oranges 8 2; fill t1 withcolor Blues 8 1; fill t2 withcolor Blues 8 2; fill t3 withcolor Blues 8 3; fill t4 withcolor Blues 8 4; ); grid_unit = image( draw s1; draw s2; draw t2; draw t3; draw t4; ); pair u, v; u = point 1 of s1 - point 1 of s2; v = u rotated 90; numeric n; n = 4; forsuffixes $=color_unit, grid_unit: for i=-n upto n: for j=-n upto n: draw $ shifted (i * u + j * v); endfor endfor endfor \end{smallcode} \newpage \subsection{Showing the dual tiling} \textsc{These tilings can be classified} by the configuration of the polygons that meet at each vertex. This one is $(3^4, 6)$ because each vertex has four triangles and one hexagon. It exists in two enantiomorph forms.\mxpic{-80pt}{3.6in}{arch-snub-hexagon} The unit pictures look like this: \par\bigskip \vbox{\halign{#&\qquad\qquad\vbox to 48pt{\hsize=2.7in\noindent #\par\vss}\cr \includegraphics[scale=0.75]{arch-snub-hexagon-unit} &\hey\itshape To reveal the dual of the tiling, you can draw a line from the median (or centroid if you prefer) of each polygon to the centre of each edge.\cr}} \bigskip \noindent They are drawn like this, where $h$ is the hexagon, $t_1 \dots\ t_6$ are the blue triangles surrounding it, and $t_7$ \& $t_8$ are the two “connecting” triangles, which swap sides to make the enantiomorphs. \begin{code} unit[k] = image( for i=1 upto 6: fill t[i] withcolor Blues 8 if odd i: 2 else: 3 fi; endfor for i=7 upto 8: fill t[i] withcolor Oranges 8 if odd i: 3 else: 2 fi; endfor fill h withcolor Oranges 8 2; forsuffixes S=h, t1, t2, t3, t4, t5, t6, t7, t8: draw S withpen pencircle scaled 1/4 withcolor 3/4; pair m; m = median(S); for i=1 upto length S: draw m -- point i - 1/2 of S withcolor 3/4; endfor endfor); \end{code} The $\id{median}()$ routine is from §\ref{polygons-given-side} and the colours are from §\ref{colorbrewer}. This tiling is generated using the loop-with-triangular-grid-vectors from §\ref{sec:regtiling}. \newpage \subsection{Tiling with a dynamic unit} \textsc{In order to reveal} patterns in a tiling, you might want to vary the colours or line styles used in each repeated drawing unit. In this case, you can write a macro that takes a parameter and returns a picture to draw.\mwpic{-36pt}{arch-3-4-6-4} \begin{smallcode} \mplibsetformat{metafun} % <-- for the "transparent" macro \begin{mplibcode} input colorbrewer-rgb beginfig(1); numeric r; r = 5; path d; d = for i=1 upto 12: (0, r) shifted (r * (sqrt(3)+2), 0) rotated 30i -- endfor cycle; color shade[]; shade0 = Oranges 8 3; shade2 = Greens 8 3; shade1 = Blues 8 3; shade3 = Reds 8 3; vardef unit(expr n) = image( fill d withcolor transparent (2, .9, shade[n mod 4]); draw d; ) enddef; pair u, v; u = point 0 of d - point 3 of d; v = u rotated 60; numeric n; n = 6; for i=-n upto n: for j=-n upto n: draw unit(i*j) shifted ((i - floor(j / 2)) * u + j * v); endfor endfor clip currentpicture to unitsquare shifted -(1/2, 1/2) scaled (n * 9 r); endfig; \end{mplibcode} \end{smallcode} Instead of defining six triangles, six squares, and a hexagon, you can just define the dodecagon and overlap each one. Using a macro to create the unit, allows you to choose a different colour for each filler. Using the \mpl{transparent} macro from Metafun automatically mixes the colours for the overlaps. But the edges don't look so good, so you need to clip the whole picture to a neat square. \newpage \section{Recursion and iteration} \textsc{This chapter is not a tutorial} on recursion or iteration \textit{per se}, but rather more of an exploration of the \MP\ techniques you can use to create some particular types of drawing such as trees, plane-filling curves, non-periodic tilings, and fractals.\mwpic{-48pt}{rec-bush} \medskip\noindent Even so, it is perhaps useful to review some of the basic programming ideas involved. Consider for example the greatest common divisor algorithm presented in §\ref{sec:gcd}. \begin{smallcode} vardef gcd(expr a, b) = if b = 0: a else: gcd(b, a mod b) fi enddef; \end{smallcode} The reason this works is that we know (mathematically) that $0 \le a \bmod b < b$, and therefore that the arguments to the recursive call must get smaller each time and eventually we must get to $b=0$ when the answer will be $a$. This is the basic recursive approach: ensure at least one argument gets smaller each time and stop when you get to a given limit. The examples in this chapter use one of two simple approaches: \begin{itemize} \item Explicitly pass a \mpl{level} argument that is decremented on each recursive call, and stop the recursion when the level gets to zero \item Pass a \ or two \ arguments, and stop the recursion when the path is too short or the pairs are too close together. \end{itemize} If you find recursion confusing, you can nearly always use an iterative approach instead. For example, you can implement the \mpl{gcd} function like this: \begin{smallcode} vardef gcd(expr A, B) = save r, a, b; numeric a, b, r; a := A; b := B; forever: r := a mod b; exitif r = 0; a := b; b := r; endfor b enddef; \end{smallcode} Notice that you have to use assignment in the loop to update the variables, and that you cannot assign to the arguments of a macro. Notice also that this version requires both arguments to be positive integers. You need to use your judgement to decide which is the better approach for a given problem. \newpage \subsection{The Koch curve} \textsc{The Swedish mathematician} Helge von Koch\mpic{-30pt}{rec-koch-steps} originally devised the Koch curve as an example of a non-differentiable curve that could be constructed with elementary geometry. It makes a good introduction to recursive paths with \MP. The construction is recursive: each straight line segment in the path is replaced with four copies of itself, scaled down $\frac13$ and arranged as shown at Level 1 \rightarrowfill\break At each level of the construction, the number of points in the path increases four-fold and the \mpl{arclength} of the path gets $\frac43$ longer. \begin{code} vardef koch(expr level, a, b) = if level = 0: a -- b else: save p, q, r; pair p, q, r; p = 1/3[a,b]; r = 2/3[a,b]; q = r rotatedabout(p, 60); koch(level-1, a, p) & koch(level-1, p, q) & koch(level-1, q, r) & koch(level-1, r, b) fi enddef; \end{code} The five levels were drawing using this function in a loop like this: \begin{code} for n=0 upto 4: draw koch(n, origin, 300 right) shifted (0, -100n) endfor \end{code} The annotations in the middle show the \mpl{length} of the path and the \mpl{arclength}. The curve will always fit in the same bounding box but in theory it can become infinitely long. In practice it looks much the same past level 6, and you will start running into \MP\ limitations. The length of a path is not limited by the default scaled number system, but the numbers actually returned by \mpl{length} and \mpl{arclength} may not be reliable for very long paths. Also the call stack may get very large and the single-threaded processing time can get very slow, and when the length of each segment shrinks to the size of your pen, you will start losing detail. \newpage \subsection{Sierpinski's gaskets} \textsc{The second example} of recursive construction also dates from the early 20th century, but unlike von Koch's infinite curve, the area of Sierpinski's gasket tends to zero.\mwpic{-12pt}{rec-sierpinski-triangle} In the original specification, you are supposed to remove the central quarter of each triangle, but this program does it the other way round and delays drawing the triangles until they are small enough. \begin{code}[xleftmargin=0pt, xrightmargin=-2in] vardef gasket(expr t, s, limit) = if length (point 1 of t - point 0 of t) < limit: fill t; else: save little_t; path little_t; little_t = t scaled s; for i=1 upto length t: gasket(little_t shifted (point i of t - point i of little_t), s, limit); endfor fi enddef; \end{code} Note the useful idiom \mpl{shifted (point i of t - point i of little_t)} – this neatly tucks a copy of the small triangle into the appropriate corner of the big triangle. You can make this even simpler by coding the scaling parameter $s$ and \id{limit} as constants in the recursive routine, so that you do not have to pass them down each time. The triangular gasket was generated using the macro like this: \begin{code}[xleftmargin=0pt, xrightmargin=-2in] beginfig(1); path T; T = for i = 1 upto 3: 220 up rotated 120i -- endfor cycle; gasket(T, 1/2, 20); endfig; \end{code} You can generalize it, for example by making the path \id{T} into a pentagon with scaling factor $s=(3-\sqrt5)/2$, or a hexagon with $s=1/3$, and so on: \vbox to 0pt{\vskip-2pt\hsize10in\noindent\includegraphics[width=10in]{rec-sierpinski-pentagon.pdf}\par\vss} \newpage \subsection{The Heighway dragon} \textsc{The Heighway dragon curve} dates from the 1960s, and is created in a similar way to the Koch curve: each straight line segment is recursively replaced with two copies of itself scaled down and arranged as shown.\mwpic{-36pt}{rec-dragon} \medskip \centerline{\includegraphics{rec-heighway-stages}} \noindent Note that every other segment is flipped left and right. At each stage, the number of points increases two-fold and the path gets $\sqrt2$ times longer. Here is a recursive routine to generate the curve as a single path. \begin{smallcode} numeric r, theta; r = sqrt 1/2; theta = 45; vardef dragon(expr level, a, b) = if level > 0: save p; pair p; p = r[a, b] rotatedabout(a, theta); dragon(level - 1, a, p) & reverse dragon(level - 1, b, p) else: a .. b fi enddef; \end{smallcode} The blue dragon was created with: {\small\mpl{draw dragon(15, origin, 240 right)}}\rlap{\raise1ex\hbox{\ $\smash{\nearrow}$}} After the fourth level the corners of the curve start to touch each other, but they never cross. You can see this if you draw the curve with rounded corners. \begin{smallcode} vardef rounded_corners expr p = save r, n; numeric r, n; r = 1/3; n = length p; subpath (0, 1-r) of p for t=1 upto n-1: .. subpath (t+r, t+1-r) of p endfor .. subpath (n-r, n) of p enddef; \end{smallcode} The red dragon was: {\small\mpl{draw rounded_corners dragon(10, origin, 240 right)}}\rlap{\hbox{\ $\smash{\longrightarrow}$}} \vfill \noindent{\small\llap{\hey\ }The length of the dragon path at level $n$ is $2^n$, so if you want to do arithmetic with the path length you need to use a big number system when $n > 11$.} \newpage \subsection{Iterative dragons} \textsc{The dragon curve} can also be created with iteration instead of recursion. Another way of viewing the stages of developing the curve is that at each stage the whole curve is replaced by two copies of itself arranged as shown: \medskip \centerline{\includegraphics{ifs-heighway-stages}} \smallskip\noindent We can do this in two steps in a loop, like this:\mpic{-160pt}{ifs-heigh} \begin{smallcode} path p; p = origin -- dir 30; numeric n; for i=1 upto 12: n := length p; p := p rotated 45; p := p & reverse p rotatedabout(point n of p, 90); endfor draw p scaled (384 / xpart (urcorner p - llcorner p)); \end{smallcode} In this approach, instead of scaling down each time, the curve is just allowed to grow $\sqrt2$-times bigger in each loop, then scaled to the desired width (384\unit{pt}) when it is complete. The 12 stages in the loop produce the rotated blue dragon as shown.\rlap{\raise1ex\hbox{\ $\smash{\nearrow}$}} \vfill\noindent With a small adaptation, you can also use this to explore variations. \begin{smallcode} path p; p = origin -- dir 30; numeric n, r; r = 3; for i=1 upto 12: n := length p; p := p rotated (45 - r); p := p & reverse p rotatedabout(point n of p, 90 + 2r); endfor \end{smallcode} The extra parameter $r$ is used to open up the folds, making it more “organic”.\mpic{-200pt}{ifs-heigh-open} \newpage \subsection{The golden dragon} \textsc{You can also explore variations} with the recursive approach by altering the scaling and rotation. Here $r\simeq 0.74274$ and $\theta\simeq 32.893°$ in the initial triangle.\vadjust{\moveright136pt\vbox to 0pt{\vskip 3.16in \hsize 3.6in \noindent Because the initial triangle shape is shorter on one side, it is better to adapt the \mpl{dragon} routine to measure the gap between points instead of using a fixed level parameter: \begin{smallcode} vardef dragon(expr a, b) = if abs(a-b) > 1: save p; pair p; p = r[a, b] rotatedaround(a, theta); dragon(a, p) & reverse dragon(b, p) else: a .. b fi enddef; \end{smallcode} \vss}} $$\hbox to \textwidth{\includegraphics{rec-dragon-golden.pdf}\hss}$$ \newpage \subsection{The Peano-Gosper curve, or flow-snake} \textsc{The Peano-Gosper curve} is a space-filling curve. It is constructed in the same way as the dragons, but generating shape has seven sections instead of two, and they are cunningly arranged to fill the space.\mpic{-48pt}{rec-flowsnake-construction} The arrows indicate the reversals so that the scaled-down copies fill the larger part of the hexagons that contain them.\rlap{\hbox{\ $\smash{\rightarrow}$}} $$\includegraphics[width=\textwidth]{rec-flowsnake}$$ This fourth-level curve is the boundary between the filled and unfilled branches. \vadjust{\moveright 384pt \vbox to 0pt{\vss\hsize 4in \noindent Given the \id{snake} path scaled to unit length as shown above in \red{red}, the flow-snake path can be created with: \begin{smallcode} vardef rattle(expr level, a, b) = if level > 0: save s; path s; s = snake zscaled (b-a) shifted a; reverse rattle(level - 1, point 1 of s, a) & rattle(level - 1, point 1 of s, point 2 of s) & rattle(level - 1, point 2 of s, point 3 of s) & rattle(level - 1, point 3 of s, point 4 of s) & reverse rattle(level - 1, point 5 of s, point 4 of s) & reverse rattle(level - 1, point 6 of s, point 5 of s) & rattle(level - 1, point 6 of s, b) else: a -- b fi enddef; path S; S = rattle(4, origin, 360 right); \end{smallcode} }} \newpage \subsection{Fractal trees} \textsc{You can make a tree} with a vertical line segment, a scaling factor $0< r < 1$, and an angle $0° < \theta < 180°$. Start with the vertical line as the trunk, then make the first branch by scaling the trunk by $r$, rotating it $+\theta$, and moving it to the top of the trunk; make the second in the same way but rotate it by $-\theta$. Then repeat using each branch as a new trunk.\mpic{-114pt}{rec-simple-tree} And stop after enough levels. This can be implemented easily in \MP, but requires a slightly different technique. There is no simple way to represent the tree as a single \ because a path cannot have branches, so you need to draw each segment separately instead of trying to join them up. Compare this to the \mpl{rattle} routine on the page before. \begin{code} vardef make_tree(expr level, bar) = draw bar; if level > 0: for t=-theta, theta: make_tree(level - 1, bar shifted - point 0 of bar scaled r rotated t shifted point 1 of bar); endfor fi enddef; \end{code} To combine several such trees in a drawing either move the initial \id{bar} path, or capture the tree as a \ using \mpl{image(make_tree(...))}, like so: \begin{code} picture T[]; numeric r, theta; r = 0.58; theta = 60; T1 = image( make_tree(3, origin -- 100 up); ); % update r and theta... r := 0.75; theta := 14; T2 = image( make_tree(10, origin -- 100 up); ); draw T1 shifted 32 up; draw T2 shifted 128 right; \end{code} Notice that $r$ and $\theta$ are treated as global constants. You could pass them to the \mpl{make_tree} routine instead. Notice also that the smaller tree only has three levels, but the larger one has 10. And that the labels were omitted. \newpage \subsubsection{More fractal vegetation} \textsc{If you are more interested} in the visual aspect of your tree than the mathematical, you can tweak the \mpl{make_tree} routine a bit.\mpic{-12pt}{rec-general-tree} \begin{smallcode}[xleftmargin=0pt] vardef make_tree(expr bar) = save a; numeric a; a = abs(point 1 of bar - point 0 of bar); cutdraw bar withpen pencircle scaled 1.2(1/8 a) withcolor background; cutdraw bar withpen pencircle scaled (1/8 a) withcolor 1/256(57, 35, 32); if a > leaf: save s; pair s; s = 1/32 a * r * unitvector(direction 1 of bar) rotated 90; make_tree(bar shifted - point 0 of bar shifted s scaled r rotated theta shifted point 1 of bar); make_tree(bar shifted - point 0 of bar shifted -s scaled r rotated -theta shifted point 1 of bar); else: draw point 1 of bar withpen pencircle scaled 1 withcolor 2/3 green; fi enddef; beginfig(1); numeric leaf, r, theta; r = 0.75; theta = 14; leaf = 3; make_tree(origin -- 100 up); endfig; \end{smallcode} \begin{itemize} \item The recursion is controlled by measuring the length of the branches instead of using a \id{level} parameter. \item Each branch is drawn with a pen scaled to $\frac18$ of its length using \mpl{cutdraw}, and outlined so you can see the crossings. \item Each branch is moved slightly left or right with $s$ to make the joins neater. \item Tiny green leaves are added on the ends of each branch. \end{itemize} \newpage \subsubsection{Randomized recursive plants} \vskip-\baselineskip \noindent\hbox to \linewidth{\includegraphics{rec-general-tree-deviate}\hss} \noindent \textsc{To get plants that look more natural} you can introduce some random factors. Strictly these are not fractal because they are not self-similar. The only change from the previous \mpl{make_tree} is to replace \mpl{scaled r rotated theta} with \begin{smallcode}[xleftmargin=0pt] scaled (r + 1/16 normaldeviate) rotated (theta + 8 normaldeviate) \end{smallcode} The bush is similar, except that it splits into four branches at each step instead of two and only the lengths randomized.\mwpic{-96pt}{rec-bush} The colouring was a happy accident. \begin{smallcode}[xleftmargin=0pt, xrightmargin=-100pt] input colorbrewer-rgb vardef bush(expr start, aim, level, limit) = save s, target; numeric s; pair target; s = level / limit; for a = -32, -8, 8, 16: target = aim scaled ((32 + 16 normaldeviate) * s) rotated a shifted start; draw start -- target withpen pencircle scaled s withcolor BrBG[limit][limit-level]; if level > 1: bush(target, aim rotated a, level - 1, limit); fi endfor enddef; beginfig(1); bush(origin, dir 80, 6, 8); endfig; \end{smallcode} \newpage \subsection{Penrose tilings} \textsc{Recursion is useful} for generating non-periodic tilings,% \vadjust{\moveright5.5in\vbox to 0pt{\kern-8pt \begin{smallcode} % golden ratio constant numeric psi; psi = (sqrt 5 - 1) / 2; % inflating tall shape makes two others vardef inflate_tall(expr level, a, b, c) = if level = 0: draw a--b--c withpen pencircle scaled 1/8; else: save d; pair d; d = psi[b,a]; inflate_tall(level - 1, d, c, a); inflate_wide(level - 1, c, d, b); fi enddef; % inflating wide makes three vardef inflate_wide(expr level, a, b, c) = if level = 0: draw a--b--c withpen pencircle scaled 1/8; else: save d, e; pair d, e; d = psi[a,b]; e = psi[a,c]; inflate_tall(level - 1, d, e, b); inflate_wide(level - 1, e, d, a); inflate_wide(level - 1, c, e, b); fi enddef; % start with a tall triangle with apex at origin pair a, b, c; b = origin; c = (sind(18), sind(72)) scaled 800; a = (-xpart c, ypart c); % make an inflated "wedge" picture P; P = image(inflate_tall(7, a, b, c)); % then exploit the five-fold symmetry to make the picture for t = 0 upto 9: draw P if odd t: reflectedabout(b, c) fi rotated 72t; endfor; \end{smallcode} \qquad\hey \textit{\small Colouring the tiling is left as an exercise for the reader.}\par\vss}} like those discovered in the 1970s by the British polymath Sir Roger Penrose. $$\includegraphics[width=\textwidth]{penrose-P3.pdf}$$ By definition, there is no periodic unit to repeat; but there are well-known expansion rules to split each shape in the tiling into smaller congruent copies. So you can start with a single large shape and apply the rules recursively to make the tiling. The tiling above is made from two rhombus shapes, but each of these shapes can be split in half into two triangles, and the expansion process actually works on these: $$\includegraphics{penrose-stages.pdf}$$ \vbox to 0pt{\noindent Each expansion of half the thick rhombus, produces two more thick halves and one thin half; each expansion of half the thin rhombus produces a thick half and a thin half. No other shapes are produced, so the recursive process can be repeated indefinitely. At the desired lowest level the triangles are patched back into rhombus shapes simply by \textit{not} drawing the edges shown with dots.\par\vss} \newpage \subsection{Pinwheel tiling} \textsc{Another non-periodic tiling} is the so-called pinwheel tiling, devised in 1994 by Charles Radin, based on this dissection by John Conway.\mpic{-22pt}{pinwheel} $$\includegraphics{conway.pdf}$$ Starting with a triangle of this shape, the tiling recursively divides into five smaller copies of itself. The colouring is passed down each level but only used on the lowest. \begin{smallcode} input colorbrewer-rgb vardef pinwheel(expr level, a, b, c, s) = if level = 0: fill a--b--c--cycle withcolor s; draw a--b--c--cycle withpen pencircle scaled 1/8 withcolor white; else: save d, e, f, g; pair d, e, f, g; d = 2/5[b, c]; e = 4/5[b,c]; f = 1/2[e, a]; g = 1/2[a, b]; pinwheel(level - 1, e, a, c, Blues 9 4); pinwheel(level - 1, f, g, a, Blues 9 3); pinwheel(level - 1, f, g, e, Blues 9 2); pinwheel(level - 1, d, e, g, Blues 9 5); pinwheel(level - 1, d, b, g, Blues 9 6); fi enddef; beginfig(1); pinwheel(5, origin, 200 right, 100 up, ""); pinwheel(5, (200,100), 100 up, 200 right, ""); endfig; \end{smallcode} Notice that to make the dissection work, it is important to pass the three \ arguments in the right order. \newpage \tableofcontents \newpage \section*{To do...} - angle marks, including curved angle marks - drawing knots, double lines, ropes - decorating lines - the eye, hand - physics diagrams, pendulum, indicating movement and vibration - examining a glyph - all sorts of arrow, arrows between arrows, arrows next to a path (handles) - faking 3d - functions, def, vardef, recursion, primarydef etc, of syntax, expr suffix text - four box model charts - Tufte charts - Venn diagrams - tour of the plain format \end{document}