Next: , Previous: light, Up: Base modules


7.22 graph3

This module implements three-dimensional versions of the functions in graph.asy. They work much like their two-dimensional counterparts, except that the user has to keep track of the three-dimensional axes limits (which in two dimension are stored in the picture) in a bbox3 bounding box. The function

bbox3 autolimits(picture pic=currentpicture, triple min, triple max);
can be used to determine “nice” values for the bounding box corners. A user-space bounding box that takes into account of the axes scalings for picture pic is returned by
bbox3 limits(picture pic=currentpicture, triple min, triple max);

To crop a bounding box to a given interval use:

void xlimits(bbox3 b, real min, real max);
void ylimits(bbox3 b, real min, real max);
void zlimits(bbox3 b, real min, real max);
void limits(bbox3 b, triple min, triple max);

To draw an x axis in three dimensions from triple min to triple max with ticks in the direction dir, use the routine

void xaxis(picture pic=currentpicture, Label L="", triple min, triple max,
           pen p=currentpen, ticks ticks=NoTicks, triple dir=Y,
           arrowbar arrow=None, bool put=Above,
           projection P=currentprojection, bool opposite=false);
To draw an x axis in three dimensions from triple min to triple (max,min.y,min.z) with ticks in the direction dir, use the routine
void xaxis(picture pic=currentpicture, Label L="", triple min, real max,
           pen p=currentpen, ticks ticks=NoTicks, triple dir=Y,
           arrowbar arrow=None, bool put=Above,
           projection P=currentprojection, bool opposite=false);
To draw an x axis in three dimensions using bbox3 b with ticks in the direction dir, use the routine
void xaxis(picture pic=currentpicture, Label L="", bool all=false,
           bbox3 b, pen p=currentpen, ticks ticks=NoTicks,
           triple dir=Y, arrowbar arrow=None, bool put=Above,
           projection P=currentprojection);
If all=true, also draw opposing edges of the three-dimensional bounding box. Analogous routines yaxis and zaxis can be used to draw y and z axes in three dimensions. There are also some convenient routines for drawing all three axis:
void axes(Label xlabel="$x$", Label ylabel="$y$", Label zlabel="$z$", 
          triple min, triple max, pen p=currentpen, arrowbar arrow=None,
          bool put=Below, projection P=currentprojection);

void axes(Label xlabel="$x$", Label ylabel="$y$", Label zlabel="$z$", 
          bbox3 b, pen p=currentpen, arrowbar arrow=None,
          bool put=Below, projection P=currentprojection);

Here is an example of a helix and bounding box axes with rotated tick and axis labels, using orthographic projection:

import graph3;

size(0,200);

currentprojection=orthographic(4,6,3);

real x(real t) {return cos(2pi*t);}
real y(real t) {return sin(2pi*t);}
real z(real t) {return t;}

defaultpen(overwrite(SuppressQuiet));

path3 p=graph(x,y,z,0,2.7,Spline);
bbox3 b=autolimits(min(p),max(p));
aspect(b,1,1,1);

xaxis(rotate(X)*"$x$",all=true,b,red,RightTicks(rotate(X)*Label,2,2));
yaxis(rotate(Y)*"$y$",all=true,b,red,RightTicks(rotate(Y)*Label,2,2));
zaxis("$z$",all=true,b,red,RightTicks);

draw(p,Arrow);

helix.png

The next example illustrates three-dimensional x, y, and z axes, with autoscaling of the upper z limit disabled:

import graph3;

size(0,200,IgnoreAspect);

currentprojection=perspective(5,2,2);

defaultpen(overwrite(SuppressQuiet));

scale(Linear,Linear,Log(automax=false));

bbox3 b=autolimits(Z,X+Y+30Z);

xaxis("$x$",b,red,RightTicks(2,2));
yaxis("$y$",b,red,RightTicks(2,2));
zaxis("$z$",b,red,RightTicks);

axis3.png

One can also place ticks along a general three-dimensional axis:

import graph3;

size(0,100);

path3 G=xscale3(1)*(yscale3(2)*unitcircle3);

axis(Label("C",align=Relative(5E)),G,
     LeftTicks(endlabel=false,8,end=false),
     ticklocate(0,360,new real(real v) {
		  path g=G;
		  path h=O--max(abs(max(G)),abs(min(G)))*dir(90,v);
		  return intersect(g,h).x;
		},perpendicular(G,Z)));
generalaxis3.png

Surface plots of matrices and functions over the region box(a,b) in the XY plane are also implemented:

picture surface(real[][] f, pair a, pair b,
                pen surfacepen=lightgray, pen meshpen=nullpen,
                light light=currentlight, projection P=currentprojection);
picture surface(triple[][] f, pen surfacepen=lightgray, pen meshpen=nullpen,
                light light=currentlight, projection P=currentprojection);
picture surface(real f(pair z), int nsub=1, pair a, pair b, int nx=nmesh,
                int ny=nx, pen surfacepen=lightgray, pen meshpen=nullpen,
                light light=currentlight, projection P=currentprojection);
A parametric surface for a function f(u,v) over the parameter space box(a,b) may be drawn with
picture surface(triple f(pair z), int nsub=1, pair a, pair b, int nu=nmesh,
                int nv=nu, pen surfacepen=lightgray, pen meshpen=nullpen,
                light light=currentlight, projection P=currentprojection);
as illustrated in the example parametricsurface.asy. The optional argument nsub allows one to subsample the function nsub times along the cell edges. However, smoother Gouraud shading is used for lighting effects if nsub=1. Lighting can be disabled by setting light=O, as in this example of a Gaussian surface subsampled 4 times:
import graph3;

size(200,0);

currentprojection=perspective(5,4,2);

real f(pair z) {return 0.5+exp(-abs(z)^2);}

draw((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle3);

draw(arc(0.12Z,0.2,90,60,90,15),ArcArrow);

picture surface=surface(f,nsub=4,(-1,-1),(1,1),nx=10,light=O);
  
bbox3 b=limits(O,1.75(1,1,1));

xaxis(Label("$x$",1),b,red,Arrow);
yaxis(Label("$y$",1),b,red,Arrow);
zaxis(Label("$z$",1),b,red,Arrow);

label("$O$",(0,0,0),S,red);
  
add(surface);

surface.png Surface lighting is illustrated in the example files parametricsurface.asy and sinc.asy. A mesh can be drawn without solid fills by specifying nullpen for the surfacepen. A mesh is always drawn in the absence of lighting, unless meshpen=invisible.