// A group of 3 or 4 points.
private struct object
{
bool active;
weighted[] pts;
}
// Return contour vertices for a 3D data array.
// z: three-dimensional array of nonoverlapping mesh points
// f: three-dimensional arrays of real data values
// midpoint: optional array containing estimate of f at midpoint values
vertex[][] contour3(triple[][][] v, real[][][] f,
real[][][] midpoint=new real[][][],
projection P=currentprojection)
{
int nx=v.length-1;
if(nx == 0)
abort("array v must have length >= 2");
int ny=v[0].length-1;
if(ny == 0)
abort("array v[0] must have length >= 2");
int nz=v[0][0].length-1;
if(nz == 0)
abort("array v[0][0] must have length >= 2");
// go over region a rectangle at a time
for(int i=0; i < nx; ++i) {
triple[][] vi=v[i];
triple[][] vp=v[i+1];
real[][] fi=f[i];
real[][] fp=f[i+1];
int i2=2i;
int i2p1=i2+1;
int i2p2=i2+2;
for(int j=0; j < ny; ++j) {
triple[] vij=vi[j];
triple[] vpj=vp[j];
triple[] vip=vi[j+1];
triple[] vpp=vp[j+1];
real[] fij=fi[j];
real[] fpj=fp[j];
real[] fip=fi[j+1];
real[] fpp=fp[j+1];
int j2=2j;
int j2p1=j2+1;
int j2p2=j2+2;
for(int k=0; k < nz; ++k) {
// vertex values
real vdat0=fij[k];
real vdat1=fij[k+1];
real vdat2=fip[k];
real vdat3=fip[k+1];
real vdat4=fpj[k];
real vdat5=fpj[k+1];
real vdat6=fpp[k];
real vdat7=fpp[k+1];
real angle(triple u, triple v) {
real Dot=-dot(u,v);
return Dot > 1 ? 0 : Dot < -1 ? pi : acos(Dot);
}
real angle0=angle(vec1,vec2);
real angle1=angle(vec2,vec0);
pts[0].normal=normal*angle0;
pts[1].normal=normal*angle1;
pts[2].normal=normal*(pi-angle0-angle1);
}
// Checks if a pyramid contains a contour object.
object checkpyr(triple v0, triple v1, triple v2, triple v3,
real d0, real d1, real d2, real d3,
int[] c0, int[] c1, int[] c2, int[] c3) {
object obj;
real a0=abs(d0);
real a1=abs(d1);
real a2=abs(d2);
real a3=abs(d3);
// Return contour vertices for a 3D data array on a uniform lattice.
// f: three-dimensional arrays of real data values
// midpoint: optional array containing estimate of f at midpoint values
// a,b: diagonally opposite points of rectangular parellelpiped domain
vertex[][] contour3(real[][][] f, real[][][] midpoint=new real[][][],
triple a, triple b, projection P=currentprojection)
{
int nx=f.length-1;
if(nx == 0)
abort("array f must have length >= 2");
int ny=f[0].length-1;
if(ny == 0)
abort("array f[0] must have length >= 2");
int nz=f[0][0].length-1;
if(nz == 0)
abort("array f[0][0] must have length >= 2");
triple[][][] v=new triple[nx+1][ny+1][nz+1];
for(int i=0; i <= nx; ++i) {
real xi=interp(a.x,b.x,i/nx);
triple[][] vi=v[i];
for(int j=0; j <= ny; ++j) {
triple[] vij=v[i][j];
real yj=interp(a.y,b.y,j/ny);
for(int k=0; k <= nz; ++k) {
vij[k]=(xi,yj,interp(a.z,b.z,k/nz));
}
}
}
return contour3(v,f,midpoint,P);
}
// Return contour vertices for a 3D data array, using a pyramid mesh
// f: real-valued function of three real variables
// a,b: diagonally opposite points of rectangular parellelpiped domain
// nx,ny,nz number of subdivisions in x, y, and z directions
vertex[][] contour3(real f(real, real, real), triple a, triple b,
int nx=nmesh, int ny=nx, int nz=nx,
projection P=currentprojection)
{
// evaluate function at points and midpoints
real[][][] dat=new real[nx+1][ny+1][nz+1];
real[][][] midpoint=new real[2nx+2][2ny+2][2nz+1];
for(int i=0; i <= nx; ++i) {
real x=interp(a.x,b.x,i/nx);
real x2=interp(a.x,b.x,(i+0.5)/nx);
real[][] dati=dat[i];
real[][] midpointi2=midpoint[2i];
real[][] midpointi2p1=midpoint[2i+1];
for(int j=0; j <= ny; ++j) {
real y=interp(a.y,b.y,j/ny);
real y2=interp(a.y,b.y,(j+0.5)/ny);
real datij[]=dati[j];
real[] midpointi2p1j2=midpointi2p1[2j];
real[] midpointi2p1j2p1=midpointi2p1[2j+1];
real[] midpointi2j2p1=midpointi2[2j+1];
for(int k=0; k <= nz; ++k) {
real z=interp(a.z,b.z,k/nz);
real z2=interp(a.z,b.z,(k+0.5)/nz);
datij[k]=f(x,y,z);
if(i == nx || j == ny || k == nz) continue;
int k2p1=2k+1;
midpointi2p1j2p1[2k]=f(x2,y2,z);
midpointi2p1j2p1[k2p1]=f(x2,y2,z2);
midpointi2p1j2[k2p1]=f(x2,y,z2);
midpointi2j2p1[k2p1]=f(x,y2,z2);
if(i == 0) midpoint[2nx][2j+1][k2p1]=f(b.x,y2,z2);
if(j == 0) midpointi2p1[2ny][k2p1]=f(x2,b.y,z2);
if(k == 0) midpointi2p1j2p1[2nz]=f(x2,y2,b.z);
}
}
}
return contour3(dat,midpoint,a,b,P);
}
// Construct contour surface for a 3D data array, using a pyramid mesh.
surface surface(vertex[][] g)
{
surface s=surface(g.length);
for(int i=0; i < g.length; ++i) {
vertex[] cur=g[i];
s.s[i]=patch(cur[0].v--cur[1].v--cur[2].v--cycle);
}
return s;
}