/***********************************************************************/ /* 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" */ /***********************************************************************/ #include #include #include #include #include "eigen.h" #define TRUE 1 #define FALSE 0 #define DIMENSION3D 3 #define DIMENSION2D 2 #define MAX(a,b) ((a>=b) ? a : b)) extern Error _dxfGetFieldTensorStats(Field, float *, float *); extern int _dxfIsTensor(Object); extern Error _dxfGetTensorStats(Object, float *, float *); extern Error _dxfDXEmptyObject(Object); extern Error _dxfProcessGlyphObject(Object, Object, char *, float, float, int, float, int, float, int, float, int, float, int, Object, int, int, char *, int *, float *); extern Error _dxfIndexGlyphObject(Object, Object, float); static Error IndexGlyphField(Field, Object, float); extern Error _dxfGetFontName(char *, char *); static Error CheckGlyphGroup(Object, int *, int *, char *); extern Array _dxfPostArray(Field, char *, char *); extern Error _dxfGlyphTask(Pointer); extern Error _dxfGetStatisticsAndSize(Object, char *, int, float *, int, float *, float *, int *); static Error GlyphXform2d(Matrix, int, Point *, float *); extern Error _dxfTextField(Pointer); static Error GetEigenVectors(Stress_Tensor, Vector *); static Error GetEigenVectors2(Stress_Tensor2, Vector *); static Error TextGlyphs(Group, char *, Matrix, RGBColor, float, char *); static Matrix GlyphAlign (Vector, Vector); extern Error _dxfWidthHeuristic(Object, float *); static Error IncrementConnections(int, int, Triangle *, Triangle *); static Error IncrementConnectionsLines(int, int, Line *, Line *); static Error GlyphXform(Matrix, int, Point *, Point *); static Error GetNumberValidPositions(Object, int *); static Error GlyphNormalXform(Matrix, int, Point *, Point *); extern int _dxfIsFieldorGroup(Object); static Error GetGlyphName(float, char *, int, char *, char *, char *, int *); static Error GetGlyphs(char *, int *, int *, Point **, Triangle **, Point **, Line **, int *, char *); static Error GetGlyphField(Object, int *, int *, Point **, Triangle **, Line **, Point **, Matrix *, int *, int *, int *, char *); static int DivideByZero(float, float); extern Error _dxfMakeGlyphs(Object *, char *, float, float, int, float, int, float, int, float, int, float, int, Object, int, Group, int); extern Error _dxf_MakeGlyphs(Object, char *, float, float, int, float, int, float, int, float, int, float, int, Object, int, Group, int); extern Error _dxfMakeTextGlyphs(Object, Object, Object, int, int, float, char *); extern int _dxfFieldWithInformation(Object); static _dxfHasDataComponent(Object); typedef struct Point2D { float x; float y; } Point2D; typedef struct arg { Object outobject; char type[30]; Object typefield; int type_is_field; float shape; float scale; int scale_set; float ratio; int ratio_set; float given_min; int min_set; float given_max; int max_set; float quality; float base_size; int AutoSize; Object parent; int parentindex; char font[100]; } Arg; typedef struct textarg { Object inobject; Object outobject; int colored; float scale; char font[100]; } Textarg; static RGBColor DEFAULT_SCALAR_COLOR = { 0.5, 0.7, 1.0}; static RGBColor OVERRIDE_SCALAR_COLOR = { 1.0, 0.8, 0.8}; static RGBColor DEFAULT_VECTOR_COLOR = { 0.7, 0.7, 0.0}; static RGBColor DEFAULT_TENSOR_COLOR = { 1.0, 0.0, 0.0}; int _dxfIsFieldorGroup(Object ob) { Class cl; if ( ((cl = DXGetObjectClass(ob)) == CLASS_FIELD) || (cl == CLASS_GROUP) ) return OK; else return ERROR; } Error _dxfTextField(Pointer p) { Object inobject, outobject; Array positions=NULL, data, colors, colormap, invalid_pos; int invalid; float scale; InvalidComponentHandle invalidhandle=NULL; Stress_Tensor t; int numcoloritems, n; Type type, colorstype; Category category; int numitems, rank, posshape[30], datashape[30], i, colored, reginputcolors; int colorsrank, colorsshape[30], delayedcolors=0, posted, counts[30], j; char glyph_rank[30]; float s, posorigin[30], posdeltas[30]; Vector v; unsigned char *colors_byte_ptr; RGBColor color, colororigin, *colors_ptr; char string[100], *string1, *attr, *font; Matrix translation; float *data_ptr_f; ubyte *data_ptr_ub; byte *data_ptr_b; short *data_ptr_s; ushort *data_ptr_us; double *data_ptr_d; int *data_ptr_i; uint *data_ptr_ui; ArrayHandle handle=NULL; Pointer scratch=NULL; float *position=NULL; /* this routine has the object stripped down to the bottom field level of Object in. Object out is a group to put text glyphs into */ /* inobject is a copy which needs to be deleted */ Textarg *textarg = (Textarg *)p; inobject = textarg->inobject; outobject = textarg->outobject; colored = textarg->colored; scale = textarg->scale; font = textarg->font; /* Get the positions and data components of the input object */ data = (Array)DXGetComponentValue((Field)inobject,"data"); if (!data) { DXSetError(ERROR_MISSING_DATA, "data component required for text glyphs"); goto error; } attr = DXGetString((String)DXGetComponentAttribute((Field)inobject, "data", "dep")); if (!attr) { DXSetError(ERROR_INVALID_DATA,"#10255", "data","dep"); goto error; } posted = 0; /* check the attribute */ if (strcmp(attr,"connections") && (strcmp(attr,"positions"))) { DXSetError(ERROR_INVALID_DATA,"unsupported data dependency \'%s\'",attr); goto error; } if (!strcmp(attr,"connections")) { /* I need to check whether the positions are regular. If they * are, a simple grid shift is in order. Otherwise, use PostArray * to shift them */ Array pos, con; pos = (Array)DXGetComponentValue((Field)inobject,"positions"); con = (Array)DXGetComponentValue((Field)inobject,"connections"); if ((DXQueryGridPositions(pos, &n, counts, posorigin, posdeltas)) && DXQueryGridConnections(con, NULL, NULL)) { for (i=0; i 1) { posorigin[i]+=0.5*posdeltas[i + j*n]; } } } for (i=0; i1) counts[i] = counts[i]-1; } positions = DXMakeGridPositionsV(n, counts, posorigin, posdeltas); } /* else the positions are irregular */ else { positions = _dxfPostArray((Field)inobject, "positions","connections"); } if (!positions) { DXSetError(ERROR_BAD_PARAMETER, "could not compute glyph positions for cell-centered data"); goto error; } posted = 1; if (!DXGetArrayInfo(positions,&numitems, &type, &category, &rank, posshape)) goto error; } else if (!strcmp(attr,"faces")) { positions = _dxfPostArray((Field)inobject, "positions","faces"); if (!positions) { DXAddMessage("could not compute glyph positions for face-centered data"); goto error; } posted = 1; if (!DXGetArrayInfo(positions,&numitems, &type, &category, &rank, posshape)) goto error; } /* else dep positions */ else { positions = (Array)DXGetComponentValue((Field)inobject,"positions"); if (!positions) { DXSetError(ERROR_BAD_PARAMETER,"field has no positions"); goto error; } if (!DXGetArrayInfo(positions,&numitems, &type, &category, &rank, posshape)) goto error; } if ((type != TYPE_FLOAT)||(category != CATEGORY_REAL)) { DXSetError(ERROR_INVALID_DATA, "positions must be type float category real"); goto error; } if (rank != 1) { DXSetError(ERROR_INVALID_DATA,"positions must be rank 1"); goto error; } if ((posshape[0] < 1) || (posshape[0] > 3)) { DXSetError(ERROR_INVALID_DATA,"positions must be 1D, 2D, or 3D"); goto error; } DXGetArrayInfo(data, &numitems, &type, &category, &rank, datashape); if (category != CATEGORY_REAL) { DXSetError(ERROR_INVALID_DATA,"data must be category real"); goto error; } if (rank==0) strcpy(glyph_rank,"scalar"); else if (rank==1 && datashape[0] == 1) strcpy(glyph_rank,"scalar"); else if (rank==1 && datashape[0] == 2) strcpy(glyph_rank,"2-vector"); else if (rank==1 && datashape[0] == 3) strcpy(glyph_rank,"3-vector"); else if (rank==2 && datashape[0]==3 &&datashape[1]==3) strcpy(glyph_rank,"matrix"); else if (rank==2 && datashape[0]==2 &&datashape[1]==2) strcpy(glyph_rank,"matrix2"); else if (type != TYPE_STRING) { DXSetError(ERROR_INVALID_DATA, "data must be string, scalar, 2-vector, 3-vector, 2x2 or 3x3 matrix"); goto error; } /* get the colors component, if necessary, and if present */ if (colored) { colors = (Array)DXGetComponentValue((Field)inobject,"colors"); if (!colors) { colored = 0; } } if (!colored) color = DXRGB(1.0,1.0,1.0); /* get pointers to data and positions */ /* prepare to access the positions */ if (!(handle = DXCreateArrayHandle(positions))) goto error; scratch = DXAllocateLocal(posshape[0]*sizeof(float)); if (!scratch) goto error; switch (type) { case (TYPE_SHORT): data_ptr_s = (short *)DXGetArrayData(data); break; case (TYPE_INT): data_ptr_i = (int *)DXGetArrayData(data); break; case (TYPE_FLOAT): data_ptr_f = (float *)DXGetArrayData(data); break; case (TYPE_DOUBLE): data_ptr_d = (double *)DXGetArrayData(data); break; case (TYPE_UBYTE): data_ptr_ub = (ubyte *)DXGetArrayData(data); break; case (TYPE_BYTE): data_ptr_b = (byte *)DXGetArrayData(data); break; case (TYPE_USHORT): data_ptr_us = (ushort *)DXGetArrayData(data); break; case (TYPE_UINT): data_ptr_ui = (uint *)DXGetArrayData(data); break; case (TYPE_STRING): strcpy(glyph_rank,"string"); break; default: DXSetError(ERROR_INVALID_DATA,"unrecognized data type"); goto error; } if (colored) { if (DXQueryConstantArray(colors, NULL, (Pointer)&colororigin)) { reginputcolors = 1; } else { reginputcolors = 0; /* check delayed or not */ DXGetArrayInfo(colors,NULL, &colorstype, NULL,&colorsrank,colorsshape); if (colorstype == TYPE_FLOAT) { if ((colorsrank != 1)||(colorsshape[0]!=3)) { DXSetError(ERROR_INVALID_DATA, "only 3D floating point or 1D delayed colors acceptable"); goto error; } } else { if (colorstype != TYPE_UBYTE) { DXSetError(ERROR_INVALID_DATA, "only 3D floating point or 1D delayed colors acceptable"); goto error; } if (!((colorsrank == 0)||((colorsrank ==1)&&(colorsshape[0]==1)))) { DXSetError(ERROR_INVALID_DATA, "only 3D floating point or 1D delayed colors acceptable"); goto error; } colormap = (Array)DXGetComponentValue((Field)inobject,"color map"); if (!colormap) { DXSetError(ERROR_INVALID_DATA, "only 3D floating point or 1D delayed colors acceptable (no color map component)"); goto error; } if (!DXGetArrayInfo(colormap,&numcoloritems, &colorstype,NULL,&colorsrank, colorsshape)) goto error; if (colorstype != TYPE_FLOAT) { DXSetError(ERROR_INVALID_DATA, "color map component must be of type float"); goto error; } if ((colorsrank != 1)||(colorsshape[0]!=3)) { DXSetError(ERROR_INVALID_DATA, "color map component must be 3D"); goto error; } if (numcoloritems != 256) { DXSetError(ERROR_INVALID_DATA, "color map component does not have 256 items"); goto error; } delayedcolors = 1; colors_ptr = (RGBColor *)DXGetArrayData(colormap); } if (!delayedcolors) colors_ptr = (RGBColor *)DXGetArrayData(colors); else colors_byte_ptr = (unsigned char *)DXGetArrayData(colors); } } /* see if there's an invalid positions (or connections) array */ invalid = 0; if (!strcmp(attr,"connections")) { invalid_pos = (Array)DXGetComponentValue((Field)inobject, "invalid connections"); if (invalid_pos) { invalid = 1; invalidhandle = DXCreateInvalidComponentHandle((Object)inobject, NULL, "connections"); if (!invalidhandle) goto error; } } else { invalid_pos = (Array)DXGetComponentValue((Field)inobject, "invalid positions"); if (invalid_pos) { invalid = 1; invalidhandle = DXCreateInvalidComponentHandle((Object)inobject, NULL, "positions"); if (!invalidhandle) goto error; } } if (!strcmp(glyph_rank,"string")) { for (i=0; i= 1.0) return FALSE; /* number always get smaller if denominator greater than numerator */ if (dnmntr >= nmrtr) return FALSE; /* we made it this far, check ratio */ if (nmrtr >= dnmntr * DXD_MAX_FLOAT) return TRUE; else return FALSE; } /* this routine gets the data stats for an object */ Error _dxfGetStatisticsAndSize(Object outo, char *type_string, int min_set, float *given_min, int max_set, float *given_max, float *base_size, int *stats_done) { float min, max; Array data; /* XXX I need to check if the data component is tensor. If it is, I should * figure out the statistics on the three eigenvectors */ if (_dxfDXEmptyObject(outo)) { *base_size=0; return OK; } if ((!strcmp(type_string,"tensor"))||(_dxfIsTensor(outo))) { if (!_dxfGetTensorStats(outo, &min, &max)) { return ERROR; } if (!min_set) *given_min = min; if (!max_set) *given_max = max; } else { if (!DXStatistics(outo, "data", &min, &max, NULL, NULL)) { /* make sure it has a data component */ if (!_dxfHasDataComponent(outo)) { if (!strcmp(type_string,"text")) { DXSetError(ERROR_INVALID_DATA, "field must have a data component for text glyphs"); return ERROR; } else { /* it's ok if it doesn't have data, but not if they've specified a * non-scalar glyph type */ DXResetError(); if ((!strcmp(type_string, "rocket"))|| (!strcmp(type_string, "arrow"))|| (!strcmp(type_string, "needle"))|| (!strcmp(type_string, "tensor"))|| (!strcmp(type_string, "arrow2d"))|| (!strcmp(type_string, "needle2d"))|| (!strcmp(type_string, "rocket2d"))) { DXSetError(ERROR_INVALID_DATA, "only scalar glyph types accepted when no data component is present"); return ERROR; } if (!min_set) *given_min = 1.0; if (!max_set) *given_max = 1.0; } } DXResetError(); } else { if (!min_set) *given_min = min; if (!max_set) *given_max = max; } } if (!_dxfWidthHeuristic(outo, base_size)) return ERROR; if (stats_done) *stats_done = 1; return OK; } /* * This routine will "recurse to individual", that is until a series or * composite field is reached */ /* the point of this is to find the level of the "individual" and get * statistics at that point */ Error _dxfProcessGlyphObject(Object parent, Object child, char *type_string, float shape, float scale, int scale_set, float ratio, int ratio_set, float given_min, int min_set, float given_max, int max_set, float quality, int AutoSize, Object typefield, int type_is_field, int index, char *font, int *stats_done, float *base_size) { struct arg arg; Object subo; Group newgroup=NULL; Field copyfield=NULL; int i; Array data; Type type; struct textarg textarg; switch(DXGetObjectClass(child)) { case CLASS_FIELD: /* if empty field just return it */ if (DXEmptyField((Field)child)) { return OK; } /* it's a field. If it's text, don't do statistics stuff; just call the text processor */ data = (Array)DXGetComponentValue((Field)child,"data"); if ((data) && (!DXGetArrayInfo(data, NULL, &type, NULL, NULL, NULL))) goto error; if ((data) && ((type == TYPE_STRING) || (!strcmp(type_string,"text")) || (!strcmp(type_string,"coloredtext")))) { /* first make a new group which will replace the field */ newgroup = DXNewGroup(); if (!newgroup) goto error; /* make a copy of the field to work on */ copyfield = (Field)DXCopy(child,COPY_STRUCTURE); /* set the new group as a member of parent */ if (!DXSetEnumeratedMember((Group)parent, index, (Object)newgroup)) goto error; textarg.inobject = (Object)copyfield; textarg.outobject = (Object)newgroup; if (!strcmp(type_string,"coloredtext")) textarg.colored = 1; else textarg.colored = 0; textarg.scale = scale; strcpy(textarg.font,font); if (!(DXAddTask(_dxfTextField, (Pointer)&textarg, sizeof(textarg), 1.0))) goto error; } /* else it's a field, but it's not text stuff */ else { if (!*stats_done) { if (!_dxfGetStatisticsAndSize(child, type_string, min_set, &given_min, max_set, &given_max, base_size, NULL)) goto error; } arg.outobject = child; strcpy(arg.type, type_string); arg.typefield = typefield; arg.type_is_field = type_is_field; arg.shape = shape; arg.scale = scale; arg.scale_set = scale_set; arg.ratio = ratio; arg.ratio_set = ratio_set; arg.given_min = given_min; arg.min_set = min_set; arg.given_max = given_max; arg.max_set = max_set; arg.quality = quality; arg.base_size = *base_size; arg.AutoSize = AutoSize; arg.parent = parent; arg.parentindex = index; /* call GlyphTask */ if (!(DXAddTask(_dxfGlyphTask, (Pointer)&arg, sizeof(arg), 1.0))) goto error; return OK; } break; case CLASS_GROUP: if (DXGetGroupClass((Group)child) == CLASS_COMPOSITEFIELD || DXGetGroupClass((Group)child) == CLASS_SERIES || DXGetGroupClass((Group)child) == CLASS_MULTIGRID) { /* We're ready to extract the min and max of this thing */ if (!_dxfGetStatisticsAndSize(child, type_string, min_set, &given_min, max_set, &given_max, base_size, stats_done)) goto error; for (i=0; subo = DXGetEnumeratedMember((Group)child,i,NULL); i++) { if (!_dxfProcessGlyphObject(child, subo, type_string, shape, scale, scale_set, ratio, ratio_set, given_min, min_set, given_max, max_set, quality, AutoSize, typefield, type_is_field, i, font, stats_done, base_size)) goto error; } } else { /* must be a generic group, so we are not ready to get statistics */ for (i=0; subo = DXGetEnumeratedMember((Group)child,i,NULL); i++) { if (!_dxfProcessGlyphObject(child, subo, type_string, shape, scale, scale_set, ratio, ratio_set, given_min, min_set, given_max, max_set, quality, AutoSize, typefield, type_is_field, i, font, stats_done, base_size)) goto error; } } break; case (CLASS_CLIPPED): if (!(DXGetClippedInfo((Clipped)child, &subo, NULL))) goto error; if (!_dxfProcessGlyphObject(child, subo, type_string, shape, scale, scale_set, ratio, ratio_set, given_min, min_set, given_max, max_set, quality, AutoSize, typefield, type_is_field, 0, font, stats_done, base_size)) goto error; break; default: DXSetError (ERROR_BAD_PARAMETER,"group or field required"); goto error; } return OK; error: DXDelete((Object)newgroup); DXDelete((Object)copyfield); return ERROR; } static Error ExpandComponents(Field field, char *dataattr, int newpoints, int ng, int *map, char *fexcept) { Array sA, dA=NULL; int i=0; char *name; while (NULL != (sA = (Array)DXGetEnumeratedComponentValue(field, i++, &name)) ) { int itemSize; Type type; Category cat; int rank, shape[30]; Object attr = DXGetComponentAttribute(field, name, "dep"); dA = NULL; /* * don't do anything with the normals component; it's already correct */ if (!strcmp(name,"normals")) continue; /* ditto for connections */ if (!strcmp(name,"connections")) continue; /* * since positions "dep" positions, we must ignore that too */ if (!strcmp(name,"positions")) continue; if (! attr) continue; /* check dependency. Delete the component */ if (strcmp(DXGetString((String)attr), dataattr)) { DXDeleteComponent(field, name); /* need to decrement i, because we've deleted a component */ i--; continue; } /* check the "fexcept" string */ if (!strcmp(name,fexcept)) continue; DXGetArrayInfo(sA, NULL, &type, &cat, &rank, shape); itemSize = DXGetItemSize(sA); if (DXQueryConstantArray((Array)sA, NULL, NULL)) { int cst, rank, shape[30]; Pointer origin=NULL; Type type; Category category; DXGetArrayInfo(sA, NULL, &type, &category, &rank, shape); origin = DXAllocateLocal(itemSize); if (origin == NULL) { DXFree(origin); goto cleanup; } if (DXQueryConstantArray((Array)sA, NULL, origin)) dA = (Array)DXNewConstantArrayV(newpoints, origin, type, category, rank, shape); DXFree(origin); } if (! dA) { int i, j; char *srcPtr; char *dstPtr; dA = DXNewArrayV(type, cat, rank, shape); if (! dA) goto cleanup; if (! DXAddArrayData(dA, 0, newpoints, NULL)) goto cleanup; dstPtr = (char *)DXGetArrayData(dA); srcPtr = (char *)DXGetArrayData(sA); for (i = 0; i < ng; i++) { for (j = 0; j < map[i]; j++) { memcpy(dstPtr, srcPtr, itemSize); dstPtr += itemSize; } srcPtr += itemSize; } } if (! DXSetComponentValue(field, name, (Object)dA)) goto cleanup; dA = NULL; if (! DXSetComponentAttribute(field, name, "dep", (Object)DXNewString("positions"))) goto cleanup; DXChangedComponentValues((Field)field,name); } DXDelete((Object) dA); return OK; cleanup: DXDelete((Object) dA); return ERROR; } Error _dxfGlyphTask(Pointer p) { Object outo; RGBColor origin, delta; int data_incr, pos_incr, totalpoints = 0, compact=0, counter, numitems; int hasnormals, out_pos_dim, invalid, valid; int num_to_be_overridden=0, num_not_drawn=0; InvalidComponentHandle invalidhandle=NULL; Array data_array, positions_array, new_positions_array, colors_array; Array invalid_pos; ArrayHandle handle=NULL; Pointer scratch=NULL; RGBColor defaultcolor; int c, *map = NULL; Matrix overridescalematrix; Array new_normals_array, new_connections_array; Triangle *conns=NULL, *newconns, *overrideconns, *newoverrideconns; Point *normals=NULL, *newnormals, *points=NULL; float *newpoints, *newoverridepoints; Point *overridepoints, *overridenormals; Point *newoverridenormals; Line *newlines, *lines, *overridelines, *newoverridelines; Matrix scalematrix, translatematrix, rotatematrix, t; char *given_type_string, glyph_rank[10], type_string[30]; char connectiontype[30]; char overridetype_string[30]; float glyphshape, scale, ratio, given_min, given_max, quality, base_size; float min, position; int scale_set, ratio_set, min_set, max_set, numcolors, numopacities; int data_rank, data_shape[30], override; int pos_rank, pos_shape[30], counts[30]; int numpoints, numoverridepoints, numoverrideconns; int numconns, num_pos, i, j,k, n, countpos=0, countconn=0; float vector_width; float *dp_old=NULL, datavalue, lv; float datascale, range, x, posorigin[30], posdeltas[30]; float *data_ptr_f; byte *data_ptr_b; ubyte *data_ptr_ub; short *data_ptr_s; ushort *data_ptr_us; int *data_ptr_i; uint *data_ptr_ui; double *data_ptr_d; Stress_Tensor st; Stress_Tensor2 st2; Vector eigen_vector[3]; int AutoSize, num_data, posted; Vector v, canonical_v; Type pos_type, data_type, colors_type, opacities_type; Category pos_category, data_category; Object typefield; int type_is_field, anyxforms; Matrix xform; char *attr, *font; int maxnum, parentindex; Object parent, uniformscalingattr=NULL; Arg *arg = (Arg *)p; newnormals = NULL; newlines = NULL; newconns = NULL; newpoints = NULL; newoverridepoints = NULL; newoverridelines = NULL; newoverridenormals = NULL; newoverrideconns = NULL; outo = arg->outobject; given_type_string = arg->type; glyphshape = arg->shape; scale = arg->scale; scale_set = arg->scale_set; ratio = arg->ratio; ratio_set = arg->ratio_set; given_min = arg->given_min; min_set = arg->min_set; given_max = arg->given_max; max_set = arg->max_set; quality = arg->quality; base_size = arg->base_size; AutoSize = arg->AutoSize; typefield = arg->typefield; type_is_field = arg->type_is_field; parent = arg->parent; parentindex = arg->parentindex; font = arg->font; /* we have a field and are ready to put glyphs in the field */ /* first figure out what kind of glyphs we have got to do */ /* get the data component of the input field */ data_array = (Array)DXGetComponentValue((Field)outo,"data"); if (!data_array) { strcpy(glyph_rank,"scalar"); /* since there's no data to follow, are there colors? If so, follow * those. Otherwise, follow positions */ if (DXGetComponentValue((Field)outo,"colors")) { attr = DXGetString((String)DXGetComponentAttribute((Field)outo,"colors", "dep")); } else { attr = "positions"; } } else { if (!DXGetArrayInfo(data_array,&num_data, &data_type, &data_category, &data_rank, data_shape)) return ERROR; attr = DXGetString((String)DXGetComponentAttribute((Field)outo, "data", "dep")); if (data_rank==0) { strcpy(glyph_rank,"scalar"); data_incr = 1; } else if (data_rank==1 && data_shape[0] == 1) { strcpy(glyph_rank,"scalar"); data_incr = 1; } else if (data_rank==1 && data_shape[0] == 2) { strcpy(glyph_rank,"2-vector"); data_incr = 2; } else if (data_rank==1 && data_shape[0] == 3) { strcpy(glyph_rank,"3-vector"); data_incr = 3; } else if (data_rank==2 && data_shape[0]==3 &&data_shape[1]==3) { strcpy(glyph_rank,"matrix"); data_incr = 9; } else if (data_rank==2 && data_shape[0]==2 &&data_shape[1]==2) { strcpy(glyph_rank,"matrix2"); data_incr = 4; } else { DXSetError(ERROR_INVALID_DATA, "data must be scalar, 2-vector, 3-vector, 2x2 or 3x3 matrix"); return ERROR; } } posted = 0; /* check the attribute */ if (strcmp(attr,"connections") && (strcmp(attr,"positions"))) { DXSetError(ERROR_INVALID_DATA,"unsupported data dependency \'%s\'",attr); goto error; } if (!strcmp(attr,"connections")) { /* I need to check whether the positions are regular. If they * are, a simple grid shift is in order. Otherwise, use PostArray * to shift them */ Array pos, con; pos = (Array)DXGetComponentValue((Field)outo,"positions"); con = (Array)DXGetComponentValue((Field)outo,"connections"); if ((DXQueryGridPositions(pos, &n, counts, posorigin, posdeltas)) && DXQueryGridConnections(con, NULL, NULL)) { for (i=0; i 1) { posorigin[i]+=0.5*posdeltas[i + j*n]; } } } for (i=0; i1) counts[i] = counts[i]-1; } positions_array = DXMakeGridPositionsV(n, counts, posorigin, posdeltas); } /* else the positions are irregular */ else { positions_array = _dxfPostArray((Field)outo, "positions","connections"); } if (!positions_array) { DXSetError(ERROR_BAD_PARAMETER, "could not compute glyph positions for cell-centered data"); return ERROR; } posted = 1; if (!DXGetArrayInfo(positions_array,&num_pos, &pos_type, &pos_category, &pos_rank, pos_shape)) return ERROR; } else if (!strcmp(attr, "faces")) { positions_array = _dxfPostArray((Field)outo, "positions","faces"); if (!positions_array) { DXAddMessage("could not compute glyph positions for face-centered data"); return ERROR; } posted = 1; if (!DXGetArrayInfo(positions_array,&num_pos, &pos_type, &pos_category, &pos_rank, pos_shape)) return ERROR; } /* else dep positions */ else { positions_array = (Array)DXGetComponentValue((Field)outo,"positions"); if (!positions_array) { DXSetError(ERROR_BAD_PARAMETER,"field has no positions"); return ERROR; } if (!DXGetArrayInfo(positions_array,&num_pos, &pos_type, &pos_category, &pos_rank, pos_shape)) return ERROR; } invalid=0; /* see if there's an invalid positions (or connections) array */ if (!strcmp(attr,"connections")) { invalid_pos = (Array)DXGetComponentValue((Field)outo, "invalid connections"); if (invalid_pos) { DXGetArrayInfo(positions_array, &numitems, NULL, NULL, NULL, NULL); invalidhandle = DXCreateInvalidComponentHandle((Object)outo, NULL, "connections"); if (!invalidhandle) goto error; invalid=1; /* if all invalid, just return. We are done */ valid=0; for (i=0; i 3)) { DXSetError(ERROR_INVALID_DATA, "positions must be 1, 2, or 3-Dimensional"); return ERROR; } pos_incr = pos_shape[0]; /* prepare to access the positions component */ if (!(handle = DXCreateArrayHandle(positions_array))) goto error; scratch = DXAllocateLocal(pos_incr*sizeof(float)); if (!scratch) goto error; if (!ratio_set) { if (!strcmp(glyph_rank,"scalar")) ratio = 0.05; else ratio = 0.0; } if (!type_is_field) { if (!GetGlyphName(quality, glyph_rank, pos_shape[0], given_type_string, type_string, overridetype_string, &out_pos_dim)) goto error; } /* now for whatever type_string it is, find out how many positions and connections will be added for each glyph, and get the arrays of positions and connections */ /* normals are a special case. Everything else gets expanded into the glyphs */ if (DXGetComponentValue((Field)outo,"normals")) DXRemove(outo,"normals"); /* set the shade attribute to yes */ DXSetIntegerAttribute((Object)outo, "shade", 1); if (type_is_field) { xform = Identity; anyxforms = 0; if (!GetGlyphField(typefield, &numpoints, &numconns, &points, &conns, &lines, &normals, &xform, &anyxforms, &hasnormals, &out_pos_dim, connectiontype)) goto error; if (!strcmp(connectiontype,"triangles")) { newconns = (Triangle *)DXAllocateLocal((numconns)*(3*sizeof(int))); if (!newconns) { goto error; } if (strcmp(glyph_rank,"scalar")) { if ((pos_shape[0]==3)&&(hasnormals)) strcpy(overridetype_string,"sphere62"); else strcpy(overridetype_string,"circle10"); if (!GetGlyphs(overridetype_string, &numoverridepoints, &numoverrideconns, &overridepoints, &overrideconns, &overridenormals, &overridelines, &hasnormals, connectiontype)) goto error; newoverridepoints = (float *)DXAllocateLocal((numoverridepoints)*(out_pos_dim*sizeof(float))); if (!(newoverridepoints)) goto error; if (hasnormals) { newoverridenormals = (Point *)DXAllocateLocal((numoverridepoints)*(3*sizeof(float))); if (!(newoverridenormals)) { goto error; } } newoverrideconns = (Triangle *)DXAllocateLocal((numoverrideconns)*(3*sizeof(int))); if (!(newoverrideconns)) { goto error; } } } else { newlines = (Line *)DXAllocateLocal((numconns)*(2*sizeof(int))); if (!newlines) { goto error; } if (strcmp(glyph_rank,"scalar")) { strcpy(overridetype_string,"point"); if (!GetGlyphs(overridetype_string, &numoverridepoints, &numoverrideconns, &overridepoints, &overrideconns, &overridenormals, &overridelines, &hasnormals, connectiontype)) goto error; newoverridepoints = (float *)DXAllocateLocal((numoverridepoints)*(out_pos_dim*sizeof(float))); if (!(newoverridepoints)) goto error; if (hasnormals) { newoverridenormals = (Point *)DXAllocateLocal((numoverridepoints)*(3*sizeof(float))); if (!(newoverridenormals)) { goto error; } } newoverridelines = (Line *)DXAllocateLocal((numoverrideconns)*(2*sizeof(int))); if (!(newoverridelines)) { goto error; } } } newpoints = (float *)DXAllocateLocal((numpoints)*(3*sizeof(float))); if (!newpoints) goto error; if (hasnormals) { newnormals = (Point *)DXAllocateLocal((numpoints)*(3*sizeof(float))); if (!newnormals) { goto error; } } /* check for an attribute on the given glyph telling us * not to futz with the shape of the glyph. Just use it * as is, scaling length and width identically */ uniformscalingattr = (Object)DXGetAttribute(typefield,"uniformscale"); } else { if (!GetGlyphs(type_string, &numpoints, &numconns, &points, &conns, &normals, &lines, &hasnormals, connectiontype)) goto error; newpoints = (float *)DXAllocateLocal((numpoints)*(out_pos_dim*sizeof(float))); if (!(newpoints)) goto error; if (hasnormals) { newnormals = (Point *)DXAllocateLocal((numpoints)*(3*sizeof(float))); if (!(newnormals)) { goto error; } } if (!strcmp(connectiontype,"triangles")) { newconns = (Triangle *)DXAllocateLocal((numconns)*(3*sizeof(int))); if (!(newconns)) { goto error; } } else { newlines = (Line *)DXAllocateLocal((numconns)*(2*sizeof(int))); if (!(newlines)) { goto error; } } /* for non-scalar glyphs, we may also need an "override" glyph (sphere) */ if (strcmp(glyph_rank,"scalar")) { if (!GetGlyphs(overridetype_string, &numoverridepoints,&numoverrideconns, &overridepoints, &overrideconns, &overridenormals, &overridelines, &hasnormals, connectiontype)) goto error; newoverridepoints = (float *)DXAllocateLocal((numoverridepoints)*(out_pos_dim*sizeof(float))); if (!(newoverridepoints)) goto error; if (hasnormals) { newoverridenormals = (Point *)DXAllocateLocal((numoverridepoints)*(3*sizeof(float))); if (!(newoverridenormals)) { goto error; } } if (!strcmp(connectiontype,"triangles")) { newoverrideconns = (Triangle *)DXAllocateLocal((numoverrideconns)*(3*sizeof(int))); if (!(newoverrideconns)) { goto error; } } else { newoverridelines = (Line *)DXAllocateLocal((numoverrideconns)*(2*sizeof(int))); if (!(newoverridelines)) { goto error; } } } } map = (int *)DXAllocateLocalZero(num_pos*sizeof(int)); if ((pos_type != TYPE_FLOAT)||(pos_category != CATEGORY_REAL)|| (pos_rank != 1)) { DXSetError(ERROR_INVALID_DATA, "positions component must type float, category real, rank 1"); goto error; } /* get the data component */ data_array = (Array)DXGetComponentValue((Field)outo,"data"); if (data_array) { if (data_category != CATEGORY_REAL) { DXSetError(ERROR_INVALID_DATA, "data component must be category real"); goto error; } switch (data_type) { case (TYPE_SHORT): data_ptr_s = (short *)DXGetArrayData(data_array); break; case (TYPE_INT): data_ptr_i = (int *)DXGetArrayData(data_array); break; case (TYPE_FLOAT): data_ptr_f = (float *)DXGetArrayData(data_array); break; case (TYPE_DOUBLE): data_ptr_d = (double *)DXGetArrayData(data_array); break; case (TYPE_BYTE): data_ptr_b = (byte *)DXGetArrayData(data_array); break; case (TYPE_UBYTE): data_ptr_ub = (ubyte *)DXGetArrayData(data_array); break; case (TYPE_USHORT): data_ptr_us = (ushort *)DXGetArrayData(data_array); break; case (TYPE_UINT): data_ptr_ui = (uint *)DXGetArrayData(data_array); break; } } /* get the colors component */ colors_array = (Array)DXGetComponentValue((Field)outo,"colors"); if (colors_array) c = 1; else c=0; /* check the dependency of the colors vs the dependency of the data. * If they don't match, pretend there aren't any colors */ if (colors_array) { if (data_array) { if (strcmp(DXGetString((String)DXGetAttribute((Object)colors_array, "dep")), DXGetString((String)DXGetAttribute((Object)data_array, "dep")))) { c = 0; colors_array=NULL; } } } if (!colors_array) { /* make a temporary colors component to expand later */ delta = DXRGB(0.0, 0.0, 0.0); if (!strcmp(glyph_rank,"2-vector")||(!strcmp(glyph_rank,"3-vector"))) { origin = DEFAULT_VECTOR_COLOR; colors_array = (Array)DXNewConstantArray(num_pos, (Pointer)&origin, TYPE_FLOAT,CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo,"colors",(Object)colors_array); /* make the colors dep on whatever the data was dep on */ DXSetComponentAttribute((Field)outo,"colors","dep", (Object)DXNewString(attr)); } if (!strcmp(glyph_rank,"matrix")) { origin = DEFAULT_TENSOR_COLOR; colors_array = (Array)DXNewConstantArray(num_pos, (Pointer)&origin, TYPE_FLOAT,CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo,"colors",(Object)colors_array); /* make the colors dep on whatever the data was dep on */ DXSetComponentAttribute((Field)outo,"colors","dep", (Object)DXNewString(attr)); } if (!strcmp(glyph_rank,"matrix2")) { origin = DEFAULT_TENSOR_COLOR; colors_array = (Array)DXNewConstantArray(num_pos, (Pointer)&origin, TYPE_FLOAT,CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo,"colors",(Object)colors_array); /* make the colors dep on whatever the data was dep on */ DXSetComponentAttribute((Field)outo,"colors","dep", (Object)DXNewString(attr)); } if (!strcmp(glyph_rank,"scalar")) { if (data_array) { if (!DXStatistics(outo,"data",&min, NULL,NULL, NULL)) goto error; if (given_min <= min) { compact = 1; origin = DEFAULT_SCALAR_COLOR; colors_array = (Array)DXNewConstantArray(num_pos, (Pointer)&origin, TYPE_FLOAT, CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo,"colors",(Object)colors_array); /* make the colors dep on whatever the data was dep on */ DXSetComponentAttribute((Field)outo,"colors","dep", (Object)DXNewString(attr)); } else { compact = 0; colors_array = DXNewArray(TYPE_FLOAT,CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo,"colors",(Object)colors_array); /* make the colors dep on whatever the data was dep on */ DXSetComponentAttribute((Field)outo,"colors","dep", (Object)DXNewString(attr)); } } else { compact = 1; origin = DEFAULT_SCALAR_COLOR; colors_array = (Array)DXNewConstantArray(num_pos, (Pointer)&origin, TYPE_FLOAT, CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo,"colors",(Object)colors_array); /* make the colors dep on whatever the data was dep on */ DXSetComponentAttribute((Field)outo,"colors","dep", (Object)DXNewString(attr)); } } } /* now make a new output positions component */ new_positions_array = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, out_pos_dim); /* now make a new output connections component */ /* need to do different things for needles and arrows, (not triangles) */ if ( !strcmp(connectiontype,"lines")) { new_connections_array = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2); DXSetComponentValue((Field)outo, "connections", (Object)new_connections_array); DXSetComponentAttribute((Field)outo,"connections","ref", (Object)DXNewString("positions")); DXSetComponentAttribute((Field)outo,"connections","element type", (Object)DXNewString("lines")); new_normals_array = NULL; } else { new_connections_array = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo, "connections", (Object)new_connections_array); DXSetComponentAttribute((Field)outo,"connections","ref", (Object)DXNewString("positions")); DXSetComponentAttribute((Field)outo,"connections","element type", (Object)DXNewString("triangles")); /* now make a new output normals component */ /* normals only apply to triangle connections */ if (hasnormals) { new_normals_array = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); DXSetComponentValue((Field)outo, "normals", (Object)new_normals_array); DXSetComponentAttribute((Field)outo,"normals","dep", (Object)DXNewString("positions")); } } /* first figure out how many override glyphs there are going to be */ /* only matters for vector data */ num_to_be_overridden=0; num_not_drawn=0; if ((!strcmp(glyph_rank,"3-vector"))||(!strcmp(glyph_rank,"2-vector"))){ for (i=0; i 1) { posorigin[i]+=0.5*posdeltas[i + j*n]; } } } for (i=0; i1) counts[i] = counts[i]-1; } positions = DXMakeGridPositionsV(n, counts, posorigin, posdeltas); } /* else the positions are irregular */ else { positions = _dxfPostArray((Field)field, "positions", dataattr); } if (!positions) { DXSetError(ERROR_BAD_PARAMETER, "could not compute glyph positions for cell-centered data"); return ERROR; } posted = 1; } else if (!strcmp(dataattr, "faces")) { positions = _dxfPostArray((Field)field, "positions", dataattr); if (!positions) { DXAddMessage("could not compute glyph positions for face-centered data"); return ERROR; } posted = 1; } /* else dep positions */ else { positions = (Array)DXGetComponentValue(field, "positions"); if (!positions) { DXSetError(ERROR_MISSING_DATA,"#10250", "data", "positions"); goto error; } } if ((datatype != TYPE_INT)&&(datatype != TYPE_UINT)&& (datatype != TYPE_SHORT)&&(datatype != TYPE_USHORT)&& (datatype != TYPE_BYTE)&&(datatype != TYPE_UBYTE)) { DXSetError(ERROR_INVALID_DATA, "for index glyphs, data type must be of an integral type"); goto error; } if (!((datarank==0)||((datarank==1)&&(datashape[0]==1)))) { DXSetError(ERROR_INVALID_DATA,"for index glyphs, data must be scalar"); goto error; } /* XXX regular data? */ switch (datatype) { case (TYPE_INT): data_ptr_i = (int *)DXGetArrayData(data); break; case (TYPE_UINT): data_ptr_ui = (uint *)DXGetArrayData(data); break; case (TYPE_SHORT): data_ptr_s = (short *)DXGetArrayData(data); break; case (TYPE_USHORT): data_ptr_us = (ushort *)DXGetArrayData(data); break; case (TYPE_BYTE): data_ptr_b = (byte *)DXGetArrayData(data); break; case (TYPE_UBYTE): data_ptr_ub = (ubyte *)DXGetArrayData(data); break; } if (!DXGetArrayInfo(positions, NULL, &postype, &poscategory, &posrank, posshape)) goto error; if (posrank != 1) { DXSetError(ERROR_INVALID_DATA,"positions of data must be rank 1"); goto error; } if ((posshape[0] < 0)||(posshape[0]>3)) { DXSetError(ERROR_INVALID_DATA,"positions of data must be 1, 2, or 3-D"); goto error; } if (postype != TYPE_FLOAT) { DXSetError(ERROR_INVALID_DATA,"positions component must be type float"); goto error; } if (!CheckGlyphGroup(glyphs, &glyphshape, &hasnormals, glyphelementtype)) goto error; ipos = 0; icon = 0; iclr = 0; inml = 0; idata = 0; newshape = (posshape[0] >= glyphshape) ? posshape[0] : glyphshape; newpositions = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, newshape); if (!strcmp(glyphelementtype,"triangles")) newconnections = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3); else newconnections = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2); newcolors = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); if (hasnormals) { newnormals = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); if (!newnormals) goto error; } if ((!newpositions)||(!newconnections)||(!newcolors)) goto error; /* prepare to access the positions component */ if (!(handle = DXCreateArrayHandle(positions))) goto error; scratch = DXAllocateLocal(posshape[0]*sizeof(float)); if (!scratch) goto error; /* set up the invalid component stuff */ if (!(invalidhandle = DXCreateInvalidComponentHandle((Object)field, NULL,dataattr))) goto error; if (!invalidhandle) goto error; numprev = 0; map = (int *)DXAllocateLocalZero(numdata*sizeof(int)); for (i=0; ix, dp2->y, 0.0); } else if (posshape[0] == 3) { dp3 = DXGetArrayEntry(handle, i, scratch); pos3D = DXPt(dp3->x, dp3->y, dp3->z); } /* XXX if glyph positions are regular??? */ glyphpos_ptr = (float *)DXGetArrayData(glyphpositions); if (!glyphpos_ptr) goto error; for (j=0; j3)) { DXSetError(ERROR_INVALID_DATA, "glyph group member must have 1D, 2D, or 3D positions"); return ERROR; } normals = (Array)DXGetComponentValue((Field)child, "normals"); if (first) { first = 0; *outshape = shape[0]; if (normals) *hasnormals = 1; else *hasnormals = 0; strcpy(glyphelementtype, attr); } else { /* check that dimensionality matches others in the group */ if (shape[0] != *outshape) { DXSetError(ERROR_INVALID_DATA, "dimensionality of all glyphs in group must be the same"); return ERROR; } /* check that whether or not it has normals matches others in the * group */ if ((normals && (*hasnormals==0))||(!normals)&&(*hasnormals==1)) { DXSetError(ERROR_INVALID_DATA, "if one glyph in group has normals, all must"); return ERROR; } /* check that the element type matches others in the group */ if (strcmp(attr, glyphelementtype)) { DXSetError(ERROR_INVALID_DATA, "element type of all glyphs in group must be the same"); return ERROR; } } } } return OK; } Error _dxfGetFontName(char *type_string, char *font) { char *start, *oldstart; /* if it's "colored text" or "text" there may be font information * attached */ /* Look for "text" */ start = strstr(type_string, "text"); if (start != NULL) { /* found "text" */ start+=4; if (*start != '\0') { /* now look for "font=" */ oldstart=start; DXSetError(ERROR_INVALID_DATA,"unrecognized type string"); start = strstr(start,"font="); if (start != NULL) { /* found "font=" */ start+=5; if (*start != '\0') { strcpy(font,start); *oldstart='\0'; DXResetError(); } } } } if (DXGetError()!=ERROR_NONE) return ERROR; return OK; } extern Error _dxfGetTensorStats(Object object, float *min, float *max) { Object subo; int i; switch (DXGetObjectClass(object)) { case (CLASS_FIELD): if (!_dxfGetFieldTensorStats((Field)object, min, max)) goto error; break; case (CLASS_GROUP): for (i=0; subo = DXGetEnumeratedMember((Group)object,i,NULL); i++) { if (!_dxfGetTensorStats(subo, min, max)) goto error; } break; case (CLASS_XFORM): if (!(DXGetXformInfo((Xform)object, &subo, NULL))) return ERROR; if (!_dxfGetTensorStats(subo, min, max)) goto error; break; } return OK; error: return ERROR; } extern Error _dxfGetFieldTensorStats(Field field, float *min, float *max) { Array data = NULL, invalid_pos=NULL; char *attr; Type type; InvalidComponentHandle invalidhandle=NULL; Category category; int i, j, numitems, rank, shape[10], invalid=0, matrixsize; float length; Stress_Tensor st; Stress_Tensor2 st2; short *data_ptr_s; int *data_ptr_i; float *data_ptr_f; double *data_ptr_d; ubyte *data_ptr_ub; byte *data_ptr_b; ushort *data_ptr_us; uint *data_ptr_ui; Vector eigen_vector[3]; data = (Array)DXGetComponentValue(field,"data"); if (!data) return OK; attr = DXGetString((String)DXGetComponentAttribute((Field)field, "data", "dep")); if (!attr) { DXSetError(ERROR_INVALID_DATA,"#10255", "data","dep"); goto error; } if (!DXGetArrayInfo(data,&numitems, &type, &category, &rank, shape)) goto error; if ((category != CATEGORY_REAL)|| (rank != 2)|| (!((shape[0] == 3)&&(shape[1]==3)||(shape[0]==2)&&(shape[1]==2)))){ DXSetError(ERROR_INVALID_DATA,"tensors must be 2x2 or 3x3 symmetric"); goto error; } if (shape[0]==2) matrixsize = 2; else matrixsize = 3; switch (type) { case (TYPE_SHORT): data_ptr_s = (short *)DXGetArrayData(data); case (TYPE_INT): data_ptr_i = (int *)DXGetArrayData(data); break; case (TYPE_FLOAT): data_ptr_f = (float *)DXGetArrayData(data); break; case (TYPE_DOUBLE): data_ptr_d = (double *)DXGetArrayData(data); break; case (TYPE_UBYTE): data_ptr_ub = (ubyte *)DXGetArrayData(data); break; case (TYPE_BYTE): data_ptr_b = (byte *)DXGetArrayData(data); break; case (TYPE_USHORT): data_ptr_us = (ushort *)DXGetArrayData(data); break; case (TYPE_UINT): data_ptr_ui = (uint *)DXGetArrayData(data); break; default: DXSetError(ERROR_INVALID_DATA,"unrecognized data type"); goto error; } if (!strcmp(attr,"connections")) { invalid_pos = (Array)DXGetComponentValue((Field)field, "invalid connections"); if (invalid_pos) { invalid = 1; invalidhandle = DXCreateInvalidComponentHandle((Object)field, NULL, "connections"); if (!invalidhandle) goto error; } } else { invalid_pos = (Array)DXGetComponentValue((Field)field, "invalid positions"); if (invalid_pos) { invalid = 1; invalidhandle = DXCreateInvalidComponentHandle((Object)field, NULL, "positions"); if (!invalidhandle) goto error; } } if (matrixsize == 3) { for (i=0; i *max) *max=length; } } } else { /* 2x2 matix */ for (i=0; i *max) *max=length; } } } return OK; error: return ERROR; } extern int _dxfIsTensor(Object o) { int p; Object child; Array data; int rank, shape[10]; /* do until a non-empty field is found */ p = 0; child = (Object)DXGetPart((Object)o, p); while (child != NULL && DXEmptyField((Field)child)) { child = (Object)DXGetPart((Object)o, p++); } /* get the data type */ data = (Array)DXGetComponentValue((Field)child,"data"); if (!data) return 0; if (!DXGetArrayInfo(data,NULL,NULL,NULL,&rank,shape)) return ERROR; if ((rank==2)&&(shape[0]==3)&&(shape[1]==3)) return 1; else if ((rank==2)&&(shape[0]==2)&&(shape[1]==2)) return 1; else return 0; } static int _dxfHasDataComponent(Object o) { if (Exists2(o, "positions", "data")) return 1; else return 0; }