/*ScianVisIso.c Routines for the isosurface visualization object Eric Pepke May 25, 1991 */ #include "Scian.h" #include "ScianTypes.h" #include "ScianArrays.h" #include "ScianWindows.h" #include "ScianTextBoxes.h" #include "ScianObjWindows.h" #include "ScianIcons.h" #include "ScianColors.h" #include "ScianControls.h" #include "ScianButtons.h" #include "ScianTitleBoxes.h" #include "ScianLists.h" #include "ScianSpaces.h" #include "ScianSliders.h" #include "ScianIDs.h" #include "ScianDatasets.h" #include "ScianErrors.h" #include "ScianVisObjects.h" #include "ScianVisWindows.h" #include "ScianStyle.h" #include "ScianPictures.h" #include "ScianDepend.h" #include "ScianTimers.h" #include "ScianScales.h" #include "ScianTemplates.h" #include "ScianTemplateHelper.h" #include "ScianEvents.h" #include "ScianScripts.h" #include "ScianFixedClasses.h" ObjPtr isoClass; /*Specifier for a part of the hex, which can be linked into a list*/ typedef struct part { struct part *next; /*Next part in the list*/ int coords[3]; /*Coordinates of the part. For a vertex, all three must be 0 or 1 For an edge, exactly one must be 2 For a face, two must be 2*/ } Part, *PartPtr; /*Parts for using*/ #define NPARTS 1580 Part parts[NPARTS]; PartPtr freePart, tempFree; #define MAXNPOLYS 4 PartPtr presetPolys[256][MAXNPOLYS]; /*Macros for allocating parts*/ #define NEWPART (freePart ? \ (tempFree = freePart, freePart = freePart -> next, tempFree) \ : newp(Part)) #define FREEPART(p) p -> next = freePart; freePart = p; #ifdef HAVE_PROTOTYPES Bool SectPart(PartPtr, PartPtr, PartPtr); Bool IsoHex(real fieldHex[2][2][2], real surfVal, ObjPtr pic, Bool lowInside); #else Bool SectPart(); Bool IsoHex(); #endif /*Macro to insert a node after one node in the linked list*/ #define INSERTAFTER(list, node) \ { \ node -> next = list -> next; \ list -> next = node; \ } /*Macro to dispose of a node after the current node*/ #define DISPOSEAFTER(list) \ { \ PartPtr next; \ next = list -> next -> next; \ FREEPART(list -> next); \ list -> next = next; \ } /*Values for vertexState*/ #define WITHIN 0 /*Within the isosurface*/ #define WITHOUT 1 /*Outside the isosurface*/ #define USED 2 /*Already used in the polygon*/ Bool EdgeOnFace(e, f) PartPtr e, f; /*Returns true if edge e is on face f*/ { register int k; for (k = 0; k < 3; ++k) { if (e -> coords[k] == 2 && f -> coords[k] != 2) { return false; } } return true; } Bool SectPart(s1, s2, d) PartPtr s1, s2, d; /*Returns true if s1 intersects s2 and, if so, puts the intersection in d The intersection of two edges is a vertex; the intersection of two faces is an edge*/ { register int k; for (k = 0; k < 3; ++k) { if (s1 -> coords[k] == 2) { d -> coords[k] = s2 -> coords[k]; } else if (s2 -> coords[k] == 2) { d -> coords[k] = s1 -> coords[k]; } else if (s1 -> coords[k] != s2 -> coords[k]) { return false; } else { d -> coords[k] = s1 -> coords[k]; } } return true; } void UnionPart(s1, s2, d) PartPtr s1, s2, d; /*Puts in d the union of parts s1 and s2*/ { register int k; for (k = 0; k < 3; ++k) { if (s1 -> coords[k] == s2 -> coords[k]) { d -> coords[k] = s1 -> coords[k]; } else { d -> coords[k] = 2; } } } Bool ThirdEdge(s1, s2, d) PartPtr s1, s2, d; /*Given 2 edges, s1, and s2 which meet at a point, forms the third edge d*/ { register int k; for (k = 0; k < 3; ++k) { if (s1 -> coords[k] == 2) { d -> coords[k] = s2 -> coords[k]; } else if (s2 -> coords[k] == 2) { d -> coords[k] = s1 -> coords[k]; } else if (s1 -> coords[k] != s2 -> coords[k]) { return false; } else { d -> coords[k] = 2; } } return true; } void Other2Edges(e, v, e1, e2) PartPtr e, v, e1, e2; /*Given an edge e and a vertex v on that edge, puts in e1 and e2 the other two edges which intersect that vertex*/ { register int index; /*Index into which coordinate*/ for (index = 0; index < 3; ++index) { if (e -> coords[index] != 2) { e1 -> coords[0] = v -> coords[0]; e1 -> coords[1] = v -> coords[1]; e1 -> coords[2] = v -> coords[2]; e1 -> coords[index] = 2; break; } } for (index = 2; index >= 0; --index) { if (e -> coords[index] != 2) { e2 -> coords[0] = v -> coords[0]; e2 -> coords[1] = v -> coords[1]; e2 -> coords[2] = v -> coords[2]; e2 -> coords[index] = 2; break; } } } #ifdef HAVE_PROTOTYPES Bool CacheIso(int initState[2][2][2], int whichPreset, Bool lowInside) #else Bool CacheIso(initState, whichPreset, lowInside) int initState[2][2][2]; int whichPreset; Bool lowInside; #endif /*Calculates a series of polygons that make an isosurface through fieldHex at surfVal, storing it in whichPreset. If lowInside, assumes that what is lower than surfVal is inside, otherwise what is higher*/ { int i, j, k; /*Counters*/ int vertexState[2][2][2]; /*State of each vertex in the hex*/ int verticesLeft; /*Number of within vertices left*/ Bool retVal = true; /*Return value*/ int whichPolygon; /*Which polygon of this polygon cache*/ /*Figure out what the state of the vertices is*/ verticesLeft = 0; for (i = 0; i < 2; ++i) { for (j = 0; j < 2; ++j) { for(k = 0; k < 2; ++k) { if (initState[i][j][k]) { vertexState[i][j][k] = lowInside ? WITHIN : WITHOUT; } else { vertexState[i][j][k] = lowInside ? WITHOUT : WITHIN; } if (vertexState[i][j][k] == WITHIN) { ++verticesLeft; } } } } /*If all vertices are within, don't bother trying*/ if (verticesLeft == 8) { return true; } whichPolygon = 0; /*Create isosurfaces until no more are needed*/ while (verticesLeft) { int i0, j0, k0; /*Index of starting vertex*/ PartPtr polygon; /*The polygon around the isosurface, circular linked list*/ register PartPtr oneEdge; /*Temporary edge*/ /*Pick an initial vertex around which to build the surface*/ for (i = 0; i < 2; ++i) { for (j = 0; j < 2; ++j) { for (k = 0; k < 2; ++k) { if (vertexState[i][j][k] == WITHIN) { i0 = i; j0 = j; k0 = k; } } } } /*Now, i0, j0, and k0 are set to the initial vertex*/ /*Create the first polygon and account for that vertex*/ oneEdge = NEWPART; oneEdge -> next = oneEdge; oneEdge -> coords[0] = 2; oneEdge -> coords[1] = j0; oneEdge -> coords[2] = k0; polygon = oneEdge; /*Use checkerboard rule to determine initial order*/ if (i0 ^ j0 ^ k0) { oneEdge = NEWPART; oneEdge -> coords[0] = i0; oneEdge -> coords[1] = j0; oneEdge -> coords[2] = 2; INSERTAFTER(polygon, oneEdge); oneEdge = NEWPART; oneEdge -> coords[0] = i0; oneEdge -> coords[1] = 2; oneEdge -> coords[2] = k0; INSERTAFTER(polygon, oneEdge); } else { oneEdge = NEWPART; oneEdge -> coords[0] = i0; oneEdge -> coords[1] = 2; oneEdge -> coords[2] = k0; INSERTAFTER(polygon, oneEdge); oneEdge = NEWPART; oneEdge -> coords[0] = i0; oneEdge -> coords[1] = j0; oneEdge -> coords[2] = 2; INSERTAFTER(polygon, oneEdge); } vertexState[i0][j0][k0] = USED; --verticesLeft; /*Now go through and expand the polygon*/ for (;;) { PartPtr runner; /*Runner through the polygon*/ /*First see if there is any potential vertex, common to two existing adjacent edges which can combine them into one*/ runner = polygon; do { Part intersection; /*Intersection between two edges*/ if (SectPart(runner, runner -> next, &intersection)) { /*intersection contains a vertex where two edges meet*/ if (vertexState[intersection . coords[0]] [intersection . coords[1]] [intersection . coords[2]] == WITHIN) { /*It's a valid candidate; gobble it up*/ ThirdEdge(runner, runner -> next, runner); if (runner -> next == polygon) { polygon = runner; } DISPOSEAFTER(runner); vertexState[intersection . coords[0]] [intersection . coords[1]] [intersection . coords[2]] = USED; --verticesLeft; goto tryAgain; } } runner = runner -> next; } while (runner != polygon); /*Now see if an edge can be stretched over a neighboring vertex*/ runner = polygon; do { int index; /*Index into which coord is Free*/ Part vertex; /*Start off with vertex = edge*/ vertex . coords[0] = runner -> coords[0]; vertex . coords[1] = runner -> coords[1]; vertex . coords[2] = runner -> coords[2]; /*Figure out which coordinate is Free*/ for (index = 0; index < 3; ++index) { if (runner -> coords[index] == 2) { break; } } /*Now try both vertices that share that edge*/ for (vertex . coords[index] = 0; vertex . coords[index] < 2; ++(vertex . coords[index])) { if (vertexState[vertex . coords[0]] [vertex . coords[1]] [vertex . coords[2]] == WITHIN) { /*Yes, it's good! Snap it over it.*/ Part lastFace; /*Second face to climb over*/ Part temp; /*Temporary part*/ Part edge1, edge2; /*Candidate edges*/ /*Determine the last face the new line will climb over to determine the order of edges*/ UnionPart(runner, runner -> next, &lastFace); /*Start with the edge that does not intersect lastFace*/ Other2Edges(runner, &vertex, &edge1, &edge2); oneEdge = NEWPART; if (EdgeOnFace(&edge1, &lastFace)) { /*Start with edge2*/ runner -> coords[0] = edge2 . coords[0]; runner -> coords[1] = edge2 . coords[1]; runner -> coords[2] = edge2 . coords[2]; oneEdge -> coords[0] = edge1 . coords[0]; oneEdge -> coords[1] = edge1 . coords[1]; oneEdge -> coords[2] = edge1 . coords[2]; } else { /*Start with edge1*/ runner -> coords[0] = edge1 . coords[0]; runner -> coords[1] = edge1 . coords[1]; runner -> coords[2] = edge1 . coords[2]; oneEdge -> coords[0] = edge2 . coords[0]; oneEdge -> coords[1] = edge2 . coords[1]; oneEdge -> coords[2] = edge2 . coords[2]; } INSERTAFTER(runner, oneEdge); vertexState[vertex . coords[0]] [vertex . coords[1]] [vertex . coords[2]] = USED; --verticesLeft; goto tryAgain; } } runner = runner -> next; } while (runner != polygon); #if 0 /*Failed the two tests. See if there are two identical intersections between two used vertices to slide*/ runner = polygon; do { int index; /*Index into which coord is Free*/ Part vertex; /*Start off with vertex = edge*/ vertex . coords[0] = runner -> coords[0]; vertex . coords[1] = runner -> coords[1]; vertex . coords[2] = runner -> coords[2]; /*Figure out which coordinate is Free*/ for (index = 0; index < 3; ++index) { if (runner -> coords[index] == 2) { break; } } /*Try both endpoints to see if they're both USED*/ vertex . coords[index] = 0; if (vertexState[vertex . coords[0]] [vertex . coords[1]] [vertex . coords[2]] == USED) { /*Looks good so far*/ vertex . coords[index] = 1; if (vertexState[vertex . coords[0]] [vertex . coords[1]] [vertex . coords[2]] == USED) { /*Excellent! Found one. Now search for the other one, if any*/ PartPtr other; other = runner -> next; do { if (runner -> coords[0] == other -> coords[0] && runner -> coords[1] == other -> coords[1] && runner -> coords[2] == other -> coords[2]) { /*Hot diggity sclotos!*/ break; } other = other -> next; } while (other != runner); if (other != runner) { /*We found a mate! Slide the two*/ runner -> coords[0] = other -> next -> coords[0]; runner -> coords[1] = other -> next -> coords[1]; runner -> coords[2] = other -> next -> coords[2]; other -> coords[0] = runner -> next -> coords[0]; other -> coords[1] = runner -> next -> coords[1]; other -> coords[2] = runner -> next -> coords[2]; break; } } } runner = runner -> next; } while (runner != polygon); #endif break; tryAgain: ; } if (polygon) { PartPtr curNode; /*The current node in the polygon*/ PartPtr next; /*The next node in the polygon*/ int whichVertex; /*The current vertex*/ int k; whichVertex = 0; /*Test the polygon for sanity*/ curNode = polygon; do { register int n; /*Dimension counters*/ register int ic, jc, kc; int t1, t2; /*Determine along which side this intersection lies*/ ic = curNode -> coords[0]; jc = curNode -> coords[1]; kc = curNode -> coords[2]; if (ic == 2) { /*i is Free*/ t1 = initState[0][jc][kc]; t2 = initState[1][jc][kc]; if (t1 == t2) { retVal = false; goto zapPolygon; } } else if (jc == 2) { /*j is Free*/ t1 = initState[ic][0][kc]; t2 = initState[ic][1][kc]; if (t1 == t2) { retVal = false; goto zapPolygon; } } else if (kc == 2) { /*k is Free*/ t1 = initState[ic][jc][0]; t2 = initState[ic][jc][1]; if (t1 == t2) { retVal = false; goto zapPolygon; } } else { ReportError("CacheIso", "Error, neither ic nor kc nor jc Free"); } curNode = curNode -> next; } while (curNode != polygon); if (whichPolygon >= MAXNPOLYS) ReportError("CacheIso", "Too many polys"); presetPolys[whichPreset][whichPolygon] = polygon; ++whichPolygon; continue; zapPolygon: /*Get rid of the polygon*/ curNode = polygon; next = curNode -> next; do { curNode = next; next = curNode -> next; FREEPART(curNode); } while (curNode != polygon); } } return retVal; } #ifdef HAVE_PROTOTYPES Bool NewIsoHex(real *bottomField, real *topField, VertexPtr *bottomVertices, VertexPtr *topVertices, long index[], long dims[], real surfVal, ObjPtr pic, Bool lowInside) #else Bool NewIsoHex(bottomField, topField, bottomVertices, topVertices, index, dims, surfVal, pic, lowInside) real *bottomField; real *topField; VertexPtr *bottomVertices; VertexPtr *topVertices; long index[]; long dims[]; real surfVal; ObjPtr pic; Bool lowInside; #endif /*Calculates a series of polygons that make an isosurface.*/ { int i, j, t; /*Counters*/ real sample; int whichCase; register long offset; /*Calculate the case*/ whichCase = 0; for (i = 0; i < 2; ++i) { for (j = 0; j < 2; ++j) { offset = (index[0] + i) * dims[1] + (index[1] + j); whichCase = whichCase << 1; sample = bottomField[offset]; if (sample == missingData) return true; if (lowInside ? (sample <= surfVal) : (sample >= surfVal)) { whichCase += 1; } whichCase = whichCase << 1; sample = topField[offset]; if (sample == missingData) return true; if (lowInside ? (sample <= surfVal) : (sample >= surfVal)) { whichCase += 1; } } } i = index[0]; j = index[1]; for (t = 0; presetPolys[whichCase][t]; ++t) { PartPtr polygon; polygon = presetPolys[whichCase][t]; if (polygon) { PartPtr curNode; /*The current node in the polygon*/ PartPtr next; /*The next node in the polygon*/ VertexPtr vertices[20]; /*The vertices into the polygon*/ int whichVertex; /*Which vertex of the poly looking at*/ whichVertex = 0; /*Emit the polygon*/ curNode = polygon; do { register int ic, jc, kc; /*Determine along which side this intersection lies*/ ic = curNode -> coords[0]; jc = curNode -> coords[1]; kc = curNode -> coords[2]; if (ic == 2) { /*i is Free*/ offset = (i * dims[1] + (j + jc)) * 3; } else if (jc == 2) { /*j is Free*/ offset = ((i + ic) * dims[1] + j) * 3 + 1; } else if (kc == 2) { /*k is Free*/ offset = ((i + ic) * dims[1] + (j + jc)) * 3 + 2; } else { ReportError("NewIsoHex", "Error, neither ic nor kc nor jc Free"); return false; } vertices[whichVertex] = (kc == 1) ? topVertices[offset] : bottomVertices[offset]; if (vertices[whichVertex] == 0) { ReportError("NewIsoHex", "Vertex error"); return false; } ++whichVertex; curNode = curNode -> next; } while (curNode != polygon); /*Now the polygon has been assembled; spit it out.*/ TesselateSPolyToPicture(pic, whichVertex, vertices); } } } #define CALCDELTA(field, hc, pic, mic, pjc, mjc, pkc, mkc) #undef NEXTFIELD #undef PREVFIELD #undef PLUSIC #undef MINUSIC #undef PLUSJC #undef MINUSJC #undef PLUSKC #undef MINUSKC #ifdef HAVE_PROTOTYPES static void StuffIJKVertices(VertexPtr *elements, real *field, real *nextField, real deltas[], int fieldNum, int coord, long dims[3], long kVal, ObjPtr pic, real isoVal, Bool encloseLow) #else static void StuffIJKVertices(elements, field, nextField, deltas, fieldNum, coord, dims, kVal, pic, isoVal, encloseLow) VertexPtr *elements; real *field; int fieldNum; real *nextField; real deltas[]; int coord; long dims[3]; long kVal; ObjPtr pic; real isoVal; Bool encloseLow; #endif /*Makes a group of IJK vertices for field at k = kVal, sticking them in pic Coord is the coordinates. Stuffs the results into array. If deltas, uses deltas as a holding place for the deltas to make normals*/ { long index[3]; register long nElements; register long i, j; register long offset; register real curVal, nextVal; register real r; /*Empty the array*/ nElements = dims[0] * dims[1] * 3; for (offset = 0; offset < nElements; ++offset) { elements[offset] = 0; } /*Make I vertices*/ for (index[1] = 0; index[1] < dims[1]; ++index[1]) { index[0] = 0; index[2] = kVal; offset = index[1]; curVal = field[offset]; for (index[0] = 1; index[0] < dims[0]; ++index[0]) { nextVal = field[offset + dims[1]]; if (curVal != missingData && nextVal != missingData) { /*Maybe make some sort of a vertex*/ if (BETWEENP(isoVal, curVal, nextVal)) { /*Yes! Vertex here!*/ register VertexPtr v; register real location, location1; real curCoord[3], nextCoord[3]; v = NewVertex(pic, 0); location = (isoVal - curVal) / (nextVal - curVal); location1 = 1.0 - location; /*Get coordinates*/ --index[0]; curCoord[0] = SelectFieldComponent(coord, 0, index); curCoord[1] = SelectFieldComponent(coord, 1, index); curCoord[2] = SelectFieldComponent(coord, 2, index); ++index[0]; nextCoord[0] = SelectFieldComponent(coord, 0, index); nextCoord[1] = SelectFieldComponent(coord, 1, index); nextCoord[2] = SelectFieldComponent(coord, 2, index); /*Set position*/ v -> position[0] = nextCoord[0] * location + curCoord[0] * location1; v -> position[1] = nextCoord[1] * location + curCoord[1] * location1; v -> position[2] = nextCoord[2] * location + curCoord[2] * location1; if (deltas) { /*Calculate normal from delta*/ --index[0]; #define FIELDHERE field #define NEXTFIELD nextField #define HEREC curCoord #define HEREV curVal #define PLUSIC nextCoord #include "ScianIsoCalcDelta.h" #undef FIELDHERE #undef NEXTFIELD #undef HEREC #undef HEREV #undef PLUSIC ++index[0]; #define FIELDHERE field #define NEXTFIELD nextField #define HEREC nextCoord #define HEREV nextVal #define MINUSIC curCoord #include "ScianIsoCalcDelta.h" #undef FIELDHERE #undef NEXTFIELD #undef HEREC #undef HEREV #undef MINUSIC /*Now that we have two deltas, make the normal*/ offset += dims[1]; v -> normal[0] = location * deltas[offset * 3]; v -> normal[1] = location * deltas[offset * 3 + 1]; v -> normal[2] = location * deltas[offset * 3 + 2]; offset -= dims[1]; v -> normal[0] += location1 * deltas[offset * 3]; v -> normal[1] += location1 * deltas[offset * 3 + 1]; v -> normal[2] += location1 * deltas[offset * 3 + 2]; r = sqrt(SQUARE(v -> normal[0]) + SQUARE(v -> normal[1]) + SQUARE(v -> normal[2])); if (r > 0.0) { r = 1.0 / r; v -> normal[0] *= r; v -> normal[1] *= r; v -> normal[2] *= r; if (!encloseLow) { v -> normal[0] = -(v -> normal[0]); v -> normal[1] = -(v -> normal[1]); v -> normal[2] = -(v -> normal[2]); } } else { /*Just give it plus z normal*/ v -> normal[0] = 0.0; v -> normal[1] = 0.0; v -> normal[2] = 1.0; } } else { /*Just give it plus z normal*/ v -> normal[0] = 0.0; v -> normal[1] = 0.0; v -> normal[2] = 1.0; } elements[offset * 3] = v; } } curVal = nextVal; offset += dims[1]; } } /*Make J vertices*/ for (index[0] = 0; index[0] < dims[0]; ++index[0]) { index[1] = 0; index[2] = kVal; offset = index[0] * dims[1]; curVal = field[offset]; for (index[1] = 1; index[1] < dims[1]; ++index[1]) { nextVal = field[offset + 1]; if (curVal != missingData && nextVal != missingData) { /*Maybe make some sort of a vertex*/ if (BETWEENP(isoVal, curVal, nextVal)) { /*Yes! Vertex here!*/ register VertexPtr v; register real location, location1; real curCoord[3], nextCoord[3]; v = NewVertex(pic, 0); location = (isoVal - curVal) / (nextVal - curVal); location1 = 1.0 - location; /*Get coordinates*/ --index[1]; curCoord[0] = SelectFieldComponent(coord, 0, index); curCoord[1] = SelectFieldComponent(coord, 1, index); curCoord[2] = SelectFieldComponent(coord, 2, index); ++index[1]; nextCoord[0] = SelectFieldComponent(coord, 0, index); nextCoord[1] = SelectFieldComponent(coord, 1, index); nextCoord[2] = SelectFieldComponent(coord, 2, index); /*Set position*/ v -> position[0] = nextCoord[0] * location + curCoord[0] * location1; v -> position[1] = nextCoord[1] * location + curCoord[1] * location1; v -> position[2] = nextCoord[2] * location + curCoord[2] * location1; if (deltas) { /*Calculate normal from delta*/ --index[1]; #define FIELDHERE field #define NEXTFIELD nextField #define HEREC curCoord #define HEREV curVal #define PLUSJC nextCoord #include "ScianIsoCalcDelta.h" #undef FIELDHERE #undef NEXTFIELD #undef HEREC #undef HEREV #undef PLUSJC ++index[1]; #define FIELDHERE field #define NEXTFIELD nextField #define HEREC nextCoord #define HEREV nextVal #define MINUSJC curCoord #include "ScianIsoCalcDelta.h" #undef FIELDHERE #undef NEXTFIELD #undef HEREC #undef HEREV #undef MINUSJC /*Now that we have two deltas, make the normal*/ ++offset; v -> normal[0] = location * deltas[offset * 3]; v -> normal[1] = location * deltas[offset * 3 + 1]; v -> normal[2] = location * deltas[offset * 3 + 2]; --offset; v -> normal[0] += location1 * deltas[offset * 3]; v -> normal[1] += location1 * deltas[offset * 3 + 1]; v -> normal[2] += location1 * deltas[offset * 3 + 2]; r = sqrt(SQUARE(v -> normal[0]) + SQUARE(v -> normal[1]) + SQUARE(v -> normal[2])); if (r > 0.0) { r = 1.0 / r; v -> normal[0] *= r; v -> normal[1] *= r; v -> normal[2] *= r; if (!encloseLow) { v -> normal[0] = -(v -> normal[0]); v -> normal[1] = -(v -> normal[1]); v -> normal[2] = -(v -> normal[2]); } } else { /*Just give it plus z normal*/ v -> normal[0] = 0.0; v -> normal[1] = 0.0; v -> normal[2] = 1.0; } } else { /*Just give it plus z normal*/ v -> normal[0] = 0.0; v -> normal[1] = 0.0; v -> normal[2] = 1.0; } elements[offset * 3 + 1] = v; } } curVal = nextVal; ++offset; } } /*Make K vertices*/ index[0] = 0; index[1] = 0; index[2] = kVal; if (kVal < dims[2]) for (index[0] = 0; index[0] < dims[0]; ++index[0]) { offset = index[0] * dims[1]; for (index[1] =0; index[1] < dims[1]; ++index[1]) { index[2] = kVal; curVal = field[offset]; index[2] = kVal + 1; nextVal = nextField[offset]; if ((curVal != missingData) && (nextVal != missingData) && BETWEENP(isoVal, curVal, nextVal)) { /*Yes! Vertex here!*/ register VertexPtr v; register real location, location1; real curCoord[3], nextCoord[3]; v = NewVertex(pic, 0); location = (isoVal - curVal) / (nextVal - curVal); location1 = 1.0 - location; /*Get coordinates*/ --index[2]; curCoord[0] = SelectFieldComponent(coord, 0, index); curCoord[1] = SelectFieldComponent(coord, 1, index); curCoord[2] = SelectFieldComponent(coord, 2, index); ++index[2]; nextCoord[0] = SelectFieldComponent(coord, 0, index); nextCoord[1] = SelectFieldComponent(coord, 1, index); nextCoord[2] = SelectFieldComponent(coord, 2, index); /*Set position*/ v -> position[0] = nextCoord[0] * location + curCoord[0] * location1; v -> position[1] = nextCoord[1] * location + curCoord[1] * location1; v -> position[2] = nextCoord[2] * location + curCoord[2] * location1; if (deltas) { /*Calculate normal from delta*/ --index[2]; #define FIELDHERE field #define NEXTFIELD nextField #define HEREC curCoord #define PLUSKC nextCoord #define HEREV curVal #include "ScianIsoCalcDelta.h" #undef FIELDHERE #undef NEXTFIELD #undef HEREC #undef PLUSKC #undef HEREV v -> normal[0] = location1 * deltas[offset * 3]; v -> normal[1] = location1 * deltas[offset * 3 + 1]; v -> normal[2] = location1 * deltas[offset * 3 + 2]; deltas[offset * 3] = missingData; deltas[offset * 3 + 1] = missingData; deltas[offset * 3 + 2] = missingData; ++index[2]; #define FIELDHERE nextField #define PREVFIELD field #define HEREC nextCoord #define MINUSKC curCoord #define HEREV nextVal #include "ScianIsoCalcDelta.h" #undef FIELDHERE #undef PREVFIELD #undef HEREC #undef MINUSKC #undef HEREV /*Now that we have two deltas, make the normal*/ v -> normal[0] += location * deltas[offset * 3]; v -> normal[1] += location * deltas[offset * 3 + 1]; v -> normal[2] += location * deltas[offset * 3 + 2]; r = sqrt(SQUARE(v -> normal[0]) + SQUARE(v -> normal[1]) + SQUARE(v -> normal[2])); if (r > 0.0) { r = 1.0 / r; v -> normal[0] *= r; v -> normal[1] *= r; v -> normal[2] *= r; if (!encloseLow) { v -> normal[0] = -(v -> normal[0]); v -> normal[1] = -(v -> normal[1]); v -> normal[2] = -(v -> normal[2]); } } else { /*Just give it plus z normal*/ v -> normal[0] = 0.0; v -> normal[1] = 0.0; v -> normal[2] = 1.0; } } else { /*Just give it plus z normal*/ v -> normal[0] = 0.0; v -> normal[1] = 0.0; v -> normal[2] = 1.0; } elements[offset * 3 + 2] = v; } else { /*Haven't made deltas for next time, must kill them*/ if (deltas) { deltas[offset * 3] = missingData; deltas[offset * 3 + 1] = missingData; deltas[offset * 3 + 2] = missingData; } } curVal = nextVal; ++offset; } } } static ObjPtr AddIsoVRControls(object, contents) ObjPtr object, contents; /*Adds controls appropriate to an isosurface to contents*/ { ObjPtr button; ObjPtr isoField, var; real db[2]; real bc[3]; #ifdef GRAPHICS Object o; short c[3]; float v[3]; #endif #ifdef GRAPHICS /*Make the opaque button*/ o = genobj(); makeobj(o); bgnpolygon(); c[0] = 255; c[1] = 0; c[2] = 0; c3s(c); v[0] = 0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.0982890; v[1] = -0.126105; v[2] = 0.00000; v3f(v); v[0] = -0.0931852; v[1] = -0.151764; v[2] = 0.00000; v3f(v); v[0] = -0.0847759; v[1] = -0.176537; v[2] = 0.00000; v3f(v); v[0] = -0.0732051; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.0586707; v[1] = -0.221752; v[2] = 0.00000; v3f(v); v[0] = -0.0414214; v[1] = -0.241421; v[2] = 0.00000; v3f(v); v[0] = -0.0217523; v[1] = -0.258671; v[2] = 0.00000; v3f(v); v[0] = -4.47035e-08; v[1] = -0.273205; v[2] = 0.00000; v3f(v); v[0] = 0.0234633; v[1] = -0.284776; v[2] = 0.00000; v3f(v); v[0] = 0.0482361; v[1] = -0.293185; v[2] = 0.00000; v3f(v); v[0] = 0.0738947; v[1] = -0.298289; v[2] = 0.00000; v3f(v); v[0] = 0.0999999; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = 0.126105; v[1] = -0.298289; v[2] = 0.00000; v3f(v); v[0] = 0.151764; v[1] = -0.293185; v[2] = 0.00000; v3f(v); v[0] = 0.176537; v[1] = -0.284776; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.273205; v[2] = 0.00000; v3f(v); v[0] = 0.221752; v[1] = -0.258671; v[2] = 0.00000; v3f(v); v[0] = 0.241421; v[1] = -0.241421; v[2] = 0.00000; v3f(v); v[0] = 0.258671; v[1] = -0.221752; v[2] = 0.00000; v3f(v); v[0] = 0.273205; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.284776; v[1] = -0.176537; v[2] = 0.00000; v3f(v); v[0] = 0.293185; v[1] = -0.151764; v[2] = 0.00000; v3f(v); v[0] = 0.298289; v[1] = -0.126105; v[2] = 0.00000; v3f(v); v[0] = 0.300000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.298289; v[1] = -0.0738949; v[2] = 0.00000; v3f(v); v[0] = 0.293185; v[1] = -0.0482363; v[2] = 0.00000; v3f(v); v[0] = 0.284776; v[1] = -0.0234634; v[2] = 0.00000; v3f(v); v[0] = 0.273205; v[1] = -1.04308e-07; v[2] = 0.00000; v3f(v); v[0] = 0.258671; v[1] = 0.0217522; v[2] = 0.00000; v3f(v); v[0] = 0.241421; v[1] = 0.0414213; v[2] = 0.00000; v3f(v); v[0] = 0.221752; v[1] = 0.0586706; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = 0.0732050; v[2] = 0.00000; v3f(v); v[0] = 0.176537; v[1] = 0.0847759; v[2] = 0.00000; v3f(v); v[0] = 0.151764; v[1] = 0.0931851; v[2] = 0.00000; v3f(v); v[0] = 0.126105; v[1] = 0.0982890; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); c[0] = 0; c[1] = 0; c[2] = 255; c3s(c); v[0] = -0.300000; v[1] = 0.300000; v[2] = 0.00000; v3f(v); v[0] = -0.300000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.300000; v[2] = 0.00000; v3f(v); endpolygon(); closeobj(); button = NewArenaButton("VR Opaque", o, -AW_BUTTONSIZE * 0.6, -AW_BUTTONSIZE * 0.5, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); AssocConstVarControlWithVar(button, object, ISTRANSPARENT, ObjFalse); o = genobj(); makeobj(o); bgnpolygon(); c[0] = 255; c[1] = 0; c[2] = 0; c3s(c); v[0] = 0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.0982890; v[1] = -0.126105; v[2] = 0.00000; v3f(v); v[0] = -0.0931852; v[1] = -0.151764; v[2] = 0.00000; v3f(v); v[0] = -0.0847759; v[1] = -0.176537; v[2] = 0.00000; v3f(v); v[0] = -0.0732051; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.0586707; v[1] = -0.221752; v[2] = 0.00000; v3f(v); v[0] = -0.0414214; v[1] = -0.241421; v[2] = 0.00000; v3f(v); v[0] = -0.0217523; v[1] = -0.258671; v[2] = 0.00000; v3f(v); v[0] = -4.47035e-08; v[1] = -0.273205; v[2] = 0.00000; v3f(v); v[0] = 0.0234633; v[1] = -0.284776; v[2] = 0.00000; v3f(v); v[0] = 0.0482361; v[1] = -0.293185; v[2] = 0.00000; v3f(v); v[0] = 0.0738947; v[1] = -0.298289; v[2] = 0.00000; v3f(v); v[0] = 0.0999999; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = 0.126105; v[1] = -0.298289; v[2] = 0.00000; v3f(v); v[0] = 0.151764; v[1] = -0.293185; v[2] = 0.00000; v3f(v); v[0] = 0.176537; v[1] = -0.284776; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.273205; v[2] = 0.00000; v3f(v); v[0] = 0.221752; v[1] = -0.258671; v[2] = 0.00000; v3f(v); v[0] = 0.241421; v[1] = -0.241421; v[2] = 0.00000; v3f(v); v[0] = 0.258671; v[1] = -0.221752; v[2] = 0.00000; v3f(v); v[0] = 0.273205; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.284776; v[1] = -0.176537; v[2] = 0.00000; v3f(v); v[0] = 0.293185; v[1] = -0.151764; v[2] = 0.00000; v3f(v); v[0] = 0.298289; v[1] = -0.126105; v[2] = 0.00000; v3f(v); v[0] = 0.300000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.298289; v[1] = -0.0738949; v[2] = 0.00000; v3f(v); v[0] = 0.293185; v[1] = -0.0482363; v[2] = 0.00000; v3f(v); v[0] = 0.284776; v[1] = -0.0234634; v[2] = 0.00000; v3f(v); v[0] = 0.273205; v[1] = -1.04308e-07; v[2] = 0.00000; v3f(v); v[0] = 0.258671; v[1] = 0.0217522; v[2] = 0.00000; v3f(v); v[0] = 0.241421; v[1] = 0.0414213; v[2] = 0.00000; v3f(v); v[0] = 0.221752; v[1] = 0.0586706; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = 0.0732050; v[2] = 0.00000; v3f(v); v[0] = 0.176537; v[1] = 0.0847759; v[2] = 0.00000; v3f(v); v[0] = 0.151764; v[1] = 0.0931851; v[2] = 0.00000; v3f(v); v[0] = 0.126105; v[1] = 0.0982890; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); c[0] = 0; c[1] = 0; c[2] = 255; c3s(c); v[0] = -0.300000; v[1] = 0.300000; v[2] = 0.00000; v3f(v); v[0] = -0.300000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.0982890; v[1] = -0.0738948; v[2] = 0.00000; v3f(v); v[0] = -0.0931852; v[1] = -0.0482362; v[2] = 0.00000; v3f(v); v[0] = -0.0847759; v[1] = -0.0234633; v[2] = 0.00000; v3f(v); v[0] = -0.0732051; v[1] = -2.98023e-08; v[2] = 0.00000; v3f(v); v[0] = -0.0586707; v[1] = 0.0217523; v[2] = 0.00000; v3f(v); v[0] = -0.0414214; v[1] = 0.0414213; v[2] = 0.00000; v3f(v); v[0] = -0.0217523; v[1] = 0.0586706; v[2] = 0.00000; v3f(v); v[0] = -4.47035e-08; v[1] = 0.0732051; v[2] = 0.00000; v3f(v); v[0] = 0.0234633; v[1] = 0.0847759; v[2] = 0.00000; v3f(v); v[0] = 0.0482361; v[1] = 0.0931851; v[2] = 0.00000; v3f(v); v[0] = 0.0738947; v[1] = 0.0982890; v[2] = 0.00000; v3f(v); v[0] = 0.0999999; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.300000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); c[0] = 255; c[1] = 0; c[2] = 255; c3s(c); v[0] = 0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.0738948; v[1] = 0.0982890; v[2] = 0.00000; v3f(v); v[0] = 0.0482362; v[1] = 0.0931852; v[2] = 0.00000; v3f(v); v[0] = 0.0234633; v[1] = 0.0847759; v[2] = 0.00000; v3f(v); v[0] = -1.49012e-08; v[1] = 0.0732051; v[2] = 0.00000; v3f(v); v[0] = -0.0217523; v[1] = 0.0586707; v[2] = 0.00000; v3f(v); v[0] = -0.0414214; v[1] = 0.0414214; v[2] = 0.00000; v3f(v); v[0] = -0.0586707; v[1] = 0.0217523; v[2] = 0.00000; v3f(v); v[0] = -0.0732051; v[1] = 1.49012e-08; v[2] = 0.00000; v3f(v); v[0] = -0.0847759; v[1] = -0.0234633; v[2] = 0.00000; v3f(v); v[0] = -0.0931852; v[1] = -0.0482362; v[2] = 0.00000; v3f(v); v[0] = -0.0982890; v[1] = -0.0738947; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); endpolygon(); closeobj(); button = NewArenaButton("VR Transparent", o, AW_BUTTONSIZE * 0.6, -AW_BUTTONSIZE * 0.5, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); AssocConstVarControlWithVar(button, object, ISTRANSPARENT, ObjTrue); o = genobj(); makeobj(o); c[0] = 128; c[1] = 128; c[2] = 128; c3s(c); bgnpolygon(); v[0] = 0.00000; v[1] = 0.300000; v[2] = 0.00000; v3f(v); v[0] = -0.114805; v[1] = 0.277164; v[2] = 0.00000; v3f(v); v[0] = -0.212132; v[1] = 0.212132; v[2] = 0.00000; v3f(v); v[0] = -0.277164; v[1] = 0.114805; v[2] = 0.00000; v3f(v); v[0] = -0.300000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = -0.277164; v[1] = -0.114805; v[2] = 0.00000; v3f(v); v[0] = -0.212132; v[1] = -0.212132; v[2] = 0.00000; v3f(v); v[0] = -0.114805; v[1] = -0.277164; v[2] = 0.00000; v3f(v); v[0] = 0.00000; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = 0.114805; v[1] = -0.277164; v[2] = 0.00000; v3f(v); v[0] = 0.212132; v[1] = -0.212132; v[2] = 0.00000; v3f(v); v[0] = 0.277164; v[1] = -0.114805; v[2] = 0.00000; v3f(v); v[0] = 0.300000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = 0.277164; v[1] = 0.114805; v[2] = 0.00000; v3f(v); v[0] = 0.212132; v[1] = 0.212132; v[2] = 0.00000; v3f(v); v[0] = 0.114805; v[1] = 0.277164; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.00000; v[1] = 0.500000; v[2] = 0.00000; v3f(v); v[0] = -0.0500000; v[1] = 0.350000; v[2] = 0.00000; v3f(v); v[0] = 0.0500000; v[1] = 0.350000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.250000; v[1] = 0.444000; v[2] = 0.00000; v3f(v); v[0] = 0.131000; v[1] = 0.338000; v[2] = 0.00000; v3f(v); v[0] = 0.219000; v[1] = 0.287000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.438000; v[1] = 0.256000; v[2] = 0.00000; v3f(v); v[0] = 0.281000; v[1] = 0.225000; v[2] = 0.00000; v3f(v); v[0] = 0.331000; v[1] = 0.144000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.500000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = 0.350000; v[1] = 0.0500000; v[2] = 0.00000; v3f(v); v[0] = 0.350000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.450000; v[1] = -0.256000; v[2] = 0.00000; v3f(v); v[0] = 0.331000; v[1] = -0.138000; v[2] = 0.00000; v3f(v); v[0] = 0.281000; v[1] = -0.219000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.262000; v[1] = -0.444000; v[2] = 0.00000; v3f(v); v[0] = 0.231000; v[1] = -0.287000; v[2] = 0.00000; v3f(v); v[0] = 0.144000; v[1] = -0.338000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = 0.00000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); v[0] = 0.0500000; v[1] = -0.350000; v[2] = 0.00000; v3f(v); v[0] = -0.0500000; v[1] = -0.350000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = -0.256000; v[1] = -0.438000; v[2] = 0.00000; v3f(v); v[0] = -0.138000; v[1] = -0.338000; v[2] = 0.00000; v3f(v); v[0] = -0.225000; v[1] = -0.281000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = -0.450000; v[1] = -0.269000; v[2] = 0.00000; v3f(v); v[0] = -0.287000; v[1] = -0.225000; v[2] = 0.00000; v3f(v); v[0] = -0.344000; v[1] = -0.138000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = -0.500000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = 0.0500000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = -0.450000; v[1] = 0.262000; v[2] = 0.00000; v3f(v); v[0] = -0.344000; v[1] = 0.138000; v[2] = 0.00000; v3f(v); v[0] = -0.287000; v[1] = 0.225000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); v[0] = -0.250000; v[1] = 0.438000; v[2] = 0.00000; v3f(v); v[0] = -0.225000; v[1] = 0.281000; v[2] = 0.00000; v3f(v); v[0] = -0.131000; v[1] = 0.331000; v[2] = 0.00000; v3f(v); endpolygon(); closeobj(); button = NewArenaSlider("Arena Brightness", o, -AW_BUTTONSIZE * 0.6, -AW_BUTTONSIZE * 1.5, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); AssocDirectControlWithVar(button, object, BRIGHTNESS); o = genobj(); makeobj(o); bgnpolygon(); c[0] = 255; c[1] = 255; c[2] = 255; c3s(c); v[0] = 0.00000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); v[0] = 0.250000; v[1] = -0.450000; v[2] = 0.00000; v3f(v); v[0] = 0.450000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.500000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); v[0] = 0.500000; v[1] = 0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.450000; v[1] = 0.250000; v[2] = 0.00000; v3f(v); v[0] = 0.250000; v[1] = 0.450000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.500000; v[2] = 0.00000; v3f(v); v[0] = 0.00000; v[1] = 0.500000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = 0.450000; v[2] = 0.00000; v3f(v); v[0] = -0.150000; v[1] = 0.400000; v[2] = 0.00000; v3f(v); v[0] = -0.200000; v[1] = 0.250000; v[2] = 0.00000; v3f(v); v[0] = -0.250000; v[1] = 0.150000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = 0.0500000; v[2] = 0.00000; v3f(v); v[0] = -0.450000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = -0.500000; v[1] = -0.150000; v[2] = 0.00000; v3f(v); v[0] = -0.500000; v[1] = -0.250000; v[2] = 0.00000; v3f(v); v[0] = -0.450000; v[1] = -0.350000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); v[0] = -0.300000; v[1] = -0.350000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.0500000; v[1] = 0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.250000; v[2] = 0.00000; v3f(v); v[0] = 0.300000; v[1] = 0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.400000; v[1] = 0.0500000; v[2] = 0.00000; v3f(v); v[0] = 0.400000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.350000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.400000; v[2] = 0.00000; v3f(v); v[0] = 0.00000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); c[0] = 191; c[1] = 191; c[2] = 191; c3s(c); v[0] = 0.00000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.400000; v[2] = 0.00000; v3f(v); v[0] = 0.350000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.400000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = 0.400000; v[1] = 0.0500000; v[2] = 0.00000; v3f(v); v[0] = 0.300000; v[1] = 0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.250000; v[2] = 0.00000; v3f(v); v[0] = -0.0500000; v[1] = 0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = -0.100000; v[2] = 0.00000; v3f(v); v[0] = -0.350000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.300000; v[1] = -0.350000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); v[0] = -0.200000; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = -0.200000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.150000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); v[0] = -0.0500000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = 0.150000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = 0.150000; v[1] = -0.400000; v[2] = 0.00000; v3f(v); v[0] = 0.00000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); endpolygon(); bgnpolygon(); c[0] = 63; c[1] = 63; c[2] = 63; c3s(c); v[0] = 0.00000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); v[0] = 0.150000; v[1] = -0.400000; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = 0.200000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = 0.150000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); v[0] = 0.100000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = -0.0500000; v[1] = 0.00000; v[2] = 0.00000; v3f(v); v[0] = -0.150000; v[1] = -0.0500000; v[2] = 0.00000; v3f(v); v[0] = -0.200000; v[1] = -0.200000; v[2] = 0.00000; v3f(v); v[0] = -0.200000; v[1] = -0.300000; v[2] = 0.00000; v3f(v); v[0] = -0.100000; v[1] = -0.500000; v[2] = 0.00000; v3f(v); endpolygon(); closeobj(); isoField = GetObjectVar("AddIsoControls", object, MAINDATASET); if (!isoField) return ObjFalse; MakeVar(isoField, MINMAX); var = GetVar(isoField, MINMAX); if (!var) return ObjFalse; Array2CArray(db, var); ChooseGoodRange(&(db[0]), &(db[1])); button = NewArenaSlider("Isovalue", o, AW_BUTTONSIZE * 0.6, -AW_BUTTONSIZE * 1.5, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); AssocDirectControlWithVar(button, object, ISOVAL); SetVar(button, HIVALUE, NewReal(db[1])); SetVar(button, LOVALUE, NewReal(db[0])); SetTrackNot(button, true); c[0] = 255; c[1] = 0; c[2] = 0; #include "ScianGeoBrush.h" button = NewArenaButton("Red", o, -AW_BUTTONSIZE, -AW_BUTTONSIZE * 3.2, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); bc[0] = 1.0; bc[1] = 0.0; bc[2] = 0.0; var = NewRealArray(1, 3L); CArray2Array(var, bc); AssocConstVarControlWithVar(button, object, BASECOLOR, var); c[0] = 0; c[1] = 255; c[2] = 0; #include "ScianGeoBrush.h" button = NewArenaButton("Green", o, 0.0, -AW_BUTTONSIZE * 3.2, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); bc[0] = 0.0; bc[1] = 1.0; bc[2] = 0.0; var = NewRealArray(1, 3L); CArray2Array(var, bc); AssocConstVarControlWithVar(button, object, BASECOLOR, var); c[0] = 0; c[1] = 0; c[2] = 255; #include "ScianGeoBrush.h" button = NewArenaButton("Blue", o, AW_BUTTONSIZE, -AW_BUTTONSIZE * 3.2, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); bc[0] = 0.0; bc[1] = 0.0; bc[2] = 1.0; var = NewRealArray(1, 3L); CArray2Array(var, bc); AssocConstVarControlWithVar(button, object, BASECOLOR, var); c[0] = 0; c[1] = 255; c[2] = 255; #include "ScianGeoBrush.h" button = NewArenaButton("Cyan", o, -AW_BUTTONSIZE, -AW_BUTTONSIZE * 4.2, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); bc[0] = 0.0; bc[1] = 1.0; bc[2] = 1.0; var = NewRealArray(1, 3L); CArray2Array(var, bc); AssocConstVarControlWithVar(button, object, BASECOLOR, var); c[0] = 255; c[1] = 0; c[2] = 255; #include "ScianGeoBrush.h" button = NewArenaButton("Magenta", o, 0.0, -AW_BUTTONSIZE * 4.2, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); bc[0] = 1.0; bc[1] = 0.0; bc[2] = 1.0; var = NewRealArray(1, 3L); CArray2Array(var, bc); AssocConstVarControlWithVar(button, object, BASECOLOR, var); c[0] = 255; c[1] = 255; c[2] = 255; #include "ScianGeoBrush.h" button = NewArenaButton("White", o, AW_BUTTONSIZE, -AW_BUTTONSIZE * 4.2, AW_NUDGE, AW_BUTTONSIZE, AW_BUTTONSIZE); PrefixList(contents, button); SetVar(button, PARENT, contents); bc[0] = 1.0; bc[1] = 1.0; bc[2] = 1.0; var = NewRealArray(1, 3L); CArray2Array(var, bc); AssocConstVarControlWithVar(button, object, BASECOLOR, var); #endif return ObjTrue; } static ObjPtr AddIsoControls(object, panelContents) ObjPtr object, panelContents; /*Adds controls appropriate to an isosurface to panelContents*/ { int left, right, top; real initValue; /*The initial value of a slider*/ ObjPtr var; /*A variable of some sort*/ ObjPtr slider; /*A slider*/ ObjPtr textBox; /*A text box*/ ObjPtr corral; /*An icon corral*/ int width; /*Width of the area we can use*/ ObjPtr name; /*The name of the field*/ ObjPtr icon; /*An icon that represents the field*/ ObjPtr isoField; /*The field of the isosurface.*/ ObjPtr defaultIcon; /*The default icon of the field*/ real db[2]; /*Bounds of the isosurface*/ ObjPtr minMax; /*Array containing min and max*/ ObjPtr checkBox; /*Temporary check box*/ ObjPtr titleBox; /*Temporary title box*/ ObjPtr radioGroup; /*Group of radio buttons*/ ObjPtr mainDataset; /*The main dataset of the field*/ ObjPtr scale; /*Scale for slider*/ width = CWINWIDTH - 2 * CORRALBORDER - CWINCORRALWIDTH; left = MAJORBORDER; top = CWINHEIGHT - MAJORBORDER; /*Put in the isosurface corral at the left*/ corral = NewIconCorral(NULLOBJ, left, left + ONECORRALWIDTH, top - ONECORRALHEIGHT, top, 0); SetVar(corral, SINGLECORRAL, ObjTrue); SetVar(corral, TOPDOWN, ObjTrue); SetVar(corral, NAME, NewString("Source Field")); PrefixList(panelContents, corral); SetVar(corral, HELPSTRING, NewString("This corral shows the dataset that is being used to make \ the isosurface. To replace it with another dataset, drag the icon of the other \ dataset into this corral.")); SetVar(corral, PARENT, panelContents); SetVar(corral, REPOBJ, object); SetMethod(corral, DROPINCONTENTS, DropInMainDatasetCorral); /*Create the iso source text box*/ textBox = NewTextBox(left, left + ONECORRALWIDTH, top - ONECORRALHEIGHT - TEXTBOXSEP - TEXTBOXHEIGHT, top - ONECORRALHEIGHT - TEXTBOXSEP, 0, "Isosurface Field Text", "Source Field"); PrefixList(panelContents, textBox); SetVar(textBox, PARENT, panelContents); SetTextAlign(textBox, CENTERALIGN); top = top - ONECORRALHEIGHT - TEXTBOXSEP - TEXTBOXHEIGHT - MAJORBORDER; right = left + ONECORRALWIDTH; /*Put in an icon that represents the field*/ isoField = GetObjectVar("AddIsoControls", object, MAINDATASET); if (!isoField) return ObjFalse; MakeVar(isoField, MINMAX); minMax = GetVar(isoField, MINMAX); if (!minMax) return ObjFalse; Array2CArray(db, minMax); while (mainDataset = GetVar(isoField, MAINDATASET)) { isoField = mainDataset; } MakeVar(isoField, NAME); name = GetVar(isoField, NAME); MakeVar(isoField, DEFAULTICON); defaultIcon = GetVar(isoField, DEFAULTICON); if (defaultIcon) { icon = NewObject(defaultIcon, 0); SetVar(icon, NAME, name); SetVar(icon, REPOBJ, isoField); } else { icon = NewIcon(0, 0, ICONQUESTION, GetString(name)); } SetVar(icon, ICONLOC, NULLOBJ); DropIconInCorral(corral, icon); ChooseGoodRange(&(db[0]), &(db[1])); /*Create the isovalue slider*/ slider = TemplateSlider(IsosurfaceTemplate, "Isovalue", SCALE); if (!slider) { return ObjFalse; } PrefixList(panelContents, slider); SetVar(slider, PARENT, panelContents); SetVar(slider, HELPSTRING, NewString("This slider controls the isosurface value shown by an \ isosurface visualization object. Move the indicator to a new desired isosurface value and \ and a new isosurface will be calculated. If you don't want the isosurface \ to be recalculated, you can turn off the icon representing the isosurface \ before you do this. You can get multiple isosurfaces by duplicating the \ isosurface icon.")); scale = TemplateScale(IsosurfaceTemplate, "Iso scale", SO_LEFT, false); PrefixList(panelContents, scale); SetVar(scale, PARENT, panelContents); LinkScale(scale, slider); MakeVar(object, ISOVAL); var = GetRealVar("AddIsoControls", object, ISOVAL); if (var) { initValue = GetReal(var); } else { initValue = (db[0] + db[1]) * 0.5; SetVar(object, ISOVAL, NewReal(initValue)); } SetSliderRange(slider, db[1], db[0], 0.0); AssocDirectControlWithVar(slider, object, ISOVAL); SetTrackNot(slider, true); /*Create the value legend box*/ textBox = TemplateTextBox(IsosurfaceTemplate, "Isovalue Text", ONE_LINE, "Isovalue:"); PrefixList(panelContents, textBox); SetVar(textBox, PARENT, panelContents); top -= TEXTBOXHEIGHT + MINORBORDER; /*Create the value text box*/ textBox = TemplateTextBox(IsosurfaceTemplate, "Isovalue Readout", EDITABLE + WITH_PIT + ONE_LINE, "Isovalue"); PrefixList(panelContents, textBox); SetVar(textBox, PARENT, panelContents); SetTextAlign(textBox, RIGHTALIGN); SliderReadout(slider, textBox); /*Make radio buttons for enclosing*/ radioGroup = NewRadioButtonGroup("Enclose Data"); SetVar(radioGroup, HELPSTRING, NewString("These radio buttons allow you to specify whether high or \ are to be enclosed within the isosurfaces. This information is used to determine \ the direction of surface normals and is also used to improve the behavior of the \ isosurface routine in ambiguous cases.")); checkBox = TemplateRadioButton(IsosurfaceTemplate, "High Values"); SetVar(checkBox, HELPSTRING, NewString("This button specifies that the shapes of the isosurface \ enclose values higher than the isosurface value.")); AddRadioButton(radioGroup, checkBox); checkBox = TemplateRadioButton(IsosurfaceTemplate, "Low Values"); SetVar(checkBox, HELPSTRING, NewString("This button specifies that the shapes of the isosurface \ enclose values lower than the isosurface value.")); AddRadioButton(radioGroup, checkBox); /*Title box around it*/ titleBox = TemplateTitleBox(IsosurfaceTemplate, "Enclose"); PrefixList(panelContents, titleBox); SetVar(titleBox, PARENT, panelContents); /*Add the radio button group*/ PrefixList(panelContents, radioGroup); SetVar(radioGroup, PARENT, panelContents); /*Set its value*/ if (!GetIntVar("AddIsoControls", object, ENCLOSELOW)) { SetVar(object, ENCLOSELOW, NewInt(0)); } AssocDirectControlWithVar(radioGroup, object, ENCLOSELOW); /*Get Normals*/ titleBox = TemplateTitleBox(IsosurfaceTemplate, "Get Normals"); PrefixList(panelContents, titleBox); SetVar(titleBox, PARENT, panelContents); radioGroup = NewRadioButtonGroup("Normal Radio"); SetVar(radioGroup, HELPSTRING, NewString("These radio buttons allow you to specify whether the \ vertex normals of the resulting surface are taken from the geometry or \ from the data. Taking the normals from the data is more accurate and \ produces a smoother surface. \ Taking the normals from the geometry is faster.")); checkBox = TemplateRadioButton(IsosurfaceTemplate, "From Data"); SetVar(checkBox, HELPSTRING, NewString("This button specifies that the surface normals of the \ isosurface be taken from the gradient of the data, run through trilinear \ interpolation.")); AddRadioButton(radioGroup, checkBox); checkBox = TemplateRadioButton(IsosurfaceTemplate, "From Geometry"); SetVar(checkBox, HELPSTRING, NewString("This button specifies that the surface normals of the \ isosurface be calculated from the geometry using Phong lighting.")); AddRadioButton(radioGroup, checkBox); /*Add the radio button group*/ PrefixList(panelContents, radioGroup); SetVar(radioGroup, PARENT, panelContents); AssocDirectControlWithVar(radioGroup, object, NORMALSFROM); return ObjTrue; } #define NHIST 20 #define HISTFRACT 0.25 #define MAXDESIRABLE 2000 static ObjPtr MakeIsoVal(object) ObjPtr object; /*Makes the isoval of an object*/ { real db[2]; real isoVal; ObjPtr repObj; ObjPtr minMax; long histogram[NHIST]; int k; int nTraversalDims; long *traversalDims; long *traversalSteps; long *index; real d; long total; long runningTotal; int subDivision; int advantage; int whichDim; repObj = GetObjectVar("MakeIsoVal", object, MAINDATASET); if (!repObj) { return ObjFalse; } MakeVar(repObj, MINMAX); minMax = GetFixedArrayVar("MakeIsoVal", repObj, MINMAX, 1, 2L); if (!minMax) { return ObjFalse; } Array2CArray(db, minMax); ChooseGoodRange(&(db[0]), &(db[1])); /*Now we have the range, get the iso value*/ SetCurField(FIELD1, repObj); /*Get the information on traversing the dataset*/ nTraversalDims = CountTraversalDims(FIELD1); if (nTraversalDims) { traversalDims = (long *) Alloc(sizeof(long) * nTraversalDims); traversalSteps = (long *) Alloc(sizeof(long) * nTraversalDims); index = (long *) Alloc(sizeof(long) * nTraversalDims); GetTraversalDims(FIELD1, traversalDims); /*Figure out how coarsely to traverse dataset*/ runningTotal = 0; advantage = 1; for (k = 0; k < nTraversalDims; ++k) { runningTotal *= traversalDims[k]; advantage *= 2; } subDivision = 1; while (runningTotal > MAXDESIRABLE) { ++subDivision; runningTotal /= advantage; } /*Zero the histogram*/ for (k = 0; k < NHIST; ++k) { histogram[k] = 0; } /*Zero the index*/ for (k = 0; k < nTraversalDims; ++k) { index[k] = 0; } /*Fill up the histogram*/ do { d = SelectFieldScalar(FIELD1, index); if (d != missingData) { k = ((real) NHIST) * (d - db[0]) / (db[1] - db[0]); if (k < 0) k = 0; if (k >= NHIST) k = NHIST - 1; ++histogram[k]; } /*Advance to next sample*/ for (whichDim = 0; whichDim < nTraversalDims; ++whichDim) { if (traversalDims[whichDim] > 0) { index[whichDim] += subDivision; if (index[whichDim] >= traversalDims[whichDim]) { index[whichDim] = 0; } else { break; } } } } while (whichDim < nTraversalDims); /*Break is based on advance*/ /*Now choose from histogram*/ total = 0; for (k = 0; k < NHIST; ++k) { total += histogram[k]; } runningTotal = 0; for (k = NHIST - 1; k > 1; --k) { runningTotal += histogram[k]; if (runningTotal > HISTFRACT * total) { break; } } ++k; if (k >= NHIST) --k; isoVal = k * (db[1] - db[0]) / NHIST + db[0]; SAFEFREE(index); SAFEFREE(traversalDims); SAFEFREE(traversalSteps); } else { isoVal = (db[0] + db[1]) * 0.5; } SetVar(object, ISOVAL, NewReal(isoVal)); return ObjTrue; } Bool Escape() { int x, y; if (runningScript) { return false; } else { return Mouse(&x, &y); } } ObjPtr NewMakeIsoSurface(object) ObjPtr object; /*Makes a SURFACE in isosurface vis object*/ { ObjPtr repObj; long dims[3]; long index[3]; double time; ObjPtr var; real isoVal; Bool encloseLow; ObjPtr surface; int isoLevel; ObjPtr lastIJK, nextIJK; ObjPtr lastData, nextData, nextPlusData; Bool useDeltas; ObjPtr deltas; time = Clock(); repObj = GetObjectVar("MakeIsoSurface", object, MAINDATASET); if (!repObj) { return ObjFalse; } /*Get the iso value*/ MakeVar(object, ISOVAL); var = GetRealVar("MakeIsoSurface", object, ISOVAL); if (!var) { return ObjFalse; } isoVal = GetReal(var); encloseLow = GetPredicate(object, ENCLOSELOW); useDeltas = GetPredicate(object, NORMALSFROM) ? false : true; LongOperation(); /*Get the isolevel to start at*/ var = GetVar(object, ISOLEVEL); if (var) { isoLevel = GetInt(var); } else { isoLevel = 0; } SetCurField(FIELD1, repObj); SetCurForm(FORMFIELD, repObj); if (CountTraversalDims(FIELD1) != 3) { ReportError("MakeIsoSurface", "Wrong number of traversal dimensions"); return ObjFalse; } GetTraversalDims(FIELD1, dims); if (dims[0] <= 1 || dims[1] <= 1 || dims[2] <= 1) { SetVar(object, SURFACE, NULLOBJ); return ObjTrue; } if (isoLevel) { /*This is just a continuation of a previous incarnation*/ if (isoLevel >= dims[2]) { /*Escape clause; just return*/ return ObjTrue; } surface = GetVar(object, SURFACE); if (!surface) { surface = NewPicture(); SetVar(object, SURFACE, surface); } lastIJK = GetVar(object, LASTIJKVERTICES); if (!lastIJK) { ReportError("MakeIsoSurface", "No LASTIJKVERTICES"); return ObjFalse; } nextIJK = GetVar(object, NEXTIJKVERTICES); if (!nextIJK) { ReportError("MakeIsoSurface", "No NEXTIJKVERTICES"); return ObjFalse; } lastData = GetVar(object, LASTDATA); if (!lastData) { ReportError("MakeIsoSurface", "No LASTDATA"); return ObjFalse; } nextData = GetVar(object, NEXTDATA); if (!nextData) { ReportError("MakeIsoSurface", "No NEXTDATA"); return ObjFalse; } deltas = GetVar(object, DELTAS); } else { long arrayDims[3]; real *elements; long nElements; surface = NewPicture(); SetVar(surface, REPOBJ, object); SetVar(object, SURFACE, surface); arrayDims[0] = dims[0]; arrayDims[1] = dims[1]; arrayDims[2] = 3; /*Make data arrays*/ lastData = NewArray(AT_REAL, 2, arrayDims); SetVar(object, LASTDATA, lastData); nextData = NewArray(AT_REAL, 2, arrayDims); SetVar(object, NEXTDATA, nextData); if (useDeltas) { deltas = NewArray(AT_REAL, 3, arrayDims); /*Make them all missing*/ nElements = arrayDims[0] * arrayDims[1] * arrayDims[2]; elements = ELEMENTS(deltas); do { --nElements; elements[nElements] = missingData; } while (nElements); } else { deltas = NULLOBJ; } /*Fill in the data*/ index[0] = 0; index[1] = 0; index[2] = 0; elements = ELEMENTS(lastData); StuffIJPlane(elements, FIELD1, 0, index); /*Get last data*/ index[0] = 0; index[1] = 0; index[2] = 0; StuffIJPlane((real *) ELEMENTS(lastData), FIELD1, 0, index); /*Get next data*/ index[0] = 0; index[1] = 0; index[2] = 1; StuffIJPlane((real *) ELEMENTS(nextData), FIELD1, 0, index); /*Make IJK arrays*/ lastIJK = NewArray(AT_POINTER, 3, arrayDims); SetVar(object, LASTIJKVERTICES, lastIJK); nextIJK = NewArray(AT_POINTER, 3, arrayDims); SetVar(object, NEXTIJKVERTICES, nextIJK); /*Fill in just the lastIJK*/ StuffIJKVertices(ELEMENTS(lastIJK), ELEMENTS(lastData), ELEMENTS(nextData), deltas ? ELEMENTS(deltas) : 0, FIELD1, FORMFIELD, dims, 0, surface, isoVal, encloseLow); } nextPlusData = NewArray(AT_REAL, 2, dims); /*Go through and do the isosurface*/ while (isoLevel < dims[2] - 1) { index[0] = 0; index[1] = 0; index[2] = isoLevel + 2; /*Get next plus data*/ if (isoLevel < dims[2] - 2) { StuffIJPlane((real *) ELEMENTS(nextPlusData), FIELD1, 0, index); } /*Get next IJK's*/ StuffIJKVertices(ELEMENTS(nextIJK), ELEMENTS(nextData), ELEMENTS(nextPlusData), deltas ? ELEMENTS(deltas) : 0, FIELD1, FORMFIELD, dims, isoLevel + 1, surface, isoVal, encloseLow); /*Now go through and make the isosurface*/ for (index[0] = 0; index[0] < dims[0] - 1; ++index[0]) { for (index[1] = 0; index[1] < dims[1] - 1; ++index[1]) { NewIsoHex(ELEMENTS(lastData), ELEMENTS(nextData), ELEMENTS(lastIJK), ELEMENTS(nextIJK), index, dims, isoVal, surface, encloseLow); } } /*Shift down ijk vertices*/ var = lastIJK; lastIJK = nextIJK; nextIJK = var; /*Shift down data*/ var = lastData; lastData = nextData; nextData = nextPlusData; nextPlusData = var; /*Go to next isoLevel*/ ++isoLevel; #if 0 /*Insert escape code here*/ if (Escape()) { SetVar(object, LASTIJKVERTICES, lastIJK); SetVar(object, NEXTIJKVERTICES, nextIJK); SetVar(object, LASTDATA, lastData); SetVar(object, NEXTDATA, nextData); SetVar(object, ISOLEVEL, NewInt(isoLevel)); SetVar(object, DELTAS, deltas); DeferMessage(object, MAKEISOSURFACE); return ObjFalse; } #endif } if (!deltas) { CalcPictureNormals(surface); } SetVar(object, SURFACE, surface); MakeVar(object, CPALETTE); SetVar(surface, CPALETTE, GetVar(object, CPALETTE)); return ObjTrue; } static ObjPtr MakeIsoSurfaceLater(object) ObjPtr object; /*Sets up to make an isosurface later*/ { FuncTyp method; SetVar(object, ISOLEVEL, NewInt(0)); method = GetMethod(object, MAKEISOSURFACE); if (method) { (*method)(object); } return ObjTrue; } static MakeMethod MakeIsoColors(object) ObjPtr object; /*Makes an isosurface's COLORS and COLOROBJ variable. By default, it looks for the main dataset.*/ { ObjPtr colorObj; ObjPtr mainDataset; ObjPtr var; colorObj = GetVar(object, MAINDATASET); while (var = GetVar(colorObj, MAINDATASET)) { colorObj = var; } /*See if there's a color object within the main dataset*/ if (colorObj) { var = GetVar(colorObj, COLOROBJ); if (var) { colorObj = var; } while (var = GetVar(colorObj, MAINDATASET)) { colorObj = var; } } SetVar(object, COLOROBJ, colorObj); SetVar(object, COLORS, NewInt(0)); return ObjTrue; } void InitIsosurfaces() { ObjPtr icon; int i, j, k; int initState[2][2][2]; int *statePtr; int stateFlags, tempFlags; #ifdef GRAPHICS Object o; float n[3], v[3]; short c[3]; #endif /*Initialize the Free space*/ parts[0] . next = 0; for (k = 1; k < NPARTS; ++k) { parts[k] . next = &(parts[k - 1]); } freePart = &(parts[NPARTS - 1]); /*Zero the polygons*/ for (i = 0; i < 256; ++i) { for (j = 0; j < MAXNPOLYS; ++j) { presetPolys[i][j] = 0; } } /*Fill the polygons*/ for (stateFlags = 0; stateFlags < 256; ++stateFlags) { /*Fill initState based on stateFlag*/ tempFlags = stateFlags; statePtr = &(initState[0][0][0]); for (k = 0; k < 8; ++k) { *statePtr++ = (tempFlags & 128) ? 1 : 0; tempFlags = tempFlags << 1; } if (!CacheIso(initState, stateFlags, false)) { CacheIso(initState, stateFlags, true); } } /*Class for an isosurface*/ isoClass = NewObject(visSurface, 0); AddToReferenceList(isoClass); DefineFixedClass(isoClass, CLASS_ISOSURFACE, "visIso"); SetVar(isoClass, NAME, NewString("Isosurface")); SetMethod(isoClass, ADDCONTROLS, AddIsoControls); SetVar(isoClass, DEFAULTICON, icon = NewObject(visIcon, 0)); SetVar(isoClass, NORMALSFROM, NewInt(0)); AddSnapVar(isoClass, NORMALSFROM); #ifdef GRAPHICS #include "ScianGeoIsosurface.h" SetVar(icon, CACHEGRAPHICS, NewInt(o)); #endif SetVar(icon, WHICHICON, NewInt(ICONISOSURFACE)); SetVar(icon, NAME, NewString("Isosurface")); SetVar(icon, HELPSTRING, NewString("This icon represents an isosurface. \ The isosurface object generates surfaces of constant value through 3-D \ scalar datasets defined over structured grids. Some day it will work with \ nonstructured grids, as well.")); icon = NewIcon(0, 0, ICONISOSURFACE, "Isosurface"); SetVar(icon, HELPSTRING, NewString("Select this icon to show controls for the isosurface, such \ as the isosurface level and the treatment of missing data.")); SetVar(isoClass, CONTROLICON, icon); SetVar(icon, PANELHELP, NewString("The isosurface object displays 3-D scalar \ fields as isosurfaces, or surfaces of constant value, in 3-space. This control panel \ lets you change the parameters of the isosurface.")); SetVar(isoClass, SAVEEXTENSION, NewString("isoSurface")); SetVar(isoClass, HANDLEMISSING, NewInt(0)); AddSnapVar(isoClass, HANDLEMISSING); SetMethod(isoClass, ISOVAL, MakeIsoVal); AddSnapVar(isoClass, ISOVAL); DeclareDependency(isoClass, SURFACE, ISOVAL); DeclareDependency(isoClass, SURFACE, ENCLOSELOW); AddSnapVar(isoClass, ENCLOSELOW); SetVar(isoClass, ENCLOSELOW, NewInt(0)); DeclareIndirectDependency(isoClass, SURFACE, MAINDATASET, CHANGED); DeclareDependency(isoClass, SURFACE, MAINDATASET); DeclareDependency(isoClass, SURFACE, NORMALSFROM); SetMethod(isoClass, MAKEISOSURFACE, NewMakeIsoSurface); SetMethod(isoClass, SURFACE, MakeIsoSurfaceLater); SetMethod(isoClass, COLORS, MakeIsoColors); SetMethod(isoClass, ADDVRCONTROLS, AddIsoVRControls); DefineVisMapping(DS_HASFORM | DS_HASFIELD, 3, 3, -1, isoClass); DefineVisMapping(DS_HASFORM | DS_HASFIELD | DS_VECTOR, 3, 3, -1, isoClass); } void KillIsosurfaces() { DeleteThing(isoClass); }