three
This 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);
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));
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:
oblique
(x,y,z)
is projected to (x-0.5z,y-0.5z)
.
If an optional real argument is given to oblique
, the
negative z axis is drawn at this angle in degrees measured
counterclockwise from the positive x axis.
orthographic(triple camera)
orthographic(real x, real y, real z)
camera
or (x,y,z)
, respectively.
Parallel lines are projected to parallel lines.
perspective(triple camera)
perspective(real x, real y, real z)
camera
or (x,y,z)
, respectively.
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
.