Next: , Previous: palette, Up: Base modules


7.27 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 with 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);
guide3 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);
unitcircle3.png 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)..cycle;
filldraw(g,lightgrey);
dot(g,red);
draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle));
saddle.png 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 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)
The point (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)
The point (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)
The point (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)
This projects from three to two dimensions using the view as seen at a point infinitely far away in the direction 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)
This is equivalent to orthographic((x,y,z),up).
perspective(triple camera, triple up=Z, triple target=O)
This projects from three to two dimensions, taking account of perspective, as seen from the location camera looking at target, orienting the camera so that, if possible, the vector up points upwards.
perspective(real x, real y, real z, triple up=Z, triple target=O)
This is equivalent to 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);

Three-dimensional objects may be transformed with one of the following built-in transform3 types:

shift(triple v)
translates by the triple v;
xscale3(real x)
scales by x in the x direction;
yscale3(real y)
scales by y in the y direction;
zscale3(real z)
scales by z in the z direction;
scale3(real s)
scales by s in the x, y, and z directions;
rotate(real angle, triple v)
rotates by angle in degrees about an axis v through the origin;
rotate(real angle, triple u, triple v)
rotates by angle in degrees about the axis u--v;
reflect(triple u, triple v, triple w)
reflects about the plane through 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 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);

planes.png

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);

join3.png

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.