Next: Pens, Previous: Data types, Up: Programming
guide
This 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);
path
The 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;