1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8 /*
9 * $Header: /src/master/dx/src/exec/dxmods/_rubbersheet.c,v 1.5 2000/08/24 20:04:20 davidt Exp $:
10 */
11 #include <stdio.h>
12 #include <math.h>
13 #include <string.h>
14 #include <dx/dx.h>
15 #include "_rubbersheet.h"
16 #include "vectors.h"
17 #include "_normals.h"
18
19 #include <dxconfig.h>
20
21
22 typedef struct
23 {
24 Field field;
25 float scale, offset;
26 } Params;
27
28 enum PrimType
29 { PRIM_LINES, PRIM_TRIANGLES, PRIM_QUADS, PRIM_INVALID};
30
31 #define TRIANGLE(i,j,k) \
32 *outConnections++ = base + i; \
33 *outConnections++ = base + j; \
34 *outConnections++ = base + k;
35
36 #define QUAD(i,j,k,l) \
37 *outConnections++ = base + i; \
38 *outConnections++ = base + j; \
39 *outConnections++ = base + k; \
40 *outConnections++ = base + l;
41
42 static enum PrimType GetPrimType(Field);
43 static Error GetQuadNormal(ArrayHandle, ArrayHandle, int, float *);
44 static Error GetQuadNormals(ArrayHandle, ArrayHandle, int, float **);
45 static Error GetTriNormal(ArrayHandle, ArrayHandle, int, float *);
46 static Error GetTriNormals(ArrayHandle, ArrayHandle, int, float **);
47 static Error _GetTriNormal(float *, float *, float *, float *);
48 static Error _GetQuadNormal(float *, float *, float *, float *, float *);
49 static Error RS_Object(Object, Object, Object, Object);
50 static Error RS_Field(Object, float, float);
51 static Error RS_Field_task(Pointer);
52 static Error RS_Field_PDep_task(Field, float, float);
53 static Error RS_Field_CDep_task(Field, int, int, float, float);
54 static Error SetDefaultColor(Field, int);
55 static Error ValidForRubberSheet(Object);
56 static Error GetScaleAndOffset(Object, Object, Object, Object,
57 float *, float *);
58
59 Error
_dxfRubberSheet(Object ino0,Object scale,Object min,Object max,Object * outo)60 _dxfRubberSheet(Object ino0, Object scale, Object min, Object max, Object *outo)
61 {
62 Object copy = NULL;
63
64 *outo = NULL;
65
66 if (NULL == (copy = DXCopy(ino0, COPY_STRUCTURE)))
67 goto error;
68
69 if (! DXCreateTaskGroup())
70 goto error;
71
72 if (! RS_Object(copy, scale, min, max))
73 {
74 DXAbortTaskGroup();
75 goto error;
76 }
77
78 if (! DXExecuteTaskGroup() || DXGetError() != ERROR_NONE)
79 goto error;
80
81 *outo = copy;
82 return OK;
83
84 error:
85 DXDelete((Object)copy);
86 return ERROR;
87 }
88
89 static Error
RS_Object(Object object,Object scale_o,Object min_o,Object max_o)90 RS_Object(Object object, Object scale_o, Object min_o, Object max_o)
91 {
92 Class class = DXGetObjectClass(object);
93 if (class == CLASS_GROUP)
94 class = DXGetGroupClass((Group)object);
95
96 switch(class)
97 {
98 case CLASS_FIELD:
99 {
100 float s, o;
101
102 if (DXEmptyField((Field)object))
103 return OK;
104
105 if (! GetScaleAndOffset(object, scale_o, min_o, max_o, &s, &o))
106 return ERROR;
107
108 if (! RS_Field(object, s, o))
109 return ERROR;
110
111 if (! DXSetFloatAttribute(object, "RubberSheet scale", s))
112 return ERROR;
113
114 return OK;
115 }
116
117 case CLASS_SERIES:
118 case CLASS_COMPOSITEFIELD:
119 case CLASS_MULTIGRID:
120 {
121 float s, o;
122
123 if (! GetScaleAndOffset(object, scale_o, min_o, max_o, &s, &o))
124 return ERROR;
125
126 if (! RS_Field(object, s, o))
127 return ERROR;
128
129 if (! DXSetFloatAttribute(object, "RubberSheet scale", s))
130 return ERROR;
131
132 return OK;
133 }
134
135 case CLASS_GROUP:
136 {
137 Object c;
138 int i;
139 Group g = (Group)object;
140
141 for (i = 0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++)
142 if (! RS_Object(c, scale_o, min_o, max_o))
143 return ERROR;
144
145 return OK;
146 }
147
148 case CLASS_XFORM:
149 {
150 Object c;
151
152 if (! DXGetXformInfo((Xform)object, &c, NULL))
153 return ERROR;
154
155 if (! RS_Object(c, scale_o, min_o, max_o))
156 return ERROR;
157
158 return OK;
159 }
160
161 case CLASS_CLIPPED:
162 {
163 Object c;
164
165 if (! DXGetClippedInfo((Clipped)object, &c, NULL))
166 return ERROR;
167
168 if (! RS_Object(c, scale_o, min_o, max_o))
169 return ERROR;
170
171 return OK;
172 }
173
174 case CLASS_SCREEN:
175 {
176 Object c;
177
178 if (! DXGetScreenInfo((Screen)object, &c, NULL, NULL))
179 return ERROR;
180
181 if (! RS_Object(c, scale_o, min_o, max_o))
182 return ERROR;
183
184 return OK;
185 }
186
187 default:
188 DXSetError(ERROR_BAD_CLASS,
189 "unknown object encountered in traversal");
190 return ERROR;
191 }
192
193 }
194
195 static Error
RS_Field(Object object,float scale,float offset)196 RS_Field(Object object, float scale, float offset)
197 {
198 Class class = DXGetObjectClass(object);
199
200 switch(class)
201 {
202 case CLASS_FIELD:
203 {
204 Params params;
205
206 if (DXEmptyField((Field)object))
207 return OK;
208
209 if (! ValidForRubberSheet(object))
210 return ERROR;
211
212 params.field = (Field)object;
213 params.scale = scale;
214 params.offset = offset;
215
216 if (! DXAddTask(RS_Field_task,
217 (Pointer)¶ms, sizeof(params), 1.0))
218 return ERROR;
219
220 return OK;
221 }
222
223 case CLASS_GROUP:
224 {
225 Group g = (Group)object;
226 int i;
227 Object c;
228
229 for (i = 0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++)
230 if (! RS_Field(c, scale, offset))
231 return ERROR;
232
233 return OK;
234 }
235
236 case CLASS_XFORM:
237 {
238 Object c;
239
240 if (! DXGetXformInfo((Xform)object, &c, NULL))
241 return ERROR;
242
243 if (! RS_Field(c, scale, offset))
244 return ERROR;
245
246 return OK;
247 }
248
249 case CLASS_CLIPPED:
250 {
251 Object c;
252
253 if (! DXGetClippedInfo((Clipped)object, &c, NULL))
254 return ERROR;
255
256 if (! RS_Field(c, scale, offset))
257 return ERROR;
258
259 return OK;
260 }
261
262 case CLASS_SCREEN:
263 {
264 Object c;
265
266 if (! DXGetScreenInfo((Screen)object, &c, NULL, NULL))
267 return ERROR;
268
269 if (! RS_Field(c, scale, offset))
270 return ERROR;
271
272 return OK;
273 }
274
275 default:
276 DXSetError(ERROR_BAD_CLASS,
277 "unknown object encountered in traversal");
278 return ERROR;
279 }
280 }
281
282 static Error
RS_Field_task(Pointer ptr)283 RS_Field_task(Pointer ptr)
284 {
285 Params *params;
286 float scale, offset;
287 Field field;
288 Object attr;
289 int dDepP, nDepP;
290
291 params = (Params *)ptr;
292
293 field = params->field;
294 scale = params->scale;
295 offset = params->offset;
296
297 if (DXEmptyField(field))
298 return OK;
299
300 attr = DXGetComponentAttribute(field, "data", "dep");
301 if (! attr || DXGetObjectClass(attr) != CLASS_STRING)
302 {
303 DXSetError(ERROR_DATA_INVALID,
304 "invalid or nonexistant data dependency attribute");
305 return ERROR;
306 }
307
308 if (!strcmp(DXGetString((String)attr), "positions"))
309 dDepP = 1;
310 else if (!strcmp(DXGetString((String)attr), "connections"))
311 dDepP = 0;
312 else
313 {
314 DXSetError(ERROR_DATA_INVALID,
315 "invalid data dependency: %s", DXGetString((String)attr));
316 return ERROR;
317 }
318
319 /*
320 * If there are no normals input, then by default, normals
321 * dependency follows data. If there is a normals component,
322 * then its dependency overrides.
323 */
324 nDepP = dDepP;
325 if (DXGetComponentValue(field, "normals"))
326 {
327 attr = DXGetComponentAttribute(field, "normals", "dep");
328 if (! attr || DXGetObjectClass(attr) != CLASS_STRING)
329 {
330 DXSetError(ERROR_DATA_INVALID,
331 "invalid or nonexistant normals dependency attribute");
332 return ERROR;
333 }
334
335 if (!strcmp(DXGetString((String)attr), "positions"))
336 nDepP = 1;
337 else if (!strcmp(DXGetString((String)attr), "connections"))
338 nDepP = 0;
339 else
340 {
341 DXSetError(ERROR_DATA_INVALID,
342 "invalid normals dependency: %s",
343 DXGetString((String)attr));
344 return ERROR;
345 }
346 }
347
348 if (dDepP && nDepP)
349 {
350 if (! RS_Field_PDep_task(field, scale, offset))
351 return ERROR;
352 }
353 else
354 {
355 if (! RS_Field_CDep_task(field, nDepP, dDepP, scale, offset))
356 return ERROR;
357 }
358
359 if (! _dxfNormalsObject((Object)field, "data"))
360 return ERROR;
361
362 DXDeleteComponent(field, "box");
363
364 if (! DXEndField(field))
365 return ERROR;
366
367 return OK;
368 }
369
370 #define STRETCH_POSITIONS_VARYING_NORMAL(type) \
371 { \
372 type *ptr = (type *)data; \
373 \
374 for (i = 0; i < nPositions; i++) \
375 { \
376 float *pt = (float *)DXGetArrayEntry(pHandle, i, pbuf); \
377 \
378 vector_scale((Vector *)v_normal, \
379 scale * (*ptr + offset), (Vector *)s_normal); \
380 vector_add((Vector *)pt, (Vector *)s_normal, \
381 (Vector *)outPositions); \
382 \
383 ptr += 1; \
384 v_normal += 3; \
385 outPositions += 3; \
386 } \
387 }
388
389 #define STRETCH_POSITIONS_CONSTANT_NORMAL(type) \
390 { \
391 type *ptr = (type *)data; \
392 for (i = 0; i < nPositions; i++) \
393 { \
394 float *pt = (float *)DXGetArrayEntry(pHandle, i, pbuf); \
395 \
396 vector_scale((Vector *)c_normal, \
397 scale * (*ptr + offset), (Vector *)s_normal); \
398 vector_add((Vector *)pt, (Vector *)s_normal, \
399 (Vector *)outPositions); \
400 \
401 ptr += 1; \
402 outPositions += 3; \
403 } \
404 }
405
406 #define STRETCH_POSITIONS_2D(type) \
407 { \
408 type *ptr = (type *)data; \
409 for (i = 0; i < nPositions; i++) \
410 { \
411 float *pt = (float *)DXGetArrayEntry(pHandle, i, pbuf); \
412 for (j = 0; j < nDim; j++) \
413 *outPositions++ = *pt++; \
414 \
415 *outPositions++ = (*ptr++ + offset) * scale; \
416 } \
417 }
418
419 static Error
RS_Field_PDep_task(Field field,float scale,float offset)420 RS_Field_PDep_task(Field field, float scale, float offset)
421 {
422 Array cArray, dArray;
423 Array pArrayIn, pArrayOut;
424 float *outPositions;
425 float *data;
426 enum PrimType primType;
427 int nPositions, nDim;
428 Type type, dataType;
429 Category cat;
430 int rank, shape[32];
431 ArrayHandle pHandle = NULL;
432 ArrayHandle cHandle = NULL;
433 Pointer pbuf = NULL;
434
435 pArrayOut = NULL;
436
437 if ((primType = GetPrimType(field)) == PRIM_INVALID)
438 goto error;
439
440 cArray = (Array)DXGetComponentValue(field, "connections");
441 if (! cArray)
442 {
443 DXSetError(ERROR_UNEXPECTED, "missing connections");
444 goto error;
445 }
446
447 dArray = (Array)DXGetComponentValue(field, "data");
448 if (! dArray)
449 {
450 DXSetError(ERROR_UNEXPECTED, "missing data");
451 goto error;
452 }
453
454 DXGetArrayInfo(dArray, NULL, &dataType, NULL, NULL, NULL);
455
456 pArrayIn = (Array)DXGetComponentValue(field, "positions");
457 DXGetArrayInfo(pArrayIn, &nPositions, &type, &cat, &rank, shape);
458 if (type != TYPE_FLOAT || cat != CATEGORY_REAL || rank != 1)
459 {
460 DXSetError(ERROR_UNEXPECTED, "type/category/rank error");
461 goto error;
462 }
463
464 nDim = shape[0];
465
466 pHandle = DXCreateArrayHandle(pArrayIn);
467 pbuf = DXAllocate(DXGetItemSize(pArrayIn));
468 if (! pHandle || ! pbuf)
469 goto error;
470
471 data = (float *)DXGetArrayData(dArray);
472
473 /*
474 * If there are already 3 dimensions, we move the point in the normal
475 * direction. Otherwise, we add the next dimension.
476 */
477 if (nDim == 3)
478 {
479 Array nArray;
480
481 pArrayOut = DXNewArrayV(type, cat, rank, shape);
482 if (! pArrayOut)
483 goto error;
484
485 if (! DXAddArrayData(pArrayOut, 0, nPositions, NULL))
486 goto error;
487
488 outPositions = (float *)DXGetArrayData(pArrayOut);
489
490 /*
491 * We need a direction in which to stretch the point. If there are
492 * position normals, use them. Otherwise, assume the data is planar
493 * and get the normal to the plane.
494 */
495 nArray = (Array)DXGetComponentValue(field, "normals");
496
497 if (nArray && !DXQueryConstantArray(nArray, NULL, NULL))
498 {
499 Object att;
500 float *v_normal, s_normal[3];
501 int i;
502
503 att = DXGetComponentAttribute(field, "normals", "dep");
504 if (! att || DXGetObjectClass(att) != CLASS_STRING)
505 {
506 DXSetError(ERROR_DATA_INVALID,
507 "bad normals dependency attribute");
508 goto error;
509 }
510
511 if (strcmp(DXGetString((String)att), "positions"))
512 {
513 DXSetError(ERROR_DATA_INVALID,
514 "normals dependency must match data dependency");
515 goto error;
516 }
517
518 v_normal = (float *)DXGetArrayData(nArray);
519
520 switch(dataType)
521 {
522 case TYPE_DOUBLE:
523 STRETCH_POSITIONS_VARYING_NORMAL(double);
524 break;
525
526 case TYPE_FLOAT:
527 STRETCH_POSITIONS_VARYING_NORMAL(float);
528 break;
529
530 case TYPE_UBYTE:
531 STRETCH_POSITIONS_VARYING_NORMAL(ubyte);
532 break;
533
534 case TYPE_BYTE:
535 STRETCH_POSITIONS_VARYING_NORMAL(byte);
536 break;
537
538 case TYPE_USHORT:
539 STRETCH_POSITIONS_VARYING_NORMAL(ushort);
540 break;
541
542 case TYPE_SHORT:
543 STRETCH_POSITIONS_VARYING_NORMAL(short);
544 break;
545
546 case TYPE_UINT:
547 STRETCH_POSITIONS_VARYING_NORMAL(uint);
548 break;
549
550 case TYPE_INT:
551 STRETCH_POSITIONS_VARYING_NORMAL(int);
552 break;
553 default:
554 break;
555 }
556 }
557 else
558 {
559 float *c_normal, c_normal_buf[3], s_normal[3];
560 int nConnections;
561 int i;
562
563 DXGetArrayInfo(cArray, &nConnections, NULL, NULL, NULL, NULL);
564
565 /*
566 * Now if there is a normals array, it must be constant
567 */
568 if (nArray)
569 {
570 c_normal = (float *)DXGetConstantArrayData(nArray);
571 }
572 else
573 {
574 cHandle = DXCreateArrayHandle(cArray);
575 if (! cHandle)
576 goto error;
577
578 if (primType == PRIM_TRIANGLES)
579 {
580 if (! GetTriNormal(pHandle, cHandle,
581 nConnections, c_normal_buf))
582 {
583 DXSetError(ERROR_DATA_INVALID,
584 "unable to derive a surface normal");
585 goto error;
586 }
587 }
588 else if (primType == PRIM_QUADS)
589 {
590 if (! GetQuadNormal(pHandle, cHandle,
591 nConnections, c_normal_buf))
592 {
593 DXSetError(ERROR_DATA_INVALID,
594 "unable to derive a surface normal");
595 goto error;
596 }
597 }
598 else if (primType == PRIM_LINES)
599 {
600 DXSetError(ERROR_DATA_INVALID,
601 "require position normals for 3D lines");
602 goto error;
603 }
604
605 c_normal = c_normal_buf;
606 DXFreeArrayHandle(cHandle);
607 cHandle = NULL;
608 }
609
610 switch(dataType)
611 {
612 case TYPE_DOUBLE:
613 STRETCH_POSITIONS_CONSTANT_NORMAL(double);
614 break;
615
616 case TYPE_FLOAT:
617 STRETCH_POSITIONS_CONSTANT_NORMAL(float);
618 break;
619
620 case TYPE_UBYTE:
621 STRETCH_POSITIONS_CONSTANT_NORMAL(ubyte);
622 break;
623
624 case TYPE_BYTE:
625 STRETCH_POSITIONS_CONSTANT_NORMAL(byte);
626 break;
627
628 case TYPE_USHORT:
629 STRETCH_POSITIONS_CONSTANT_NORMAL(ushort);
630 break;
631
632 case TYPE_SHORT:
633 STRETCH_POSITIONS_CONSTANT_NORMAL(short);
634 break;
635
636 case TYPE_UINT:
637 STRETCH_POSITIONS_CONSTANT_NORMAL(uint);
638 break;
639
640 case TYPE_INT:
641 STRETCH_POSITIONS_CONSTANT_NORMAL(int);
642 break;
643 default:
644 break;
645 }
646
647 }
648 }
649 else if (nDim == 2 || nDim == 1)
650 {
651 int i, j;
652
653 shape[0] ++;
654
655 pArrayOut = DXNewArrayV(type, cat, rank, shape);
656 if (! pArrayOut)
657 goto error;
658
659 if (! DXAddArrayData(pArrayOut, 0, nPositions, NULL))
660 goto error;
661
662 outPositions = (float *)DXGetArrayData(pArrayOut);
663
664 switch(dataType)
665 {
666 case TYPE_DOUBLE:
667 STRETCH_POSITIONS_2D(double);
668 break;
669
670 case TYPE_FLOAT:
671 STRETCH_POSITIONS_2D(float);
672 break;
673
674 case TYPE_UBYTE:
675 STRETCH_POSITIONS_2D(ubyte);
676 break;
677
678 case TYPE_BYTE:
679 STRETCH_POSITIONS_2D(byte);
680 break;
681
682 case TYPE_USHORT:
683 STRETCH_POSITIONS_2D(ushort);
684 break;
685
686 case TYPE_SHORT:
687 STRETCH_POSITIONS_2D(short);
688 break;
689
690 case TYPE_UINT:
691 STRETCH_POSITIONS_2D(uint);
692 break;
693
694 case TYPE_INT:
695 STRETCH_POSITIONS_2D(int);
696 break;
697 default:
698 break;
699 }
700 }
701
702 DXSetComponentValue(field, "positions", (Object)pArrayOut);
703 pArrayOut = NULL;
704
705 /*
706 * If there's a colors component, use it. Otherwise, create one.
707 */
708 if (!DXGetComponentValue(field, "colors") &&
709 !DXGetComponentValue(field, "front colors"))
710 if (! SetDefaultColor(field, nPositions))
711 goto error;
712
713 DXDeleteComponent(field, "normals");
714
715 DXFreeArrayHandle(pHandle);
716 DXFreeArrayHandle(cHandle);
717 DXFree(pbuf);
718
719 DXEndField(field);
720
721 return OK;
722
723 error:
724 DXFreeArrayHandle(pHandle);
725 DXFreeArrayHandle(cHandle);
726 DXFree(pbuf);
727 DXDelete((Object)pArrayOut);
728 return ERROR;
729 }
730
731 #define STRETCH_CONNECTIONS_3D(type) \
732 { \
733 type *data; \
734 \
735 data = (type *)inData; \
736 for (i = 0; i < nConnections; i++) \
737 { \
738 int *elt; \
739 \
740 elt = (int *)DXGetArrayEntry(cHandle, i, (Pointer)ebuf); \
741 \
742 if (! dDepP) \
743 { \
744 scaledData = scale * (data[i] + offset); \
745 \
746 if (! nDepP || cst_normal) { \
747 if (cst_normal) \
748 { \
749 vector_scale((Vector *)cst_normal, \
750 scaledData, (Vector *)s_normal); \
751 } \
752 else \
753 { \
754 vector_scale(((Vector *)normals)+i, \
755 scaledData, (Vector *)s_normal); \
756 } \
757 } \
758 } \
759 \
760 for (j = 0; j < nVerts; j++) \
761 { \
762 float *pt, pbuf[3]; \
763 int pNum; \
764 \
765 pNum = *elt++; \
766 \
767 pt = (float *)DXGetArrayEntry(pHandle, \
768 pNum, (Pointer)pbuf); \
769 \
770 *outPositions++ = pt[0]; \
771 *outPositions++ = pt[1]; \
772 *outPositions++ = pt[2]; \
773 \
774 if (dDepP) \
775 { \
776 scaledData = scale * (data[pNum] + offset); \
777 if (! nDepP) { \
778 if (cst_normal) \
779 vector_scale(((Vector *)cst_normal), \
780 scaledData, (Vector *)s_normal); \
781 else \
782 vector_scale(((Vector *)normals)+i, \
783 scaledData, (Vector *)s_normal); \
784 } \
785 } \
786 else \
787 { \
788 if (nDepP && !cst_normal) \
789 vector_scale(((Vector *)normals)+pNum, \
790 scaledData, (Vector *)s_normal); \
791 } \
792 \
793 vector_add((Vector *)pt, \
794 (Vector *)s_normal, (Vector *)outPositions); \
795 \
796 outPositions += 3; \
797 } \
798 \
799 } \
800 }
801
802 #define STRETCH_CONNECTIONS_2D(type) \
803 { \
804 type *data = (type *)inData; \
805 \
806 for (i = 0; i < nConnections; i++) \
807 { \
808 int *elt; \
809 \
810 elt = (int *)DXGetArrayEntry(cHandle, i, (Pointer)ebuf); \
811 \
812 if (!dDepP) \
813 scaledData = scale * (data[i] + offset); \
814 \
815 for (j = 0; j < nVerts; j++) \
816 { \
817 float *pt, pbuf[2]; \
818 int pNum; \
819 \
820 pNum = *elt++; \
821 \
822 if (dDepP) \
823 scaledData = scale * (data[pNum] + offset); \
824 \
825 pt = (float *)DXGetArrayEntry(pHandle, \
826 pNum, (Pointer)pbuf); \
827 \
828 for (k = 0; k < nDim; k++) \
829 *outPositions++ = pt[k]; \
830 *outPositions++ = 0.0; \
831 \
832 for (k = 0; k < nDim; k++) \
833 *outPositions++ = pt[k]; \
834 *outPositions++ = scaledData; \
835 } \
836 } \
837 }
838
839 static Error
RS_Field_CDep_task(Field field,int nDepP,int dDepP,float scale,float offset)840 RS_Field_CDep_task(Field field, int nDepP, int dDepP, float scale, float offset)
841 {
842 Array dArrayIn;
843 Array pArrayIn, pArrayOut;
844 Array cArrayIn, cArrayOut;
845 float *outPositions;
846 int *outConnections;
847 Pointer inData;
848 int nConnections;
849 enum PrimType primType;
850 int nPositions, nDim, nVerts, outPerIn=0;
851 Type type, dataType;
852 Category cat;
853 int rank, shape[32], i, j, k;
854 float scaledData=0;
855 float s_normal[3], *c_normals = NULL;
856 Object attr;
857 char *name;
858 Array inA, outA = NULL;
859 ArrayHandle pHandle = NULL;
860 ArrayHandle cHandle = NULL;
861 int *ebuf = NULL;
862 char *toDelete[100];
863 int nDelete;
864 InvalidComponentHandle iInv = NULL, oInv = NULL;
865
866 cArrayOut = NULL;
867 pArrayOut = NULL;
868
869 if (DXEmptyField(field))
870 return OK;
871
872 if (! DXInvalidateConnections((Object)field))
873 goto error;
874
875 if ((primType = GetPrimType(field)) == PRIM_INVALID)
876 goto error;
877
878 cArrayIn = (Array)DXGetComponentValue (field, "connections");
879 if (! cArrayIn)
880 {
881 DXSetError(ERROR_UNEXPECTED, "missing connections");
882 goto error;
883 }
884
885 DXGetArrayInfo(cArrayIn, &nConnections, NULL, NULL, NULL, &nVerts);
886
887 dArrayIn = (Array)DXGetComponentValue (field, "data");
888 if (! dArrayIn)
889 {
890 DXSetError(ERROR_UNEXPECTED, "missing data");
891 goto error;
892 }
893 DXGetArrayInfo(dArrayIn, NULL, &dataType, NULL, NULL, NULL);
894
895 pArrayIn = (Array)DXGetComponentValue(field, "positions");
896 if (! pArrayIn)
897 {
898 DXSetError(ERROR_UNEXPECTED, "missing positions");
899 goto error;
900 }
901
902 DXGetArrayInfo(pArrayIn, &nPositions, &type, &cat, &rank, shape);
903
904 nDim = shape[0];
905
906 if (nDim > 3)
907 {
908 DXSetError(ERROR_DATA_INVALID, ">3D positions not supported");
909 goto error;
910 }
911
912 cHandle = DXCreateArrayHandle(cArrayIn);
913 pHandle = DXCreateArrayHandle(pArrayIn);
914 if (! cHandle || ! pHandle)
915 goto error;
916
917 ebuf = (int *)DXAllocate(nVerts*sizeof(int));
918 if (! ebuf)
919 goto error;
920
921 inData = DXGetArrayData(dArrayIn);
922
923 if (DXGetComponentValue(field, "invalid connections"))
924 {
925 iInv = DXCreateInvalidComponentHandle((Object)field,
926 NULL, "connections");
927 if (! iInv)
928 goto error;
929 }
930
931 if (nDim == 3)
932 {
933 float *normals = NULL;
934 float *cst_normal = NULL;
935 Array nArray;
936
937 /*
938 * Get normals. Options are: position dependent normals,
939 * connections dependent normals and none at all. In the
940 * last case, generate one dep on connections.
941 */
942 nArray = (Array)DXGetComponentValue(field, "normals");
943 if (nArray && DXQueryConstantArray(nArray, NULL, NULL))
944 {
945 cst_normal = (float *)DXGetConstantArrayData(nArray);
946 }
947 else if (nArray)
948 {
949 normals = (float *)DXGetArrayData(nArray);
950 }
951 else if (primType == PRIM_TRIANGLES)
952 {
953 if (! GetTriNormals(pHandle, cHandle, nConnections, &normals))
954 goto error;
955 }
956 else if (primType == PRIM_QUADS)
957 {
958 if (! GetQuadNormals(pHandle, cHandle, nConnections, &normals))
959 goto error;
960 }
961 else if (primType == PRIM_LINES)
962 {
963 DXSetError(ERROR_MISSING_DATA,
964 "normals component required for lines in 3-space");
965 goto error;
966 }
967
968 pArrayOut = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3);
969 if (! DXAddArrayData(pArrayOut, 0, 2*nVerts*nConnections, NULL))
970 goto error;
971
972 outPositions = (float *)DXGetArrayData(pArrayOut);
973
974 switch(dataType)
975 {
976 case TYPE_DOUBLE:
977 STRETCH_CONNECTIONS_3D(double);
978 break;
979
980 case TYPE_FLOAT:
981 STRETCH_CONNECTIONS_3D(float);
982 break;
983
984 case TYPE_INT:
985 STRETCH_CONNECTIONS_3D(int);
986 break;
987
988 case TYPE_UINT:
989 STRETCH_CONNECTIONS_3D(uint);
990 break;
991
992 case TYPE_SHORT:
993 STRETCH_CONNECTIONS_3D(short);
994 break;
995
996 case TYPE_USHORT:
997 STRETCH_CONNECTIONS_3D(ushort);
998 break;
999
1000 case TYPE_UBYTE:
1001 STRETCH_CONNECTIONS_3D(ubyte);
1002 break;
1003
1004 case TYPE_BYTE:
1005 STRETCH_CONNECTIONS_3D(byte);
1006 break;
1007 default:
1008 break;
1009 }
1010
1011 if (! nArray && normals)
1012 DXFree((Pointer)normals);
1013 }
1014 else
1015 {
1016 pArrayOut = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, nDim+1);
1017 if (! DXAddArrayData(pArrayOut, 0, 2*nVerts*nConnections, NULL))
1018 goto error;
1019
1020 outPositions = (float *)DXGetArrayData(pArrayOut);
1021
1022 switch(dataType)
1023 {
1024 case TYPE_DOUBLE:
1025 STRETCH_CONNECTIONS_2D(double);
1026 break;
1027
1028 case TYPE_FLOAT:
1029 STRETCH_CONNECTIONS_2D(float);
1030 break;
1031
1032 case TYPE_UINT:
1033 STRETCH_CONNECTIONS_2D(uint);
1034 break;
1035
1036 case TYPE_INT:
1037 STRETCH_CONNECTIONS_2D(int);
1038 break;
1039
1040 case TYPE_USHORT:
1041 STRETCH_CONNECTIONS_2D(ushort);
1042 break;
1043
1044 case TYPE_SHORT:
1045 STRETCH_CONNECTIONS_2D(short);
1046 break;
1047
1048 case TYPE_BYTE:
1049 STRETCH_CONNECTIONS_2D(byte);
1050 break;
1051
1052 case TYPE_UBYTE:
1053 STRETCH_CONNECTIONS_2D(ubyte);
1054 break;
1055 default:
1056 break;
1057 }
1058 }
1059
1060
1061 switch (primType)
1062 {
1063 case PRIM_TRIANGLES:
1064 {
1065 cArrayOut = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3);
1066 if (! cArrayOut)
1067 goto error;
1068
1069 if (! DXAddArrayData(cArrayOut, 0, 8*nConnections, NULL))
1070 goto error;
1071
1072 outConnections = (int *)DXGetArrayData(cArrayOut);
1073
1074 for (i = 0; i < nConnections; i++)
1075 {
1076 int base;
1077
1078 /*
1079 * base is the index of the first of the 6 points
1080 * corresponding to input triangle i (and hence output prism
1081 * i).
1082 */
1083 base = i*6;
1084
1085 TRIANGLE(1,3,5);
1086 TRIANGLE(0,4,2);
1087 TRIANGLE(5,3,2);
1088 TRIANGLE(5,2,4);
1089 TRIANGLE(3,1,0);
1090 TRIANGLE(3,0,2);
1091 TRIANGLE(1,5,4);
1092 TRIANGLE(1,4,0);
1093 }
1094
1095 outPerIn = 8;
1096
1097 }
1098 break;
1099
1100 case PRIM_QUADS:
1101 {
1102 cArrayOut = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 4);
1103 if (! cArrayOut)
1104 goto error;
1105
1106 if (! DXAddArrayData(cArrayOut, 0, 6*nConnections, NULL))
1107 goto error;
1108
1109 outConnections = (int *)DXGetArrayData(cArrayOut);
1110
1111 for (i = 0; i < nConnections; i++)
1112 {
1113 int base;
1114
1115 /*
1116 * base is the index of the first of the 8 points
1117 * corresponding to input quad i (and hence output box i).
1118 */
1119 base = i<<3;
1120
1121 QUAD(0,1,2,3);
1122 QUAD(4,5,6,7);
1123 QUAD(1,5,0,4);
1124 QUAD(0,4,2,6);
1125 QUAD(2,6,3,7);
1126 QUAD(3,7,1,5);
1127 }
1128
1129 outPerIn = 6;
1130 }
1131 break;
1132
1133 case PRIM_LINES:
1134 {
1135 cArrayOut = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 4);
1136 if (! cArrayOut)
1137 goto error;
1138
1139 if (! DXAddArrayData(cArrayOut, 0, nConnections, NULL))
1140 goto error;
1141
1142 outConnections = (int *)DXGetArrayData(cArrayOut);
1143
1144 for (i = 0; i < nConnections; i++)
1145 {
1146 int base;
1147
1148 /*
1149 * base is the index of the first of the 8 points
1150 * corresponding to input quad i (and hence output box i).
1151 */
1152 base = i<<2;
1153
1154 QUAD(0,1,2,3);
1155 }
1156
1157 outPerIn = 1;
1158 }
1159 break;
1160 default:
1161 break;
1162 }
1163
1164 /*
1165 * DXDelete components that are no longer appropriate.
1166 */
1167 DXDeleteComponent(field, "normals");
1168 DXDeleteComponent(field, "box");
1169 DXDeleteComponent(field, "data statistics");
1170 DXDeleteComponent(field, "front colors");
1171 DXDeleteComponent(field, "back colors");
1172 DXDeleteComponent(field, "invalid positions");
1173
1174 /*
1175 * Need to get rid of everything that deps refs or ders positions.
1176 * Before doing so, delete the connections component to break the recursion
1177 * chain - we do not want to delete data, for example, and because it is
1178 * dep on connections, it would get deleted by the recursive call when
1179 * DXChangedComponentStructure notices that connections refs positions and
1180 * calls itself recursively on it.
1181 */
1182 DXDeleteComponent(field, "connections");
1183
1184 /*
1185 * Set new positions and connections arrays.
1186 */
1187 if (! DXSetComponentValue(field, "positions", (Object)pArrayOut))
1188 goto error;
1189 pArrayOut = NULL;
1190
1191 if (! DXSetComponentValue(field, "connections", (Object)cArrayOut))
1192 goto error;
1193 cArrayOut = NULL;
1194
1195 switch(primType)
1196 {
1197 case PRIM_LINES:
1198 case PRIM_QUADS:
1199 if (! DXSetComponentAttribute(field, "connections", "element type",
1200 (Object)DXNewString("quads")))
1201 goto error;
1202 break;
1203 case PRIM_TRIANGLES:
1204 if (! DXSetComponentAttribute(field, "connections", "element type",
1205 (Object)DXNewString("triangles")))
1206 goto error;
1207 break;
1208 default:
1209 break;
1210 }
1211
1212 i = 0; nDelete = 0;
1213 while ((inA=(Array)DXGetEnumeratedComponentValue(field, i++, &name)) != NULL)
1214 {
1215 char *src;
1216 char *dst;
1217 int itemSize;
1218 int j, k;
1219 Type t;
1220 Category c;
1221 int n, r, s[32];
1222
1223 if (! strcmp(name, "connections") || ! strcmp(name, "positions"))
1224 continue;
1225
1226 if ((attr = DXGetComponentAttribute(field, name, "dep")) == NULL)
1227 continue;
1228
1229 if (DXGetComponentAttribute(field, name, "ref") ||
1230 DXGetComponentAttribute(field, name, "der"))
1231 {
1232 toDelete[nDelete++] = name;
1233 continue;
1234 }
1235
1236 if (! strcmp(DXGetString((String)attr), "positions"))
1237 {
1238 DXGetArrayInfo(inA, &n, &t, &c, &r, s);
1239
1240 if (DXQueryConstantArray(inA, NULL, NULL))
1241 {
1242 outA = (Array)DXNewConstantArrayV(2*nVerts*nConnections,
1243 DXGetConstantArrayData(inA), t, c, r, s);
1244 }
1245 else
1246 {
1247 outA = DXNewArrayV(t, c, r, s);
1248 if (! outA)
1249 goto error;
1250
1251 if (! DXAddArrayData(outA, 0, 2*nVerts*nConnections, NULL))
1252 goto error;
1253
1254 itemSize = DXGetItemSize(inA);
1255
1256 src = (char *)DXGetArrayData(inA);
1257 dst = (char *)DXGetArrayData(outA);
1258 for (j = 0; j < nConnections; j++)
1259 {
1260 int *e = (int *)DXGetArrayEntry(cHandle, j, ebuf);
1261
1262 for (k = 0; k < nVerts; k++)
1263 {
1264 memcpy(dst, src+e[k]*itemSize, itemSize);
1265 dst += itemSize;
1266 memcpy(dst, src+e[k]*itemSize, itemSize);
1267 dst += itemSize;
1268 }
1269 }
1270
1271 }
1272 }
1273 else if (! strcmp(DXGetString((String)attr), "connections"))
1274 {
1275 DXGetArrayInfo(inA, &n, &t, &c, &r, s);
1276
1277 if (DXQueryConstantArray(inA, NULL, NULL))
1278 {
1279 outA = (Array)DXNewConstantArrayV(outPerIn*n,
1280 DXGetConstantArrayData(inA), t, c, r, s);
1281 }
1282 else
1283 {
1284 outA = DXNewArrayV(t, c, r, s);
1285 if (! outA)
1286 goto error;
1287
1288 if (! DXAddArrayData(outA, 0, outPerIn*n, NULL))
1289 goto error;
1290
1291 itemSize = DXGetItemSize(inA);
1292
1293 src = (char *)DXGetArrayData(inA);
1294 dst = (char *)DXGetArrayData(outA);
1295 for (j = 0; j < n; j++)
1296 {
1297 for (k = 0; k < outPerIn; k++)
1298 {
1299 memcpy(dst, src, itemSize);
1300 dst += itemSize;
1301 }
1302 src += itemSize;
1303 }
1304
1305 }
1306 }
1307 else
1308 {
1309 DXSetError(ERROR_DATA_INVALID, "invalid dependency: %s",
1310 DXGetString((String)attr));
1311 goto error;
1312 }
1313
1314 if (! DXSetComponentValue(field, name, (Object)outA))
1315 goto error;
1316 outA = NULL;
1317 }
1318
1319
1320 if (! DXGetComponentValue(field, "colors"))
1321 {
1322 if (! SetDefaultColor(field, outPerIn*nConnections))
1323 goto error;
1324
1325 if (! DXSetComponentAttribute(field, "colors", "dep",
1326 (Object)DXNewString("connections")))
1327 goto error;
1328 }
1329
1330
1331 if (iInv)
1332 {
1333 int k = 0;
1334
1335 oInv = DXCreateInvalidComponentHandle((Object)cArrayOut,
1336 NULL, "connections");
1337 if (! oInv)
1338 goto error;
1339
1340 for (i = 0; i < nConnections; i++)
1341 if (DXIsElementInvalid(iInv, i))
1342 {
1343 for (j = 0; j < outPerIn; j++)
1344 if (! DXSetElementInvalid(oInv, k++))
1345 goto error;
1346 }
1347 else k += outPerIn;
1348
1349 if (! DXSaveInvalidComponent(field, oInv))
1350 goto error;
1351 }
1352
1353 for (i = 0; i < nDelete; i++)
1354 DXDeleteComponent(field, toDelete[i]);
1355
1356 if (iInv)
1357 DXFreeInvalidComponentHandle(iInv);
1358 if (oInv)
1359 DXFreeInvalidComponentHandle(oInv);
1360
1361 DXFree((Pointer)ebuf);
1362 DXFreeArrayHandle(pHandle);
1363 DXFreeArrayHandle(cHandle);
1364
1365 DXEndField(field);
1366
1367 return OK;
1368
1369 error:
1370 if (iInv)
1371 DXFreeInvalidComponentHandle(iInv);
1372 if (oInv)
1373 DXFreeInvalidComponentHandle(oInv);
1374 DXFree((Pointer)ebuf);
1375 DXFreeArrayHandle(pHandle);
1376 DXFreeArrayHandle(cHandle);
1377 DXFree((Pointer)c_normals);
1378 DXDelete((Object)pArrayOut);
1379 DXDelete((Object)cArrayOut);
1380 DXDelete((Object)outA);
1381 return ERROR;
1382 }
1383
1384 static Error
GetQuadNormal(ArrayHandle pHandle,ArrayHandle cHandle,int n,float * normal)1385 GetQuadNormal(ArrayHandle pHandle, ArrayHandle cHandle, int n, float *normal)
1386 {
1387 int j;
1388
1389 for (j = 0; j < n; j++, normal += 3)
1390 {
1391 int *quad, quadbuf[4];
1392 float *p, *q, *r, *s;
1393 float pbuf[3], qbuf[3], rbuf[3], sbuf[3];
1394
1395 quad = (int *)DXGetArrayEntry(cHandle, j, (Pointer)quadbuf);
1396 p = (float *)DXGetArrayEntry(pHandle, quad[0], (Pointer)pbuf);
1397 q = (float *)DXGetArrayEntry(pHandle, quad[1], (Pointer)qbuf);
1398 r = (float *)DXGetArrayEntry(pHandle, quad[2], (Pointer)rbuf);
1399 s = (float *)DXGetArrayEntry(pHandle, quad[3], (Pointer)sbuf);
1400
1401 if (! _GetQuadNormal(p, q, r, s, normal))
1402 continue;
1403
1404 return OK;
1405
1406 }
1407
1408 return ERROR;
1409 }
1410
1411 static Error
GetQuadNormals(ArrayHandle pHandle,ArrayHandle cHandle,int n,float ** normals)1412 GetQuadNormals(ArrayHandle pHandle, ArrayHandle cHandle, int n, float **normals)
1413 {
1414 int j;
1415 float *ptr;
1416
1417 *normals = (float *)DXAllocateLocal(n * 3 * sizeof(float));
1418 if (! *normals)
1419 {
1420 DXResetError();
1421 *normals = (float *)DXAllocate(n * 3 * sizeof(float));
1422 }
1423 if (! *normals)
1424 return ERROR;
1425
1426 ptr = *normals;
1427 for (j = 0; j < n; j++, ptr += 3)
1428 {
1429 int *quad, quadbuf[4];
1430 float *p, *q, *r, *s;
1431 float pbuf[3], qbuf[3], rbuf[3], sbuf[3];
1432
1433 quad = (int *)DXGetArrayEntry(cHandle, j, (Pointer)quadbuf);
1434 p = (float *)DXGetArrayEntry(pHandle, quad[0], (Pointer)pbuf);
1435 q = (float *)DXGetArrayEntry(pHandle, quad[1], (Pointer)qbuf);
1436 r = (float *)DXGetArrayEntry(pHandle, quad[2], (Pointer)rbuf);
1437 s = (float *)DXGetArrayEntry(pHandle, quad[3], (Pointer)sbuf);
1438
1439 if (! _GetQuadNormal(p, q, r, s, ptr))
1440 ptr[0] = ptr[1] = ptr[2] = 0;
1441 }
1442
1443 return OK;
1444 }
1445
1446 static Error
GetTriNormal(ArrayHandle pHandle,ArrayHandle cHandle,int n,float * normal)1447 GetTriNormal(ArrayHandle pHandle, ArrayHandle cHandle, int n, float *normal)
1448 {
1449 int j;
1450
1451 for (j = 0; j < n; j++)
1452 {
1453 int *tri, tbuf[3];
1454 float *p, *q, *r;
1455 float pbuf[3], qbuf[3], rbuf[3];
1456
1457 tri = (int *)DXGetArrayEntry(cHandle, j, (Pointer)tbuf);
1458 p = (float *)DXGetArrayEntry(pHandle, tri[0], (Pointer)pbuf);
1459 q = (float *)DXGetArrayEntry(pHandle, tri[1], (Pointer)qbuf);
1460 r = (float *)DXGetArrayEntry(pHandle, tri[2], (Pointer)rbuf);
1461
1462 if (_GetTriNormal(p, q, r, normal))
1463 return OK;
1464 }
1465
1466 return ERROR;
1467 }
1468
1469 static Error
GetTriNormals(ArrayHandle pHandle,ArrayHandle cHandle,int n,float ** normals)1470 GetTriNormals(ArrayHandle pHandle, ArrayHandle cHandle, int n, float **normals)
1471 {
1472 int j;
1473 float *ptr;
1474
1475 *normals = (float *)DXAllocateLocal(n * 3 * sizeof(float));
1476 if (! *normals)
1477 {
1478 DXResetError();
1479 *normals = (float *)DXAllocate(n * 3 * sizeof(float));
1480 }
1481 if (! *normals)
1482 return ERROR;
1483
1484 ptr = *normals;
1485 for (j = 0; j < n; j++, ptr+=3)
1486 {
1487 int *tri, tbuf[3];
1488 float *p, *q, *r, pbuf[3], qbuf[3], rbuf[3];
1489
1490 tri = (int *)DXGetArrayEntry(cHandle, j, (Pointer)tbuf);
1491 p = (float *)DXGetArrayEntry(pHandle, tri[0], (Pointer)pbuf);
1492 q = (float *)DXGetArrayEntry(pHandle, tri[1], (Pointer)qbuf);
1493 r = (float *)DXGetArrayEntry(pHandle, tri[2], (Pointer)rbuf);
1494
1495 if (! _GetTriNormal(p, q, r, ptr))
1496 ptr[0] = ptr[1] = ptr[2] = 0.0;
1497 }
1498
1499 return OK;
1500 }
1501
1502 static Error
_GetTriNormal(float * p,float * q,float * r,float * normal)1503 _GetTriNormal(float *p, float *q, float *r, float *normal)
1504 {
1505 float v0[3], v1[3], d;
1506
1507 vector_subtract((Vector *)q, (Vector *)p, (Vector *)v0);
1508 vector_subtract((Vector *)r, (Vector *)p, (Vector *)v1);
1509 vector_cross((Vector *)v0, (Vector *)v1, (Vector *)normal);
1510 d = vector_length((Vector *)normal);
1511 if (d == 0.0)
1512 return ERROR;
1513 else
1514 vector_scale((Vector *)normal, 1.0/d, (Vector *)normal);
1515
1516 return OK;
1517 }
1518
1519 static Error
_GetQuadNormal(float * p,float * q,float * r,float * s,float * normal)1520 _GetQuadNormal(float *p, float *q, float *r, float *s, float *normal)
1521 {
1522 float v0[3], v1[3], d, cross[3];
1523
1524 vector_subtract((Vector *)q, (Vector *)p, (Vector *)v0);
1525 vector_subtract((Vector *)r, (Vector *)p, (Vector *)v1);
1526 vector_cross((Vector *)v1, (Vector *)v0, (Vector *)normal);
1527
1528 vector_subtract((Vector *)s, (Vector *)q, (Vector *)v0);
1529 vector_subtract((Vector *)p, (Vector *)q, (Vector *)v1);
1530 vector_cross((Vector *)v1, (Vector *)v0, (Vector *)cross);
1531 vector_add((Vector *)normal, (Vector *)cross, (Vector *)normal);
1532
1533 vector_subtract((Vector *)r, (Vector *)s, (Vector *)v0);
1534 vector_subtract((Vector *)q, (Vector *)s, (Vector *)v1);
1535 vector_cross((Vector *)v1, (Vector *)v0, (Vector *)cross);
1536 vector_add((Vector *)normal, (Vector *)cross, (Vector *)normal);
1537
1538 vector_subtract((Vector *)p, (Vector *)r, (Vector *)v0);
1539 vector_subtract((Vector *)s, (Vector *)r, (Vector *)v1);
1540 vector_cross((Vector *)v1, (Vector *)v0, (Vector *)cross);
1541 vector_add((Vector *)normal, (Vector *)cross, (Vector *)normal);
1542
1543 d = vector_length((Vector *)normal);
1544 if (d == 0.0)
1545 return ERROR;
1546 else
1547 vector_scale((Vector *)normal, 1.0/d, (Vector *)normal);
1548
1549 return OK;
1550 }
1551
1552 static enum PrimType
GetPrimType(Field field)1553 GetPrimType(Field field)
1554 {
1555 Object attr;
1556 char *str;
1557
1558 attr = DXGetComponentAttribute(field, "connections", "element type");
1559 if (! attr)
1560 {
1561 if (! DXGetComponentValue(field, "connections"))
1562 DXSetError(ERROR_MISSING_DATA, "connections");
1563 else
1564 DXSetError(ERROR_MISSING_DATA, "element type attribute");
1565 return PRIM_INVALID;
1566 }
1567
1568 if (DXGetObjectClass(attr) != CLASS_STRING)
1569 {
1570 DXSetError(ERROR_INTERNAL, "element type attribute not STRING");
1571 return PRIM_INVALID;
1572 }
1573
1574 str = DXGetString((String)attr);
1575
1576 if (! strcmp(str, "lines"))
1577 return PRIM_LINES;
1578 else if (! strcmp(str, "quads"))
1579 return PRIM_QUADS;
1580 else if (! strcmp(str, "triangles"))
1581 return PRIM_TRIANGLES;
1582
1583 DXSetError(ERROR_DATA_INVALID, "element type %s not supported", str);
1584 return PRIM_INVALID;
1585 }
1586
1587 static Error
SetDefaultColor(Field field,int n)1588 SetDefaultColor(Field field, int n)
1589 {
1590 RegularArray array;
1591 float color[3];
1592 float delta[3];
1593
1594 color[0] = 0.5; color[1] = 0.7; color[2] = 1.0;
1595 delta[0] = 0.0; delta[1] = 0.0; delta[2] = 0.0;
1596
1597 array = DXNewRegularArray(TYPE_FLOAT, 3, n, (Pointer)color, (Pointer)delta);
1598 if (! array)
1599 return ERROR;
1600
1601 DXSetComponentValue(field, "colors", (Object)array);
1602
1603 return OK;
1604 }
1605
1606 static Error
ValidForRubberSheet(Object object)1607 ValidForRubberSheet(Object object)
1608 {
1609 Category cat;
1610 int rank, shape[32];
1611
1612 if (! DXGetType(object, NULL, &cat, &rank, shape) ||
1613 (cat != CATEGORY_REAL) ||
1614 (! (rank == 0 || (rank == 1 && shape[0] == 1))))
1615 {
1616 DXSetError(ERROR_DATA_INVALID,
1617 "invalid data: scalar or 1-vector real data required");
1618 return ERROR;
1619 }
1620
1621 return OK;
1622 }
1623
1624 static Error
GetScaleAndOffset(Object obj,Object scale_o,Object min_o,Object max_o,float * scale,float * offset)1625 GetScaleAndOffset(Object obj, Object scale_o, Object min_o,
1626 Object max_o, float *scale, float *offset)
1627 {
1628 float thickness;
1629 float max, min;
1630 Class class;
1631
1632 if (! DXStatistics(obj, "data", &min, &max, NULL, NULL))
1633 {
1634 DXAddMessage("#10520","data");
1635 return ERROR;
1636 }
1637
1638 if (min_o)
1639 {
1640 if (! DXExtractParameter(min_o, TYPE_FLOAT, 1, 1, (Pointer)&min))
1641 {
1642 class = DXGetObjectClass(min_o);
1643
1644 if ((class != CLASS_GROUP) && (class != CLASS_FIELD))
1645 {
1646 /*
1647 * min must be a field or a scalar value
1648 */
1649 DXSetError(ERROR_BAD_PARAMETER, "#10520", "min");
1650 return ERROR;
1651 }
1652
1653 if (! DXStatistics(min_o, "data", &min, NULL, NULL, NULL))
1654 {
1655 /*
1656 * min must be a field or a scalar value
1657 */
1658 DXAddMessage("#10520","min");
1659 return ERROR;
1660 }
1661 }
1662
1663 *offset = -min;
1664 }
1665 else
1666 *offset = 0.0;
1667
1668 if (max_o)
1669 {
1670 if (! DXExtractParameter(max_o, TYPE_FLOAT, 1, 1, (Pointer)&max))
1671 {
1672 class = DXGetObjectClass(max_o);
1673
1674 if ((class != CLASS_GROUP) && (class != CLASS_FIELD))
1675 {
1676 /*
1677 * max must be a field or a scalar value
1678 */
1679 DXSetError(ERROR_BAD_PARAMETER, "#10520", "max");
1680 return ERROR;
1681 }
1682
1683 if (! DXStatistics(max_o, "data", NULL, &max, NULL, NULL))
1684 {
1685 /*
1686 * max must be a field or a scalar value
1687 */
1688 DXAddMessage("#10520","max");
1689 return ERROR;
1690 }
1691 }
1692 }
1693
1694 if (scale_o)
1695 {
1696 if (! DXExtractParameter (scale_o, TYPE_FLOAT, 1, 1, (Pointer)scale))
1697 {
1698 /*
1699 * scale must be a scalar value
1700 */
1701 DXSetError (ERROR_BAD_PARAMETER, "#10080", "scale");
1702 return ERROR;
1703 }
1704 }
1705 else
1706 {
1707 Point boxPoints[8];
1708
1709 if (! DXBoundingBox(obj, boxPoints))
1710 return (ERROR);
1711
1712 thickness = DXLength(DXSub(boxPoints[7], boxPoints[0]));
1713 if (thickness == 0.0)
1714 {
1715 *scale = 0;
1716 }
1717 else
1718 {
1719 if (min == max)
1720 {
1721 *scale = 1.0;
1722 }
1723 else
1724 {
1725 *scale = thickness / (10.0 * (max - min));
1726 }
1727 }
1728 }
1729
1730 return OK;
1731 }
1732