Next: Pens, Previous: Data types, Up: Programming
guideThis is like a path except that the computation of the cubic spline is deferred until drawing time (when it is resolved into a path); this allows two guides with free endpoint conditions to be joined together smoothly. The solid curve in the following example is built up incrementally as a guide, but only resolved at drawing time:
size(200);
real mexican(real x) {return (1-8x^2)*exp(-(4x^2));}
int n=30;
real a=1.5;
real width=2a/n;
guide hat;
path solved;
for(int i=0; i < n; ++i) {
real t=-a+i*width;
pair z=(t,mexican(t));
hat=hat..z;
solved=solved..z;
}
draw(hat);
dot(hat,red);
draw(solved,dashed);
pathThe implicit initializer for paths and guides is nullpath,
which is useful for building up a path within a loop.
The routine circle(pair c, real r), which returns a Bezier curve
approximating a circle of radius r centered on c,
is based on unitcircle:
path circle(pair c, real r)
{
return shift(c)*scale(r)*unitcircle;
}
If high accuracy is needed, a true circle may be produced with this
routine, defined in the module graph.asy:
path Circle(pair c, real r, int n=400);
A circular arc consistent with the above approximation centered on
c with radius r from angle1 to angle2
degrees, drawing counterclockwise if angle2 >= angle1, can be
constructed with
guide arc(pair c, real r, real angle1, real angle2);
If r < 0, the complementary arc of radius |r| is constructed.
For convenience, an arc centered at c from pair z1 to
z2 (assuming |z2-c|=|z1-c|) in the direction CCW
(counter-clockwise) or CW (clockwise) may also be constructed with
guide arc(pair c, explicit pair z1, explicit pair z2,
bool direction=CCW)
If high accuracy is needed, a true arc may be produced with this
routine, defined in the module graph.asy:
guide Arc(pair c, real r, real angle1, real angle2,
int n=400);
An ellipse can be drawn with the routine
guide ellipse(pair c, real a, real b)
{
return shift(c)*xscale(a)*yscale(b)*unitcircle;
}
Here is an example of all five path connectors discussed in Tutorial:
size(300,0);
pair[] z=new pair[10];
z[0]=(0,100); z[1]=(50,0); z[2]=(180,0);
for(int n=3; n <= 9; ++n)
z[n]=z[n-3]+(200,0);
path p=z[0]..z[1]---z[2]::{up}z[3]
&z[3]..z[4]--z[5]::{up}z[6]
&z[6]::z[7]---z[8]..{up}z[9];
draw(p,grey+linewidth(4mm));
dot(z);
Here are some useful functions for paths:
int length(path);int size(path);pair point(path p, int n);p is cyclic, return the coordinates of node n mod
length(p). Otherwise, return the coordinates of node n,
unless n < 0 (in which case point(0) is returned) or
n > length(p) (in which case point(length(p))
is returned).
pair point(path p, real t);floor(t)
and floor(t)+1 corresponding to the cubic spline parameter
t=t-floor(t) (see Bezier). If t lies outside the range
[0,length(p)], it is first reduced modulo length(p)
in the case where p is cyclic or else converted to the corresponding
endpoint of p.
pair dir(path, int n);n. If the path contains only one point, (0,0) is returned.
pair dir(path, real t);floor(t) and floor(t)+1 corresponding to the
cubic spline parameter t=t-floor(t) (see Bezier).
If the path contains only one point, (0,0) is returned.
pair precontrol(path, int n);n.
pair precontrol(path, real t);t.
pair postcontrol(path, int n);n.
pair postcontrol(path, real t);t.
real arclength(path);real arctime(path, real L);point(path, real), at which the
cumulative arclength (measured from the beginning of the path) equals L.
real dirtime(path, pair z);point(path, real), at which the tangent
to the path has the direction of pair z, or -1 if this never happens.
path reverse(path p);path subpath(path p, int n, int m);n to node m.
If n < m, the direction of the subpath is reversed.
path subpath(path p, real a, real b);a to path time b,
in the sense of point(path, real). If a < b, the
direction of the subpath is reversed.
pair intersect(path p, path q, real fuzz=0);p and q have at least one intersection point, return a
pair of times representing the respective path times along
p and q, in the sense of point(path, real), for
one such intersection point (as chosen by the algorithm described on
page 137 of The MetaFontbook).
Perform the computations to the absolute error specified by fuzz,
or, if fuzz is 0, to machine precision. If the paths do not
intersect, return the pair (-1,-1).
pair intersectionpoint(path p, path q, real fuzz=0);point(p,intersect(p,q,fuzz).x), the actual point
of intersection.
slice firstcut(path p, path q);p before and after the first intersection
of p with path q as a structure slice (if no such
intersection exists, the entire path is considered to be `before' the
intersection):
struct slice {
public path before,after;
}
Note that firstcut.after plays the role of the
MetaPost cutbefore command.
slice lastcut(path p, path q);p before and after the last intersection
of p with path q as a slice (if no such
intersection exists, the entire path is considered to be `after' the
intersection).
Note that lastcut.before plays the role of the
MetaPost cutafter command.
path buildcycle(... path[] g);MetaPost buildcycle command.
pair min(path);pair max(path);bool cyclic(path);true iff path is cyclic
bool straight(path, int i);true iff the segment between node i and node i+1
is straight.
bool inside(path g, pair z, pen p=currentpen);true iff the point z is inside the region bounded
by the cyclic path g according to the fillrule of pen p
(see fillrule).
We point out an efficiency distinction in the use of guides and paths:
guide g; for(int i=0; i < 10; ++i) g=g--(i,i); path p=g;
runs in linear time, whereas
path p; for(int i=0; i < 10; ++i) p=p--(i,i);
runs in quadratic time, as the entire path up to that point is copied at each step of the iteration.
As a technical detail we note that a direction specifier given to
nullpath modifies the node on the other side: the paths
a..{up}nullpath..b;
c..nullpath{up}..d;
e..{up}nullpath{down}..f;
are respectively equivalent to
a..nullpath..{up}b;
c{up}..nullpath..d;
e{down}..nullpath..{up}f;