Next: light, Previous: palette, Up: Base modules
three
This module fully extends the notion of guides and paths in Asymptote
to three dimensions, introducing the new types guide3
and path3
.
Guides in three dimensions are specified with the same syntax as in two
dimensions but using triples (x,y,z)
in place of pairs (x,y)
for
the nodes and direction specifiers. 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); path3 g=(1,0,0)..(0,1,0)..(-1,0,0)..(0,-1,0)..cycle; filldraw(g,lightgrey); draw(O--Z,red+dashed,BeginBar,Arrow); draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle)); dot(g,red);
import three; size(100,0); path3 g=(1,0,0)..(0,1,1)..(-1,0,0)..(0,-1,1)..cycle; filldraw(g,lightgrey); draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle)); dot(g,red);
three
module defines O=(0,0,0)
,
X=(1,0,0)
, Y=(0,1,0)
, and Z=(0,0,1)
, along with a
unitcircle in the XY plane:
path3 unitcircle3=X..Y..-X..-Y..cycle;
A general (approximate) 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 GaussianSurface 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
path3[] box(triple v1, triple v2);For example, a unit cube is predefined as
path3[] unitcube=box((0,0,0),(1,1,1));
These projections to two dimensions are predefined:
oblique
oblique(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
.
obliqueX
obliqueX(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.
obliqueY
obliqueY(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)
unit(camera)
, orienting the camera
so that, if possible, the vector up
points upwards. Parallel
lines are projected to parallel lines.
orthographic(real x, real y, real z, triple up=Z)
orthographic((x,y,z),up)
.
perspective(triple camera, triple up=Z, triple target=O)
camera
looking at target
,
orienting the camera so that, if possible, the vector up
points upwards.
Projection of three-dimensional cubic Bezier splines is implemented
by approximating a two-dimensional nonuniform rational B-spline
(nurbs) with a two-dimensional Bezier curve containing
additional nodes and control points.
perspective(real x, real y, real z, triple up=Z, triple target=O)
perspective((x,y,z),up,target)
.
The default projection, currentprojection
, is initially set to
perspective(5,4,2)
.
A triple or path3 can be implicitly cast to a pair or path,
respectively, using currentprojection
. To use another
projection, call project(triple, projection P=currentprojection)
or
project(path, projection P=currentprojection)
.
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);
To project a Label onto the plane passing through point O
with
normal cross(u,v)
use the function
transform transform(triple u, triple v, triple O=O, 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;
scale(real x, real y, real z)
x
in the x direction,
by y
in the y direction, and by z
in the z
direction;
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
, intersections
, intersectionpoint
,
intersectionpoints
, 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
structure 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
.