asymptote: contour

 
 8.36 'contour'
 ==============
 
 This package draws contour lines.  To construct contours corresponding
 to the values in a real array 'c' for a function 'f' on 'box(a,b)', use
 the routine
 guide[][] contour(real f(real, real), pair a, pair b,
                   real[] c, int nx=ngraph, int ny=nx,
                   interpolate join=operator --, int subsample=1);
 The integers 'nx' and 'ny' define the resolution.  The default
 resolution, 'ngraph x ngraph' (here 'ngraph' defaults to '100') can be
 increased for greater accuracy.  The default interpolation operator is
 'operator --' (linear).  Spline interpolation ('operator ..') may
 produce smoother contours but it can also lead to overshooting.  The
 'subsample' parameter indicates the number of interior points that
 should be used to sample contours within each '1 x 1' box; the default
 value of '1' is usually sufficient.
 
    To construct contours for an array of data values on a uniform
 two-dimensional lattice on 'box(a,b)', use
 guide[][] contour(real[][] f, pair a, pair b, real[] c,
                   interpolate join=operator --, int subsample=1);
 
    To construct contours for an array of data values on a nonoverlapping
 regular mesh specified by the two-dimensional array 'z',
 guide[][] contour(pair[][] z, real[][] f, real[] c,
                   interpolate join=operator --, int subsample=1);
 
 To construct contours for an array of values 'f' specified at
 irregularly positioned points 'z', use the routine
 guide[][] contour(pair[] z, real[] f, real[] c, interpolate join=operator --);
 The contours themselves can be drawn with one of the routines
 void draw(picture pic=currentpicture, Label[] L=new Label[],
           guide[][] g, pen p=currentpen);
 
 void draw(picture pic=currentpicture, Label[] L=new Label[],
           guide[][] g, pen[] p);
 
    The following simple example draws the contour at value '1' for the
 function z=x^2+y^2, which is a unit circle:
 import contour;
 size(75);
 
 real f(real a, real b) {return a^2+b^2;}
 draw(contour(f,(-1,-1),(1,1),new real[] {1}));
 
                              [onecontour]
 
    The next example draws and labels multiple contours for the function
 z=x^2-y^2 with the resolution '100 x 100', using a dashed pen for
 negative contours and a solid pen for positive (and zero) contours:
 import contour;
 
 size(200);
 
 real f(real x, real y) {return x^2-y^2;}
 int n=10;
 real[] c=new real[n];
 for(int i=0; i < n; ++i) c[i]=(i-n/2)/n;
 
 pen[] p=sequence(new pen(int i) {
     return (c[i] >= 0 ? solid : dashed)+fontsize(6pt);
   },c.length);
 
 Label[] Labels=sequence(new Label(int i) {
     return Label(c[i] != 0 ? (string) c[i] : "",Relative(unitrand()),(0,0),
                  UnFill(1bp));
   },c.length);
 
 draw(Labels,contour(f,(-1,-1),(1,1),c),p);
 
                             [multicontour]
 
    The next example illustrates how contour lines can be drawn on color
 density images:
 import graph;
 import palette;
 import contour;
 
 size(10cm,10cm,IgnoreAspect);
 
 pair a=(0,0);
 pair b=(2pi,2pi);
 
 real f(real x, real y) {return cos(x)*sin(y);}
 
 int N=200;
 int Divs=10;
 int divs=2;
 
 defaultpen(1bp);
 pen Tickpen=black;
 pen tickpen=gray+0.5*linewidth(currentpen);
 pen[] Palette=BWRainbow();
 
 bounds range=image(f,Automatic,a,b,N,Palette);
 
 // Major contours
 
 real[] Cvals=uniform(range.min,range.max,Divs);
 draw(contour(f,a,b,Cvals,N,operator --),Tickpen);
 
 // Minor contours
 real[] cvals;
 for(int i=0; i < Cvals.length-1; ++i)
   cvals.append(uniform(Cvals[i],Cvals[i+1],divs)[1:divs]);
 draw(contour(f,a,b,cvals,N,operator --),tickpen);
 
 xaxis("$x$",BottomTop,LeftTicks,above=true);
 yaxis("$y$",LeftRight,RightTicks,above=true);
 
 palette("$f(x,y)$",range,point(NW)+(0,0.5),point(NE)+(0,1),Top,Palette,
         PaletteTicks(N=Divs,n=divs,Tickpen,tickpen));
 
                             [imagecontour]
 
    Finally, here is an example that illustrates the construction of
 contours from irregularly spaced data:
 import contour;
 
 size(200);
 
 int n=100;
 
 real f(real a, real b) {return a^2+b^2;}
 
 srand(1);
 
 real r() {return 1.1*(rand()/randMax*2-1);}
 
 pair[] points=new pair[n];
 real[] values=new real[n];
 
 for(int i=0; i < n; ++i) {
   points[i]=(r(),r());
   values[i]=f(points[i].x,points[i].y);
 }
 
 draw(contour(points,values,new real[]{0.25,0.5,1},operator ..),blue);
 
                           [irregularcontour]
 
    In the above example, the contours of irregularly spaced data are
 constructed by first creating a triangular mesh from an array 'z' of
 pairs:
 
 int[][] triangulate(pair[] z);
 
 size(200);
 int np=100;
 pair[] points;
 
 real r() {return 1.2*(rand()/randMax*2-1);}
 
 for(int i=0; i < np; ++i)
   points.push((r(),r()));
 
 int[][] trn=triangulate(points);
 
 for(int i=0; i < trn.length; ++i) {
   draw(points[trn[i][0]]--points[trn[i][1]]);
   draw(points[trn[i][1]]--points[trn[i][2]]);
   draw(points[trn[i][2]]--points[trn[i][0]]);
 }
 
 for(int i=0; i < np; ++i)
   dot(points[i],red);
 
                              [triangulate]
 
    The example 'Gouraudcontour.asy' illustrates how to produce color
 density images over such irregular triangular meshes.  'Asymptote' uses
 a robust version of Paul Bourke's Delaunay triangulation algorithm based
 on the public-domain exact arithmetic predicates written by Jonathan
 Shewchuk.