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
path 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
path 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
:
path Arc(pair c, real r, real angle1, real angle2, int n=400);
An ellipse can be drawn with the routine
path 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 p);
p
.
If p
is cyclic, this is the same as the number of nodes in p
.
int size(path p);
p
.
If p
is cyclic, this is the same as length(p)
.
pair point(path p, int t);
p
is cyclic, return the coordinates of node t
mod
length(p)
. Otherwise, return the coordinates of node t
,
unless t
< 0 (in which case point(0)
is returned) or
t
> 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-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 p, int t, int sign=0);
sign < 0
, the direction (as a pair) of the incoming tangent
to path p
at node t
is returned; if sign > 0
, the
direction of the outgoing tangent is returned. If sign=0
, the
mean of these two directions is returned. If p
contains only one
point, (0,0)
is returned.
pair dir(path p, real t);
p
at the point
between node floor(t)
and floor(t)+1
corresponding to the
cubic spline parameter t-floor(t)
(see Bezier).
If p
contains only one point, (0,0)
is returned.
pair precontrol(path p, int t);
p
at node t
.
pair precontrol(path p, real t);
p
at parameter t
.
pair postcontrol(path p, int t);
p
at node t
.
pair postcontrol(path p, real t);
p
at parameter t
.
real arclength(path p);
p
represents.
real arctime(path p, real L);
point(path p, real t)
, at which the
cumulative arclength (measured from the beginning of the path) equals L
.
real dirtime(path p, pair z);
point(path, real)
, at which the tangent
to the path has the direction of pair z
, or -1 if this never happens.
real reltime(path p, real l);
p
at the relative fraction l
of
its arclength.
pair relpoint(path p, real l);
p
at the relative fraction l
of its
arclength.
pair midpoint(path p);
p
at half of its arclength.
path reverse(path p);
p
.
path subpath(path p, int a, int b);
p
running from node a
to node b
.
If a
< b
, the direction of the subpath is reversed.
path subpath(path p, real a, real b);
p
running from path time a
to path
time b
, in the sense of point(path, real)
. If a
<
b
, the direction of the subpath is reversed.
real[] intersect(path p, path q, real fuzz=0);
p
and q
have at least one intersection point, return a
real array of length 2 containing the 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 a real array of length 0.
pair intersectionpoint(path p, path q, real fuzz=0);
point(p,intersect(p,q,fuzz)[0])
.
pair[] intersectionpoints(path p, path q);
p
and q
.
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 { 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[] p);
MetaPost buildcycle
command.
pair min(path p);
p
.
pair max(path p);
p
.
bool cyclic(path p);
true
iff path p
is cyclic
bool straight(path p, int i);
true
iff the segment of path p
between node
i
and node i+1
is straight.
int windingnumber(path p, pair z);
g
relative to the point
z
. The winding number is positive if the path encircles z
in the
counterclockwise direction.
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;