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)&params, 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