/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ /* * $Header: /home/gda/dxcvs/dx/src/exec/dxmods/_rubbersheet.c,v 1.3 1999/05/10 15:45:21 gda Exp $: */ #include #include #include #include #include "vectors.h" #include typedef struct { Field field; float scale, offset; } Params; enum PrimType { PRIM_LINES, PRIM_TRIANGLES, PRIM_QUADS, PRIM_INVALID}; #define TRIANGLE(i,j,k) \ *outConnections++ = base + i; \ *outConnections++ = base + j; \ *outConnections++ = base + k; #define QUAD(i,j,k,l) \ *outConnections++ = base + i; \ *outConnections++ = base + j; \ *outConnections++ = base + k; \ *outConnections++ = base + l; static enum PrimType GetPrimType(Field); static Error GetQuadNormal(ArrayHandle, ArrayHandle, int, float *); static Error GetQuadNormals(ArrayHandle, ArrayHandle, int, float **); static Error GetTriNormal(ArrayHandle, ArrayHandle, int, float *); static Error GetTriNormals(ArrayHandle, ArrayHandle, int, float **); static Error _GetTriNormal(float *, float *, float *, float *); static Error _GetQuadNormal(float *, float *, float *, float *, float *); static Error RS_Object(Object, Object, Object, Object); static Error RS_Field(Object, float, float); static Error RS_Field_task(Pointer); static Error RS_Field_PDep_task(Field, float, float); static Error RS_Field_CDep_task(Field, int, int, float, float); static Error SetDefaultColor(Field, int); static Error ValidForRubberSheet(Object); static Error GetScaleAndOffset(Object, Object, Object, Object, float *, float *); Error _dxfRubberSheet(Object ino0, Object scale, Object min, Object max, Object *outo) { Object copy = NULL; *outo = NULL; if (NULL == (copy = DXCopy(ino0, COPY_STRUCTURE))) goto error; if (! DXCreateTaskGroup()) goto error; if (! RS_Object(copy, scale, min, max)) { DXAbortTaskGroup(); goto error; } if (! DXExecuteTaskGroup() || DXGetError() != ERROR_NONE) goto error; *outo = copy; return OK; error: DXDelete((Object)copy); return ERROR; } static Error RS_Object(Object object, Object scale_o, Object min_o, Object max_o) { Class class = DXGetObjectClass(object); if (class == CLASS_GROUP) class = DXGetGroupClass((Group)object); switch(class) { case CLASS_FIELD: { float s, o; if (DXEmptyField((Field)object)) return OK; if (! GetScaleAndOffset(object, scale_o, min_o, max_o, &s, &o)) return ERROR; if (! RS_Field(object, s, o)) return ERROR; if (! DXSetFloatAttribute(object, "RubberSheet scale", s)) return ERROR; return OK; } case CLASS_SERIES: case CLASS_COMPOSITEFIELD: case CLASS_MULTIGRID: { float s, o; if (! GetScaleAndOffset(object, scale_o, min_o, max_o, &s, &o)) return ERROR; if (! RS_Field(object, s, o)) return ERROR; if (! DXSetFloatAttribute(object, "RubberSheet scale", s)) return ERROR; return OK; } case CLASS_GROUP: { Object c; int i; Group g = (Group)object; for (i = 0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++) if (! RS_Object(c, scale_o, min_o, max_o)) return ERROR; return OK; } case CLASS_XFORM: { Object c; if (! DXGetXformInfo((Xform)object, &c, NULL)) return ERROR; if (! RS_Object(c, scale_o, min_o, max_o)) return ERROR; return OK; } case CLASS_CLIPPED: { Object c; if (! DXGetClippedInfo((Clipped)object, &c, NULL)) return ERROR; if (! RS_Object(c, scale_o, min_o, max_o)) return ERROR; return OK; } case CLASS_SCREEN: { Object c; if (! DXGetScreenInfo((Screen)object, &c, NULL, NULL)) return ERROR; if (! RS_Object(c, scale_o, min_o, max_o)) return ERROR; return OK; } default: DXSetError(ERROR_BAD_CLASS, "unknown object encountered in traversal"); return ERROR; } } static Error RS_Field(Object object, float scale, float offset) { Class class = DXGetObjectClass(object); switch(class) { case CLASS_FIELD: { Params params; if (DXEmptyField((Field)object)) return OK; if (! ValidForRubberSheet(object)) return ERROR; params.field = (Field)object; params.scale = scale; params.offset = offset; if (! DXAddTask(RS_Field_task, (Pointer)¶ms, sizeof(params), 1.0)) return ERROR; return OK; } case CLASS_GROUP: { Group g = (Group)object; int i; Object c; for (i = 0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++) if (! RS_Field(c, scale, offset)) return ERROR; return OK; } case CLASS_XFORM: { Object c; if (! DXGetXformInfo((Xform)object, &c, NULL)) return ERROR; if (! RS_Field(c, scale, offset)) return ERROR; return OK; } case CLASS_CLIPPED: { Object c; if (! DXGetClippedInfo((Clipped)object, &c, NULL)) return ERROR; if (! RS_Field(c, scale, offset)) return ERROR; return OK; } case CLASS_SCREEN: { Object c; if (! DXGetScreenInfo((Screen)object, &c, NULL, NULL)) return ERROR; if (! RS_Field(c, scale, offset)) return ERROR; return OK; } default: DXSetError(ERROR_BAD_CLASS, "unknown object encountered in traversal"); return ERROR; } } static Error RS_Field_task(Pointer ptr) { Params *params; float scale, offset; Field field; Object attr; int dDepP, nDepP; params = (Params *)ptr; field = params->field; scale = params->scale; offset = params->offset; if (DXEmptyField(field)) return OK; attr = DXGetComponentAttribute(field, "data", "dep"); if (! attr || DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_INVALID_DATA, "invalid or nonexistant data dependency attribute"); return ERROR; } if (!strcmp(DXGetString((String)attr), "positions")) dDepP = 1; else if (!strcmp(DXGetString((String)attr), "connections")) dDepP = 0; else { DXSetError(ERROR_INVALID_DATA, "invalid data dependency: %s", DXGetString((String)attr)); return ERROR; } /* * If there are no normals input, then by default, normals * dependency follows data. If there is a normals component, * then its dependency overrides. */ nDepP = dDepP; if (DXGetComponentValue(field, "normals")) { attr = DXGetComponentAttribute(field, "normals", "dep"); if (! attr || DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_INVALID_DATA, "invalid or nonexistant normals dependency attribute"); return ERROR; } if (!strcmp(DXGetString((String)attr), "positions")) nDepP = 1; else if (!strcmp(DXGetString((String)attr), "connections")) nDepP = 0; else { DXSetError(ERROR_INVALID_DATA, "invalid normals dependency: %s", DXGetString((String)attr)); return ERROR; } } if (dDepP && nDepP) { if (! RS_Field_PDep_task(field, scale, offset)) return ERROR; } else { if (! RS_Field_CDep_task(field, nDepP, dDepP, scale, offset)) return ERROR; } if (! _dxfNormalsObject((Object)field, "data")) return ERROR; DXDeleteComponent(field, "box"); if (! DXEndField(field)) return ERROR; return OK; } #define STRETCH_POSITIONS_VARYING_NORMAL(type) \ { \ type *ptr = (type *)data; \ \ for (i = 0; i < nPositions; i++) \ { \ float *pt = (float *)DXGetArrayEntry(pHandle, i, pbuf); \ \ vector_scale((Vector *)v_normal, \ scale * (*ptr + offset), (Vector *)s_normal); \ vector_add((Vector *)pt, (Vector *)s_normal, \ (Vector *)outPositions); \ \ ptr += 1; \ v_normal += 3; \ outPositions += 3; \ } \ } #define STRETCH_POSITIONS_CONSTANT_NORMAL(type) \ { \ type *ptr = (type *)data; \ for (i = 0; i < nPositions; i++) \ { \ float *pt = (float *)DXGetArrayEntry(pHandle, i, pbuf); \ \ vector_scale((Vector *)c_normal, \ scale * (*ptr + offset), (Vector *)s_normal); \ vector_add((Vector *)pt, (Vector *)s_normal, \ (Vector *)outPositions); \ \ ptr += 1; \ outPositions += 3; \ } \ } #define STRETCH_POSITIONS_2D(type) \ { \ type *ptr = (type *)data; \ for (i = 0; i < nPositions; i++) \ { \ float *pt = (float *)DXGetArrayEntry(pHandle, i, pbuf); \ for (j = 0; j < nDim; j++) \ *outPositions++ = *pt++; \ \ *outPositions++ = (*ptr++ + offset) * scale; \ } \ } static Error RS_Field_PDep_task(Field field, float scale, float offset) { Array cArray, dArray; Array pArrayIn, pArrayOut; float *outPositions; float *data; enum PrimType primType; int nPositions, nDim; Type type, dataType; Category cat; int rank, shape[32]; ArrayHandle pHandle = NULL; ArrayHandle cHandle = NULL; Pointer pbuf = NULL; pArrayOut = NULL; if ((primType = GetPrimType(field)) == PRIM_INVALID) goto error; cArray = (Array)DXGetComponentValue(field, "connections"); if (! cArray) { DXSetError(ERROR_UNEXPECTED, "missing connections"); goto error; } dArray = (Array)DXGetComponentValue(field, "data"); if (! dArray) { DXSetError(ERROR_UNEXPECTED, "missing data"); goto error; } DXGetArrayInfo(dArray, NULL, &dataType, NULL, NULL, NULL); pArrayIn = (Array)DXGetComponentValue(field, "positions"); DXGetArrayInfo(pArrayIn, &nPositions, &type, &cat, &rank, shape); if (type != TYPE_FLOAT || cat != CATEGORY_REAL || rank != 1) { DXSetError(ERROR_UNEXPECTED, "type/category/rank error"); goto error; } nDim = shape[0]; pHandle = DXCreateArrayHandle(pArrayIn); pbuf = DXAllocate(DXGetItemSize(pArrayIn)); if (! pHandle || ! pbuf) goto error; data = (float *)DXGetArrayData(dArray); /* * If there are already 3 dimensions, we move the point in the normal * direction. Otherwise, we add the next dimension. */ if (nDim == 3) { Array nArray; pArrayOut = DXNewArrayV(type, cat, rank, shape); if (! pArrayOut) goto error; if (! DXAddArrayData(pArrayOut, 0, nPositions, NULL)) goto error; outPositions = (float *)DXGetArrayData(pArrayOut); /* * We need a direction in which to stretch the point. If there are * position normals, use them. Otherwise, assume the data is planar * and get the normal to the plane. */ nArray = (Array)DXGetComponentValue(field, "normals"); if (nArray && !DXQueryConstantArray(nArray, NULL, NULL)) { Object att; float *v_normal, s_normal[3]; int i; att = DXGetComponentAttribute(field, "normals", "dep"); if (! att || DXGetObjectClass(att) != CLASS_STRING) { DXSetError(ERROR_INVALID_DATA, "bad normals dependency attribute"); goto error; } if (strcmp(DXGetString((String)att), "positions")) { DXSetError(ERROR_INVALID_DATA, "normals dependency must match data dependency"); goto error; } v_normal = (float *)DXGetArrayData(nArray); switch(dataType) { case TYPE_DOUBLE: STRETCH_POSITIONS_VARYING_NORMAL(double); break; case TYPE_FLOAT: STRETCH_POSITIONS_VARYING_NORMAL(float); break; case TYPE_UBYTE: STRETCH_POSITIONS_VARYING_NORMAL(ubyte); break; case TYPE_BYTE: STRETCH_POSITIONS_VARYING_NORMAL(byte); break; case TYPE_USHORT: STRETCH_POSITIONS_VARYING_NORMAL(ushort); break; case TYPE_SHORT: STRETCH_POSITIONS_VARYING_NORMAL(short); break; case TYPE_UINT: STRETCH_POSITIONS_VARYING_NORMAL(uint); break; case TYPE_INT: STRETCH_POSITIONS_VARYING_NORMAL(int); break; } } else { float *c_normal, c_normal_buf[3], s_normal[3]; int nConnections; int i; DXGetArrayInfo(cArray, &nConnections, NULL, NULL, NULL, NULL); /* * Now if there is a normals array, it must be constant */ if (nArray) { c_normal = (float *)DXGetConstantArrayData(nArray); } else { cHandle = DXCreateArrayHandle(cArray); if (! cHandle) goto error; if (primType == PRIM_TRIANGLES) { if (! GetTriNormal(pHandle, cHandle, nConnections, c_normal_buf)) { DXSetError(ERROR_INVALID_DATA, "unable to derive a surface normal"); goto error; } } else if (primType == PRIM_QUADS) { if (! GetQuadNormal(pHandle, cHandle, nConnections, c_normal_buf)) { DXSetError(ERROR_INVALID_DATA, "unable to derive a surface normal"); goto error; } } else if (primType == PRIM_LINES) { DXSetError(ERROR_INVALID_DATA, "require position normals for 3D lines"); goto error; } c_normal = c_normal_buf; DXFreeArrayHandle(cHandle); cHandle = NULL; } switch(dataType) { case TYPE_DOUBLE: STRETCH_POSITIONS_CONSTANT_NORMAL(double); break; case TYPE_FLOAT: STRETCH_POSITIONS_CONSTANT_NORMAL(float); break; case TYPE_UBYTE: STRETCH_POSITIONS_CONSTANT_NORMAL(ubyte); break; case TYPE_BYTE: STRETCH_POSITIONS_CONSTANT_NORMAL(byte); break; case TYPE_USHORT: STRETCH_POSITIONS_CONSTANT_NORMAL(ushort); break; case TYPE_SHORT: STRETCH_POSITIONS_CONSTANT_NORMAL(short); break; case TYPE_UINT: STRETCH_POSITIONS_CONSTANT_NORMAL(uint); break; case TYPE_INT: STRETCH_POSITIONS_CONSTANT_NORMAL(int); break; } } } else if (nDim == 2 || nDim == 1) { int i, j; shape[0] ++; pArrayOut = DXNewArrayV(type, cat, rank, shape); if (! pArrayOut) goto error; if (! DXAddArrayData(pArrayOut, 0, nPositions, NULL)) goto error; outPositions = (float *)DXGetArrayData(pArrayOut); switch(dataType) { case TYPE_DOUBLE: STRETCH_POSITIONS_2D(double); break; case TYPE_FLOAT: STRETCH_POSITIONS_2D(float); break; case TYPE_UBYTE: STRETCH_POSITIONS_2D(ubyte); break; case TYPE_BYTE: STRETCH_POSITIONS_2D(byte); break; case TYPE_USHORT: STRETCH_POSITIONS_2D(ushort); break; case TYPE_SHORT: STRETCH_POSITIONS_2D(short); break; case TYPE_UINT: STRETCH_POSITIONS_2D(uint); break; case TYPE_INT: STRETCH_POSITIONS_2D(int); break; } } DXSetComponentValue(field, "positions", (Object)pArrayOut); pArrayOut = NULL; /* * If there's a colors component, use it. Otherwise, create one. */ if (!DXGetComponentValue(field, "colors") && !DXGetComponentValue(field, "front colors")) if (! SetDefaultColor(field, nPositions)) goto error; DXDeleteComponent(field, "normals"); DXFreeArrayHandle(pHandle); DXFreeArrayHandle(cHandle); DXFree(pbuf); DXEndField(field); return OK; error: DXFreeArrayHandle(pHandle); DXFreeArrayHandle(cHandle); DXFree(pbuf); DXDelete((Object)pArrayOut); return ERROR; } #define STRETCH_CONNECTIONS_3D(type) \ { \ type *data; \ \ data = (type *)inData; \ for (i = 0; i < nConnections; i++) \ { \ int *elt; \ \ elt = (int *)DXGetArrayEntry(cHandle, i, (Pointer)ebuf); \ \ if (! dDepP) \ { \ scaledData = scale * (data[i] + offset); \ \ if (! nDepP || cst_normal) \ if (cst_normal) \ { \ vector_scale((Vector *)cst_normal, \ scaledData, (Vector *)s_normal); \ } \ else \ { \ vector_scale(((Vector *)normals)+i, \ scaledData, (Vector *)s_normal); \ } \ } \ \ for (j = 0; j < nVerts; j++) \ { \ float *pt, pbuf[3]; \ int pNum; \ \ pNum = *elt++; \ \ pt = (float *)DXGetArrayEntry(pHandle, \ pNum, (Pointer)pbuf); \ \ *outPositions++ = pt[0]; \ *outPositions++ = pt[1]; \ *outPositions++ = pt[2]; \ \ if (dDepP) \ { \ scaledData = scale * (data[pNum] + offset); \ if (! nDepP) \ if (cst_normal) \ vector_scale(((Vector *)cst_normal), \ scaledData, (Vector *)s_normal); \ else \ vector_scale(((Vector *)normals)+i, \ scaledData, (Vector *)s_normal); \ } \ else \ { \ if (nDepP && !cst_normal) \ vector_scale(((Vector *)normals)+pNum, \ scaledData, (Vector *)s_normal); \ } \ \ vector_add((Vector *)pt, \ (Vector *)s_normal, (Vector *)outPositions); \ \ outPositions += 3; \ } \ \ } \ } #define STRETCH_CONNECTIONS_2D(type) \ { \ type *data = (type *)inData; \ \ for (i = 0; i < nConnections; i++) \ { \ int *elt; \ \ elt = (int *)DXGetArrayEntry(cHandle, i, (Pointer)ebuf); \ \ if (!dDepP) \ scaledData = scale * (data[i] + offset); \ \ for (j = 0; j < nVerts; j++) \ { \ float *pt, pbuf[2]; \ int pNum; \ \ pNum = *elt++; \ \ if (dDepP) \ scaledData = scale * (data[pNum] + offset); \ \ pt = (float *)DXGetArrayEntry(pHandle, \ pNum, (Pointer)pbuf); \ \ for (k = 0; k < nDim; k++) \ *outPositions++ = pt[k]; \ *outPositions++ = 0.0; \ \ for (k = 0; k < nDim; k++) \ *outPositions++ = pt[k]; \ *outPositions++ = scaledData; \ } \ } \ } static Error RS_Field_CDep_task(Field field, int nDepP, int dDepP, float scale, float offset) { Array dArrayIn; Array pArrayIn, pArrayOut; Array cArrayIn, cArrayOut; float *outPositions; int *outConnections; Pointer inData; int nConnections; enum PrimType primType; int nPositions, nDim, nVerts, outPerIn; Type type, dataType; Category cat; int rank, shape[32], i, j, k; float scaledData, *point; float s_normal[3], *c_normals = NULL; int cstNormal = 0; Object attr; char *name; Array inA, outA = NULL; ArrayHandle pHandle = NULL; ArrayHandle cHandle = NULL; int *ebuf = NULL; char *toDelete[100]; int nDelete; InvalidComponentHandle iInv = NULL, oInv = NULL; cArrayOut = NULL; pArrayOut = NULL; if (DXEmptyField(field)) return OK; if (! DXInvalidateConnections((Object)field)) goto error; if ((primType = GetPrimType(field)) == PRIM_INVALID) goto error; cArrayIn = (Array)DXGetComponentValue (field, "connections"); if (! cArrayIn) { DXSetError(ERROR_UNEXPECTED, "missing connections"); goto error; } DXGetArrayInfo(cArrayIn, &nConnections, NULL, NULL, NULL, &nVerts); dArrayIn = (Array)DXGetComponentValue (field, "data"); if (! dArrayIn) { DXSetError(ERROR_UNEXPECTED, "missing data"); goto error; } DXGetArrayInfo(dArrayIn, NULL, &dataType, NULL, NULL, NULL); pArrayIn = (Array)DXGetComponentValue(field, "positions"); if (! pArrayIn) { DXSetError(ERROR_UNEXPECTED, "missing positions"); goto error; } DXGetArrayInfo(pArrayIn, &nPositions, &type, &cat, &rank, shape); nDim = shape[0]; if (nDim > 3) { DXSetError(ERROR_INVALID_DATA, ">3D positions not supported"); goto error; } cHandle = DXCreateArrayHandle(cArrayIn); pHandle = DXCreateArrayHandle(pArrayIn); if (! cHandle || ! pHandle) goto error; ebuf = (int *)DXAllocate(nVerts*sizeof(int)); if (! ebuf) goto error; inData = DXGetArrayData(dArrayIn); if (DXGetComponentValue(field, "invalid connections")) { iInv = DXCreateInvalidComponentHandle((Object)field, NULL, "connections"); if (! iInv) goto error; } if (nDim == 3) { float *normals = NULL; float *cst_normal = NULL; Array nArray; /* * Get normals. Options are: position dependent normals, * connections dependent normals and none at all. In the * last case, generate one dep on connections. */ nArray = (Array)DXGetComponentValue(field, "normals"); if (nArray && DXQueryConstantArray(nArray, NULL, NULL)) { cst_normal = (float *)DXGetConstantArrayData(nArray); } else if (nArray) { normals = (float *)DXGetArrayData(nArray); } else if (primType == PRIM_TRIANGLES) { if (! GetTriNormals(pHandle, cHandle, nConnections, &normals)) goto error; } else if (primType == PRIM_QUADS) { if (! GetQuadNormals(pHandle, cHandle, nConnections, &normals)) goto error; } else if (primType == PRIM_LINES) { DXSetError(ERROR_MISSING_DATA, "normals component required for lines in 3-space"); goto error; } pArrayOut = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); if (! DXAddArrayData(pArrayOut, 0, 2*nVerts*nConnections, NULL)) goto error; outPositions = (float *)DXGetArrayData(pArrayOut); switch(dataType) { case TYPE_DOUBLE: STRETCH_CONNECTIONS_3D(double); break; case TYPE_FLOAT: STRETCH_CONNECTIONS_3D(float); break; case TYPE_INT: STRETCH_CONNECTIONS_3D(int); break; case TYPE_UINT: STRETCH_CONNECTIONS_3D(uint); break; case TYPE_SHORT: STRETCH_CONNECTIONS_3D(short); break; case TYPE_USHORT: STRETCH_CONNECTIONS_3D(ushort); break; case TYPE_UBYTE: STRETCH_CONNECTIONS_3D(ubyte); break; case TYPE_BYTE: STRETCH_CONNECTIONS_3D(byte); break; } if (! nArray && normals) DXFree((Pointer)normals); } else { pArrayOut = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, nDim+1); if (! DXAddArrayData(pArrayOut, 0, 2*nVerts*nConnections, NULL)) goto error; outPositions = (float *)DXGetArrayData(pArrayOut); switch(dataType) { case TYPE_DOUBLE: STRETCH_CONNECTIONS_2D(double); break; case TYPE_FLOAT: STRETCH_CONNECTIONS_2D(float); break; case TYPE_UINT: STRETCH_CONNECTIONS_2D(uint); break; case TYPE_INT: STRETCH_CONNECTIONS_2D(int); break; case TYPE_USHORT: STRETCH_CONNECTIONS_2D(ushort); break; case TYPE_SHORT: STRETCH_CONNECTIONS_2D(short); break; case TYPE_BYTE: STRETCH_CONNECTIONS_2D(byte); break; case TYPE_UBYTE: STRETCH_CONNECTIONS_2D(ubyte); break; } } switch (primType) { case PRIM_TRIANGLES: { cArrayOut = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3); if (! cArrayOut) goto error; if (! DXAddArrayData(cArrayOut, 0, 8*nConnections, NULL)) goto error; outConnections = (int *)DXGetArrayData(cArrayOut); for (i = 0; i < nConnections; i++) { int base; /* * base is the index of the first of the 6 points * corresponding to input triangle i (and hence output prism * i). */ base = i*6; TRIANGLE(1,3,5); TRIANGLE(0,4,2); TRIANGLE(5,3,2); TRIANGLE(5,2,4); TRIANGLE(3,1,0); TRIANGLE(3,0,2); TRIANGLE(1,5,4); TRIANGLE(1,4,0); } outPerIn = 8; } break; case PRIM_QUADS: { cArrayOut = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 4); if (! cArrayOut) goto error; if (! DXAddArrayData(cArrayOut, 0, 6*nConnections, NULL)) goto error; outConnections = (int *)DXGetArrayData(cArrayOut); for (i = 0; i < nConnections; i++) { int base; /* * base is the index of the first of the 8 points * corresponding to input quad i (and hence output box i). */ base = i<<3; QUAD(0,1,2,3); QUAD(4,5,6,7); QUAD(1,5,0,4); QUAD(0,4,2,6); QUAD(2,6,3,7); QUAD(3,7,1,5); } outPerIn = 6; } break; case PRIM_LINES: { cArrayOut = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 4); if (! cArrayOut) goto error; if (! DXAddArrayData(cArrayOut, 0, nConnections, NULL)) goto error; outConnections = (int *)DXGetArrayData(cArrayOut); for (i = 0; i < nConnections; i++) { int base; /* * base is the index of the first of the 8 points * corresponding to input quad i (and hence output box i). */ base = i<<2; QUAD(0,1,2,3); } outPerIn = 1; } break; } /* * DXDelete components that are no longer appropriate. */ DXDeleteComponent(field, "normals"); DXDeleteComponent(field, "box"); DXDeleteComponent(field, "data statistics"); DXDeleteComponent(field, "front colors"); DXDeleteComponent(field, "back colors"); DXDeleteComponent(field, "invalid positions"); /* * Need to get rid of everything that deps refs or ders positions. * Before doing so, delete the connections component to break the recursion * chain - we do not want to delete data, for example, and because it is * dep on connections, it would get deleted by the recursive call when * DXChangedComponentStructure notices that connections refs positions and * calls itself recursively on it. */ DXDeleteComponent(field, "connections"); /* * Set new positions and connections arrays. */ if (! DXSetComponentValue(field, "positions", (Object)pArrayOut)) goto error; pArrayOut = NULL; if (! DXSetComponentValue(field, "connections", (Object)cArrayOut)) goto error; cArrayOut = NULL; switch(primType) { case PRIM_LINES: case PRIM_QUADS: if (! DXSetComponentAttribute(field, "connections", "element type", (Object)DXNewString("quads"))) goto error; break; case PRIM_TRIANGLES: if (! DXSetComponentAttribute(field, "connections", "element type", (Object)DXNewString("triangles"))) goto error; break; } i = 0; nDelete = 0; while ((inA=(Array)DXGetEnumeratedComponentValue(field, i++, &name)) != NULL) { char *src; char *dst; int itemSize; int j, k; Type t; Category c; int n, r, s[32]; if (! strcmp(name, "connections") || ! strcmp(name, "positions")) continue; if ((attr = DXGetComponentAttribute(field, name, "dep")) == NULL) continue; if (DXGetComponentAttribute(field, name, "ref") || DXGetComponentAttribute(field, name, "der")) { toDelete[nDelete++] = name; continue; } if (! strcmp(DXGetString((String)attr), "positions")) { DXGetArrayInfo(inA, &n, &t, &c, &r, s); if (DXQueryConstantArray(inA, NULL, NULL)) { outA = (Array)DXNewConstantArrayV(2*nVerts*nConnections, DXGetConstantArrayData(inA), t, c, r, s); } else { outA = DXNewArrayV(t, c, r, s); if (! outA) goto error; if (! DXAddArrayData(outA, 0, 2*nVerts*nConnections, NULL)) goto error; itemSize = DXGetItemSize(inA); src = (char *)DXGetArrayData(inA); dst = (char *)DXGetArrayData(outA); for (j = 0; j < nConnections; j++) { int *e = (int *)DXGetArrayEntry(cHandle, j, ebuf); for (k = 0; k < nVerts; k++) { memcpy(dst, src+e[k]*itemSize, itemSize); dst += itemSize; memcpy(dst, src+e[k]*itemSize, itemSize); dst += itemSize; } } } } else if (! strcmp(DXGetString((String)attr), "connections")) { DXGetArrayInfo(inA, &n, &t, &c, &r, s); if (DXQueryConstantArray(inA, NULL, NULL)) { outA = (Array)DXNewConstantArrayV(outPerIn*n, DXGetConstantArrayData(inA), t, c, r, s); } else { outA = DXNewArrayV(t, c, r, s); if (! outA) goto error; if (! DXAddArrayData(outA, 0, outPerIn*n, NULL)) goto error; itemSize = DXGetItemSize(inA); src = (char *)DXGetArrayData(inA); dst = (char *)DXGetArrayData(outA); for (j = 0; j < n; j++) { for (k = 0; k < outPerIn; k++) { memcpy(dst, src, itemSize); dst += itemSize; } src += itemSize; } } } else { DXSetError(ERROR_INVALID_DATA, "invalid dependency: %s", DXGetString((String)attr)); goto error; } if (! DXSetComponentValue(field, name, (Object)outA)) goto error; outA = NULL; } if (! DXGetComponentValue(field, "colors")) { if (! SetDefaultColor(field, outPerIn*nConnections)) goto error; if (! DXSetComponentAttribute(field, "colors", "dep", (Object)DXNewString("connections"))) goto error; } if (iInv) { int k = 0; oInv = DXCreateInvalidComponentHandle((Object)cArrayOut, NULL, "connections"); if (! oInv) goto error; for (i = 0; i < nConnections; i++) if (DXIsElementInvalid(iInv, i)) { for (j = 0; j < outPerIn; j++) if (! DXSetElementInvalid(oInv, k++)) goto error; } else k += outPerIn; if (! DXSaveInvalidComponent(field, oInv)) goto error; } for (i = 0; i < nDelete; i++) DXDeleteComponent(field, toDelete[i]); if (iInv) DXFreeInvalidComponentHandle(iInv); if (oInv) DXFreeInvalidComponentHandle(oInv); DXFree((Pointer)ebuf); DXFreeArrayHandle(pHandle); DXFreeArrayHandle(cHandle); DXEndField(field); return OK; error: if (iInv) DXFreeInvalidComponentHandle(iInv); if (oInv) DXFreeInvalidComponentHandle(oInv); DXFree((Pointer)ebuf); DXFreeArrayHandle(pHandle); DXFreeArrayHandle(cHandle); DXFree((Pointer)c_normals); DXDelete((Object)pArrayOut); DXDelete((Object)cArrayOut); DXDelete((Object)outA); return ERROR; } static Error GetQuadNormal(ArrayHandle pHandle, ArrayHandle cHandle, int n, float *normal) { int j, p, q, r; for (j = 0; j < n; j++, normal += 3) { int *quad, quadbuf[4]; float *p, *q, *r, *s; float pbuf[3], qbuf[3], rbuf[3], sbuf[3]; quad = (int *)DXGetArrayEntry(cHandle, j, (Pointer)quadbuf); p = (float *)DXGetArrayEntry(pHandle, quad[0], (Pointer)pbuf); q = (float *)DXGetArrayEntry(pHandle, quad[1], (Pointer)qbuf); r = (float *)DXGetArrayEntry(pHandle, quad[2], (Pointer)rbuf); s = (float *)DXGetArrayEntry(pHandle, quad[3], (Pointer)sbuf); if (! _GetQuadNormal(p, q, r, s, normal)) continue; return OK; } return ERROR; } static Error GetQuadNormals(ArrayHandle pHandle, ArrayHandle cHandle, int n, float **normals) { int j, p, q, r; float *ptr; *normals = (float *)DXAllocateLocal(n * 3 * sizeof(float)); if (! *normals) { DXResetError(); *normals = (float *)DXAllocate(n * 3 * sizeof(float)); } if (! *normals) return ERROR; ptr = *normals; for (j = 0; j < n; j++, ptr += 3) { int *quad, quadbuf[4]; float *p, *q, *r, *s; float pbuf[3], qbuf[3], rbuf[3], sbuf[3]; quad = (int *)DXGetArrayEntry(cHandle, j, (Pointer)quadbuf); p = (float *)DXGetArrayEntry(pHandle, quad[0], (Pointer)pbuf); q = (float *)DXGetArrayEntry(pHandle, quad[1], (Pointer)qbuf); r = (float *)DXGetArrayEntry(pHandle, quad[2], (Pointer)rbuf); s = (float *)DXGetArrayEntry(pHandle, quad[3], (Pointer)sbuf); if (! _GetQuadNormal(p, q, r, s, ptr)) ptr[0] = ptr[1] = ptr[2] = 0; } return OK; } static Error GetTriNormal(ArrayHandle pHandle, ArrayHandle cHandle, int n, float *normal) { int j; for (j = 0; j < n; j++) { int *tri, tbuf[3]; float *p, *q, *r; float pbuf[3], qbuf[3], rbuf[3]; tri = (int *)DXGetArrayEntry(cHandle, j, (Pointer)tbuf); p = (float *)DXGetArrayEntry(pHandle, tri[0], (Pointer)pbuf); q = (float *)DXGetArrayEntry(pHandle, tri[1], (Pointer)qbuf); r = (float *)DXGetArrayEntry(pHandle, tri[2], (Pointer)rbuf); if (_GetTriNormal(p, q, r, normal)) return OK; } return ERROR; } static Error GetTriNormals(ArrayHandle pHandle, ArrayHandle cHandle, int n, float **normals) { int j; float *ptr; *normals = (float *)DXAllocateLocal(n * 3 * sizeof(float)); if (! *normals) { DXResetError(); *normals = (float *)DXAllocate(n * 3 * sizeof(float)); } if (! *normals) return ERROR; ptr = *normals; for (j = 0; j < n; j++, ptr+=3) { int *tri, tbuf[3]; float *p, *q, *r, pbuf[3], qbuf[3], rbuf[3]; tri = (int *)DXGetArrayEntry(cHandle, j, (Pointer)tbuf); p = (float *)DXGetArrayEntry(pHandle, tri[0], (Pointer)pbuf); q = (float *)DXGetArrayEntry(pHandle, tri[1], (Pointer)qbuf); r = (float *)DXGetArrayEntry(pHandle, tri[2], (Pointer)rbuf); if (! _GetTriNormal(p, q, r, ptr)) ptr[0] = ptr[1] = ptr[2] = 0.0; } return OK; } static Error _GetTriNormal(float *p, float *q, float *r, float *normal) { float v0[3], v1[3], d; vector_subtract((Vector *)q, (Vector *)p, (Vector *)v0); vector_subtract((Vector *)r, (Vector *)p, (Vector *)v1); vector_cross((Vector *)v0, (Vector *)v1, (Vector *)normal); d = vector_length((Vector *)normal); if (d == 0.0) return ERROR; else vector_scale((Vector *)normal, 1.0/d, (Vector *)normal); return OK; } static Error _GetQuadNormal(float *p, float *q, float *r, float *s, float *normal) { float v0[3], v1[3], d, cross[3]; vector_subtract((Vector *)q, (Vector *)p, (Vector *)v0); vector_subtract((Vector *)r, (Vector *)p, (Vector *)v1); vector_cross((Vector *)v1, (Vector *)v0, (Vector *)normal); vector_subtract((Vector *)s, (Vector *)q, (Vector *)v0); vector_subtract((Vector *)p, (Vector *)q, (Vector *)v1); vector_cross((Vector *)v1, (Vector *)v0, (Vector *)cross); vector_add((Vector *)normal, (Vector *)cross, (Vector *)normal); vector_subtract((Vector *)r, (Vector *)s, (Vector *)v0); vector_subtract((Vector *)q, (Vector *)s, (Vector *)v1); vector_cross((Vector *)v1, (Vector *)v0, (Vector *)cross); vector_add((Vector *)normal, (Vector *)cross, (Vector *)normal); vector_subtract((Vector *)p, (Vector *)r, (Vector *)v0); vector_subtract((Vector *)s, (Vector *)r, (Vector *)v1); vector_cross((Vector *)v1, (Vector *)v0, (Vector *)cross); vector_add((Vector *)normal, (Vector *)cross, (Vector *)normal); d = vector_length((Vector *)normal); if (d == 0.0) return ERROR; else vector_scale((Vector *)normal, 1.0/d, (Vector *)normal); return OK; } static enum PrimType GetPrimType(Field field) { Object attr; char *str; attr = DXGetComponentAttribute(field, "connections", "element type"); if (! attr) { if (! DXGetComponentValue(field, "connections")) DXSetError(ERROR_MISSING_DATA, "connections"); else DXSetError(ERROR_MISSING_DATA, "element type attribute"); return PRIM_INVALID; } if (DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_INTERNAL, "element type attribute not STRING"); return PRIM_INVALID; } str = DXGetString((String)attr); if (! strcmp(str, "lines")) return PRIM_LINES; else if (! strcmp(str, "quads")) return PRIM_QUADS; else if (! strcmp(str, "triangles")) return PRIM_TRIANGLES; DXSetError(ERROR_INVALID_DATA, "element type %s not supported", str); return PRIM_INVALID; } static Error SetDefaultColor(Field field, int n) { RegularArray array; float color[3]; float delta[3]; color[0] = 0.5; color[1] = 0.7; color[2] = 1.0; delta[0] = 0.0; delta[1] = 0.0; delta[2] = 0.0; array = DXNewRegularArray(TYPE_FLOAT, 3, n, (Pointer)color, (Pointer)delta); if (! array) return ERROR; DXSetComponentValue(field, "colors", (Object)array); return OK; } static Error ValidForRubberSheet(Object object) { Category cat; int rank, shape[32]; if (! DXGetType(object, NULL, &cat, &rank, shape) || (cat != CATEGORY_REAL) || (! (rank == 0 || (rank == 1 && shape[0] == 1)))) { DXSetError(ERROR_INVALID_DATA, "invalid data: scalar or 1-vector real data required"); return ERROR; } return OK; } static Error GetScaleAndOffset(Object obj, Object scale_o, Object min_o, Object max_o, float *scale, float *offset) { float thickness; float max, min; Class class; int i; Field field; if (! DXStatistics(obj, "data", &min, &max, NULL, NULL)) { DXAddMessage("#10520","data"); return ERROR; } if (min_o) { if (! DXExtractParameter(min_o, TYPE_FLOAT, 1, 1, (Pointer)&min)) { class = DXGetObjectClass(min_o); if ((class != CLASS_GROUP) && (class != CLASS_FIELD)) { /* * min must be a field or a scalar value */ DXSetError(ERROR_BAD_PARAMETER, "#10520", "min"); return ERROR; } if (! DXStatistics(min_o, "data", &min, NULL, NULL, NULL)) { /* * min must be a field or a scalar value */ DXAddMessage("#10520","min"); return ERROR; } } *offset = -min; } else *offset = 0.0; if (max_o) { if (! DXExtractParameter(max_o, TYPE_FLOAT, 1, 1, (Pointer)&max)) { class = DXGetObjectClass(max_o); if ((class != CLASS_GROUP) && (class != CLASS_FIELD)) { /* * max must be a field or a scalar value */ DXSetError(ERROR_BAD_PARAMETER, "#10520", "max"); return ERROR; } if (! DXStatistics(max_o, "data", NULL, &max, NULL, NULL)) { /* * max must be a field or a scalar value */ DXAddMessage("#10520","max"); return ERROR; } } } if (scale_o) { if (! DXExtractParameter (scale_o, TYPE_FLOAT, 1, 1, (Pointer)scale)) { /* * scale must be a scalar value */ DXSetError (ERROR_BAD_PARAMETER, "#10080", "scale"); return ERROR; } } else { Point boxPoints[8]; if (! DXBoundingBox(obj, boxPoints)) return (ERROR); thickness = DXLength(DXSub(boxPoints[7], boxPoints[0])); if (thickness == 0.0) { *scale = 0; } else { if (min == max) { *scale = 1.0; } else { *scale = thickness / (10.0 * (max - min)); } } } return OK; }