Next: light, Previous: palette, Up: Base modules
threeThis module fully extends the notion of guides and paths in Asymptote
to three dimensions, introducing the new types guide3 and path3,
along with a three-dimensional cycle specifier cycle3, tension operator
tension3, and curl operator curl3. Just as in two
dimensions, the nodes within a guide3 can be qualified with
these operators and also with explicit directions and control points (using
braces and controls, respectively). This generalization of John
Hobby's spline algorithm is shape-invariant under three-dimensional rotation,
scaling, and shifting, and reduces in the planar case to the
two-dimensional algorithm used in Asymptote, MetaPost,
and MetaFont.
For example, a unit circle in the XY plane may be filled and drawn like this:
import three; size(100,0); guide3 g=(1,0,0)..(0,1,0)..(-1,0,0)..(0,-1,0)..cycle3; filldraw(g,lightgrey); draw(O--Z,red+dashed,BeginBar,Arrow); draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle3)); dot(g,red);
and then distorted into a saddle:
import three; size(100,0); guide3 g=(1,0,0)..(0,1,1)..(-1,0,0)..(0,-1,1)..cycle3; filldraw(g,lightgrey); dot(g,red); draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle3));
Here O is the triple (0,0,0) and X,
Y, and Z are the triples (1,0,0),
(0,1,0), and (0,0,1), respectively.
A general circle can be drawn perpendicular to the direction
normal with the routine
path3 circle(triple c, real r, triple normal=Z);
A circular arc centered at c with radius r from
c+r*dir(theta1,phi1) to c+r*dir(theta2,phi2),
drawing counterclockwise relative to the normal vector
cross(dir(theta1,phi1),dir(theta2,phi2)) if theta2 > theta1
or if theta2 == theta1 and phi2 >= phi1, can be constructed with
path3 arc(triple c, real r, real theta1, real phi1, real theta2, real phi2,
triple normal=O);
The normal must be explicitly specified if c and the endpoints
are colinear. If r < 0, the complementary arc of radius
|r| is constructed.
For convenience, an arc centered at c from triple v1 to
v2 (assuming |v2-c|=|v1-c|) in the direction CCW
(counter-clockwise) or CW (clockwise) may also be constructed with
path3 arc(triple c, triple v1, triple v2, triple normal=O,
bool direction=CCW);
When high accuracy is needed, the routines Circle and
Arc defined in graph3 may be used instead.
See surface for an example of a three-dimensional circular arc.
A representation of the plane passing through point O with normal cross(u,v) is given by
path3 plane(triple u, triple v, triple O=O);A three-dimensional box with opposite vertices at triples
v1
and v2 may be drawn with the function
guide3[] box(triple v1, triple v2);For example, a unit cube is predefined as
guide3[] unitcube=box((0,0,0),(1,1,1));
These projections to two dimensions are predefined:
obliqueoblique(real angle)(x,y,z) is projected to (x-0.5z,y-0.5z).
If an optional real argument is given, the
negative z axis is drawn at this angle in degrees.
The projection obliqueZ is a synonym for oblique.
obliqueXobliqueX(real angle)(x,y,z) is projected to (y-0.5x,z-0.5x).
If an optional real argument is given, the
negative x axis is drawn at this angle in degrees.
obliqueYobliqueY(real angle)(x,y,z) is projected to (x+0.5y,z+0.5y).
If an optional real argument is given, the
positive y axis is drawn at this angle in degrees.
orthographic(triple camera, triple up=Z)orthographic(real x, real y, real z, triple up=Z)camera or (x,y,z), respectively,
orienting the camera so that, if possible, the vector up points
upwards. Parallel lines are projected to parallel lines.
perspective(triple camera, triple up=Z)perspective(real x, real y, real z, triple up=Z)camera or (x,y,z), respectively,
orienting the camera so that, if possible, the vector up points
upwards.
The default projection, currentprojection, is initially set to
perspective(5,4,2).
It is occasionally useful to be able to invert a projection, sending
a pair z onto the plane perpendicular to normal and passing
through point:
triple invert(pair z, triple normal, triple point,
projection P=currentprojection);
Three-dimensional objects may be transformed with one of the following
built-in transform3 types:
shift(triple v)v;
xscale3(real x)x in the x direction;
yscale3(real y)y in the y direction;
zscale3(real z)z in the z direction;
scale3(real s)s in the x, y, and z directions;
rotate(real angle, triple v)angle in degrees about an axis v through the origin;
rotate(real angle, triple u, triple v)angle in degrees about the axis u--v;
reflect(triple u, triple v, triple w)u, v, and w.
Three-dimensional versions of the path functions length,
size, point, dir, precontrol, postcontrol, arclength, arctime, reverse, subpath,
intersect, intersectionpoint,
min, max, cyclic, and straight are also
defined in the module three.
Planar hidden surface removal is implemented with a binary space
partition and picture clipping. A planar path is first converted to a
struct face derived from picture. A face may be given to
a drawing routine in place of any picture argument. An array
of such faces may then be drawn, removing hidden surfaces:
void add(picture pic=currentpicture, face[] faces,
projection P=currentprojection);
Here is an example showing three orthogonal intersecting planes:
size(6cm,0); import math; import three; real u=2.5; real v=1; currentprojection=oblique; path3 y=plane((2u,0,0),(0,2v,0),(-u,-v,0)); path3 l=rotate(90,Z)*rotate(90,Y)*y; path3 g=rotate(90,X)*rotate(90,Y)*y; face[] faces; filldraw(faces.push(y),y,yellow); filldraw(faces.push(l),l,lightgrey); filldraw(faces.push(g),g,green); add(faces);
Here is an example showing all five 3D path connectors:
import graph3;
size(0,175);
currentprojection=orthographic(500,-500,500);
triple[] z=new triple[10];
z[0]=(0,100,0); z[1]=(50,0,0); z[2]=(180,0,0);
for(int n=3; n <= 9; ++n)
z[n]=z[n-3]+(200,0,0);
path3 p=z[0]..z[1]---z[2]::{Y}z[3]
&z[3]..z[4]--z[5]::{Y}z[6]
&z[6]::z[7]---z[8]..{Y}z[9];
draw(p,grey+linewidth(4mm));
bbox3 b=limits(O,(700,200,100));
xaxis(Label("$x$",1),b,red,Arrow);
yaxis(Label("$y$",1),b,red,Arrow);
zaxis(Label("$z$",1),b,red,Arrow);
dot(z);
A three-dimensional bounding box structure is returned by calling
bbox3(triple min, triple max) with the opposite corners
min and max. This can be used to adjust the aspect ratio
(see the example helix.asy):
void aspect(picture pic=currentpicture, bbox3 b,
real x=0, real y=0, real z=0);
Further three-dimensional examples are provided in the files
near_earth.asy, conicurv.asy, and (in the animations
subdirectory) cube.asy.