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 #include <dxconfig.h>
10 
11 #if defined(HAVE_STRING_H)
12 #include <string.h>
13 #endif
14 
15 #include <dx/dx.h>
16 
17 #if defined(HAVE_SYS_TYPES_H)
18 #include <sys/types.h>
19 #endif
20 
21 #include "_normals.h"
22 
23 /*
24  *
25  * data structures, constants and prototypes
26  *
27  */
28 
29 #define MAXDEPTH 200
30 #define MAXRANK  100
31 
32 /* info about where and how to draw each object
33  */
34 typedef struct construct {
35     Class class;                /* object class determines shape */
36     int isattr;                 /* this object is an attribute of another */
37     int isshared;               /* this object is used more than once */
38     Point center;		/* center of this objects representation */
39     float di, dj, dk; 		/* size of the node box */
40     Point in, out;              /* location where attachment lines connect */
41 } Construct;
42 
43 /* info about how to do the general layout
44  */
45 typedef struct policy {
46     int vertical;               /* vs. horizontal */
47     int version;                /* test code */
48 } Policy;
49 
50 /* your basic linked list
51  */
52 typedef struct nlist {
53     struct node *this;
54     struct nlist *next;
55 } Nlist;
56 
57 /* one of these nodes per object in the input, storing the
58  *  type and relationship between the objs.
59  */
60 typedef struct node {
61     int level;			/* depth from the top object */
62     int levelnumber;		/* which member of my level */
63     int isattr;			/* am i an attribute of my parent? */
64     int attrnumber;		/* which attribute of my parent */
65     int descendents;            /* number of child objects (ex. attrs) */
66     int predescend;             /* accum width preceeding my first child */
67     int lastdescend;            /* accum width at end of my last child */
68     struct node *attr;		/* my first attribute */
69     struct node *child;		/* my first child */
70     struct node *sibling;	/* the next object at my level */
71     struct node *parent;	/* my parent object */
72     Nlist *godparent;		/* if shared, more parent objects */
73     char *ptag;                 /* text for this obj from parent */
74     char *ctag;                 /* text for this obj describing child */
75     Construct where;            /* where and how big to draw this object */
76 } Node;
77 
78 /* overall stats which are needed to do layout
79  */
80 typedef struct layout {
81     int level;                  /* current depth from top obj */
82     int maxlevel;               /* deepest depth from top obj to bottom */
83     int membercount;            /* total number of objects */
84     int uniquemembers;          /* number of unique objects */
85     int levelmembers[MAXDEPTH]; /* number of members per level */
86     int maxlevelmembers;        /* largest number of members at any level */
87     int widestlevel;            /* which level contains the most members */
88 } Layout;
89 
90 /* pointers directly to the next available location in each array.
91  */
92 typedef struct quick {
93     Point *pos;			/* pointer into positions array */
94     int *conn;			/* pointer into connections array */
95     RGBColor *color;		/* pointer into colors array */
96 } Quick;
97 
98 /* output object information
99  */
100 typedef struct outobjinfo {
101     Group g;                    /* output object */
102     Object font;		/* font for labels */
103 
104     Field fquads;               /* field of quads (is this needed?) */
105     int totalquads;             /* total number of quads in output */
106     int nquads;                 /* current number of quads */
107     Quick quaddata;             /* pointers to speed access */
108 
109     Field flines;               /* field of lines */
110     int totallines;             /* total number of lines in output */
111     int nlines;                 /* current number of lines */
112     Quick linedata;             /* pointers to speed access */
113 
114     Field ftris;                /* field of triangles */
115     int totaltris;              /* total number of triangles in output */
116     int ntris;                  /* current number of triangles */
117     Quick tridata;              /* pointers to speed access */
118 
119     Field fpoints;              /* field of scattered points */
120     int totalpoints;		/* total number of scattered pts in output */
121     int npoints;                /* current number of scattered points */
122     Quick pointdata;		/* pointers to speed access */
123 
124 } OutObjInfo;
125 
126 /* input object information
127  */
128 typedef struct inobjinfo {
129     Layout layout;              /* overall stats on object */
130     HashTable ht;               /* used to determine if objects are shared */
131     Policy policy;              /* overall layout policy */
132     Node *root;                 /* root of node tree */
133 } InObjInfo;
134 
135 /*  single handle to make it easy to pass data structs around
136  */
137 typedef struct visinfo {
138     InObjInfo oi;		/* the input object we are trying to see */
139     OutObjInfo oo;		/* the output object we are creating */
140 } VisInfo;
141 
142 
143 /* the three basic processing passes:
144  *
145  *  build a structure representing each object and it's relationship
146  *   with other objects, and accumuate stats on the overall number of
147  *   nodes, their size, the amount of geometry it is going to take to
148  *   represent this visually.
149  *
150  *  decide the layout of the nodes
151  *
152  *  convert that struct into geometry, with the option of each object
153  *   type being a different shape, size and color.
154  *
155  */
156 static Error traverse (Object o, VisInfo *vi, Node *parent,
157 		       int isattr, int num, char *ptag);
158 static Error layout (VisInfo *vi);
159 static Object makevisual (VisInfo *vi);
160 
161 static Error initVisInfo (VisInfo *vi);         /* create & init new */
162 static Error initInObjInfo (InObjInfo *oi);
163 static Error initOutObjInfo (OutObjInfo *oo);
164 static void  endVisInfo (VisInfo *vi);          /* normal exit */
165 static void  endInObjInfo (InObjInfo *oi);
166 static void  endOutObjInfo (OutObjInfo *oo);
167 static void  errdelVisInfo (VisInfo *vi);       /* error exit */
168 static void  errdelInObjInfo (InObjInfo *oi);
169 static void  errdelOutObjInfo (OutObjInfo *oo);
170 
171 
172 static Node *newnode (int level, int isattr, int number, int dup,
173 		      Class class, Node *parent, char *ptag);
174 static Error freenodetree (Node *np);
175 static int nodeplace (Node *np, Policy *p, Layout *l, OutObjInfo *oo);
176 static void attrplace (Node *np, Policy *p, Layout *l, OutObjInfo *oo);
177 static void nodecenter (Node *np, Policy *p, Layout *l, int isShared);
178 static Error drawObject (OutObjInfo *oo, Node *np, Policy *p);
179 static Error setptag(Node *np, char *ptag);
180 static Error setctag(Node *np, char *ctag);
181 
182 static Error setpolicyversion (VisInfo *vi, int version);
183 static Error setpolicyvertical (VisInfo *vi, int vertical);
184 
185 /* needed anymore? */
186 #if 0
187 static Error addparent (Node *me, Node *parent);
188 static int numnodes (Node *np);
189 #endif
190 
191 static void nodecount (Node *np, int *count);
192 
193 /* these need overhaul now */
194 static Error initgroup (OutObjInfo *oo);
195 
196 static Error allocoutobj (OutObjInfo *oo);
197 static Error nextoutobj (OutObjInfo *oo, Node *np, Policy *p);
198 static Error addCube (OutObjInfo *oo, Node *np, RGBColor *c);
199 static Error addLabel (Group g, Object font, Construct *c, Policy *p);
200 static Error addStringTag (char *s, int type, Group g, Object font,
201 			   Construct *c, Policy *p);
202 
203 static void geomCount (OutObjInfo *oo, Class class, int isAttr, int isShared);
204 
205 /*
206  *
207  * subroutines to determine if an object is shared
208  *
209  */
210 
211 
212 /* duplicate object section
213  */
214 
215 /* (should this be moved to libdx at some point?) */
216 
217 struct hashElement
218 {
219     Pointer   key;	/* either an object or an id */
220     Pointer   data;	/* the other thing */
221 };
222 
223 typedef struct hashElement *HashElement;
224 
225 /* looks for entry keyed by object memory address.  if found, sets
226  *  the id associated with that object.  if not found, sets id to 0.
227  *  after determining the object isn't already in the list, AddID should be
228  *  called to put the new object and ID in the list.
229  */
FindIDbyObject(HashTable ht,Object object,ulong * id)230 static HashTable FindIDbyObject(HashTable ht, Object object, ulong *id)
231 {
232     HashElement eltPtr;
233 
234     eltPtr = (HashElement)DXQueryHashElement(ht, (Key)&object);
235     *id = eltPtr ? (ulong)eltPtr->data : 0;
236 
237     return ht;
238 }
239 
240 
AddIDbyObject(HashTable ht,Object object,ulong id)241 static HashTable AddIDbyObject(HashTable ht, Object object, ulong id)
242 {
243     struct hashElement elt;
244     HashElement        eltPtr;
245 
246     elt.key  = (Pointer)object;
247     elt.data = (Pointer)id;
248 
249     eltPtr = (HashElement)DXQueryHashElement(ht, (Key)&object);
250     if (eltPtr)
251 	return NULL;   /* shouldn't already be there */
252 
253     if (! DXInsertHashElement(ht, (Element)&elt))
254 	return NULL;
255 
256     return ht;
257 }
258 
259 /* looks for entry keyed by ID and sets object to the object memory address
260  *  associated with it, if present.  if not found, sets object to NULL.
261  *  the AddObject function, below, is used to add an object to the
262  *  table by ID.
263  */
264 #if 0
265 static HashTable FindObjectbyID(HashTable ht, ulong id, Object *object)
266 {
267     HashElement eltPtr;
268 
269     eltPtr = (HashElement)DXQueryHashElement(ht, (Key)&id);
270     *object = eltPtr ? (Object)eltPtr->data : NULL;
271 
272     return ht;
273 }
274 
275 static HashTable AddObjectbyID(HashTable ht, ulong id, Object object)
276 {
277     struct hashElement elt;
278     HashElement        eltPtr;
279 
280     elt.key  = (Pointer)id;
281     elt.data = (Pointer)object;
282 
283     eltPtr = (HashElement)DXQueryHashElement(ht, (Key)&id);
284     if (eltPtr)
285 	return NULL;  /* shouldn't already be there */
286 
287     if (! DXInsertHashElement(ht, (Element)&elt))
288 	return NULL;
289 
290     return ht;
291 }
292 #endif
293 
294 
295 /*
296  * data struct manipulation routines
297  */
298 
initVisInfo(VisInfo * vi)299 static Error initVisInfo(VisInfo *vi)
300 {
301     if (initInObjInfo(&vi->oi) == ERROR)
302 	return ERROR;
303 
304     if (initOutObjInfo(&vi->oo) == ERROR)
305 	return ERROR;
306 
307     return OK;
308 }
309 
initInObjInfo(InObjInfo * oi)310 static Error initInObjInfo(InObjInfo *oi)
311 {
312     memset((char *)oi, '\0', sizeof(*oi));
313 
314     if (!(oi->ht = DXCreateHash(sizeof(struct hashElement), NULL, NULL)))
315 	return ERROR;
316 
317     oi->layout.level = -1;
318     oi->policy.vertical = 1;
319 
320     return OK;
321 }
322 
initOutObjInfo(OutObjInfo * oo)323 static Error initOutObjInfo(OutObjInfo *oo)
324 {
325     memset((char *)oo, '\0', sizeof(*oo));
326 
327     /* make the groups, fields and arrays, but don't allocate
328      *  space in the arrays until you know how many items they will
329      *  eventually hold.
330      */
331     if (!initgroup(oo))
332 	return ERROR;
333 
334     if (!(oo->font = DXGetFont("variable", NULL, NULL)))
335 	return ERROR;
336 
337     return OK;
338 }
339 
endVisInfo(VisInfo * vi)340 static void endVisInfo(VisInfo *vi)
341 {
342     endInObjInfo(&vi->oi);
343     endOutObjInfo(&vi->oo);
344 }
345 
endInObjInfo(InObjInfo * oi)346 static void endInObjInfo(InObjInfo *oi)
347 {
348     DXDestroyHash(oi->ht);
349     freenodetree(oi->root);
350 }
351 
endOutObjInfo(OutObjInfo * oo)352 static void endOutObjInfo(OutObjInfo *oo)
353 {
354     if (!oo)
355 	return;
356 
357     if (oo->g)
358 	DXEndObject ((Object) oo->g);
359 
360     DXDelete (oo->font);
361 }
362 
errdelVisInfo(VisInfo * vi)363 static void errdelVisInfo(VisInfo *vi)
364 {
365     errdelInObjInfo (&vi->oi);
366     errdelOutObjInfo (&vi->oo);
367 }
368 
errdelInObjInfo(InObjInfo * oi)369 static void errdelInObjInfo(InObjInfo *oi)
370 {
371     DXDestroyHash (oi->ht);
372     freenodetree (oi->root);
373 }
374 
errdelOutObjInfo(OutObjInfo * oo)375 static void errdelOutObjInfo(OutObjInfo *oo)
376 {
377     if (!oo)
378 	return;
379 
380     DXDelete ((Object)oo->g);
381     DXDelete ((Object)oo->font);
382 }
383 
initgroup(OutObjInfo * oo)384 static Error initgroup(OutObjInfo *oo)
385 {
386     Field f;
387     Array a=NULL;
388 
389     /* top level group */
390     if (!(oo->g = DXNewGroup()))
391 	return ERROR;
392 
393     /* quads */
394     if (!(f = DXNewField()))
395 	goto error;
396 
397     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
398 	goto error;
399     if (!DXSetComponentValue(f, "positions", (Object)a))
400 	goto error;
401     a = NULL;
402 
403     if (!(a = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 4)))
404 	goto error;
405     if (!DXSetStringAttribute((Object)a, "element type", "quads"))
406 	goto error;
407     if (!DXSetStringAttribute((Object)a, "ref", "positions"))
408 	goto error;
409     if (!DXSetComponentValue(f, "connections", (Object)a))
410 	goto error;
411     a = NULL;
412 
413     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
414 	goto error;
415     if (!DXSetStringAttribute((Object)a, "dep", "connections"))
416 	goto error;
417     if (!DXSetComponentValue(f, "colors", (Object)a))
418 	goto error;
419     a = NULL;
420 
421     if (!DXSetMember(oo->g, "quads", (Object)f))
422 	goto error;
423     oo->fquads = f;
424     f = NULL;
425 
426 
427     /* lines */
428     if (!(f = DXNewField()))
429 	return ERROR;
430 
431     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
432 	goto error;
433     if (!DXSetComponentValue(f, "positions", (Object)a))
434 	goto error;
435     a = NULL;
436 
437     if (!(a = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2)))
438 	goto error;
439     if (!DXSetStringAttribute((Object)a, "element type", "lines"))
440 	goto error;
441     if (!DXSetStringAttribute((Object)a, "ref", "positions"))
442 	goto error;
443     if (!DXSetComponentValue(f, "connections", (Object)a))
444 	goto error;
445     a = NULL;
446 
447     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
448 	goto error;
449     if (!DXSetStringAttribute((Object)a, "dep", "connections"))
450 	goto error;
451     if (!DXSetComponentValue(f, "colors", (Object)a))
452 	goto error;
453     a = NULL;
454 
455     if (!DXSetMember(oo->g, "lines", (Object)f))
456 	goto error;
457     oo->flines = f;
458     f = NULL;
459 
460 
461     /* tris */
462     if (!(f = DXNewField()))
463 	return ERROR;
464 
465     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
466 	goto error;
467     if (!DXSetComponentValue(f, "positions", (Object)a))
468 	goto error;
469     a = NULL;
470 
471     if (!(a = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3)))
472 	goto error;
473     if (!DXSetStringAttribute((Object)a, "element type", "triangles"))
474 	goto error;
475     if (!DXSetStringAttribute((Object)a, "ref", "positions"))
476 	goto error;
477     if (!DXSetComponentValue(f, "connections", (Object)a))
478 	goto error;
479     a = NULL;
480 
481     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
482 	goto error;
483     if (!DXSetStringAttribute((Object)a, "dep", "connections"))
484 	goto error;
485     if (!DXSetComponentValue(f, "colors", (Object)a))
486 	goto error;
487     a = NULL;
488 
489     if (!DXSetMember(oo->g, "triangles", (Object)f))
490 	goto error;
491     oo->ftris = f;
492     f = NULL;
493 
494 
495     /* points */
496     if (!(f = DXNewField()))
497 	return ERROR;
498 
499     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
500 	goto error;
501     if (!DXSetComponentValue(f, "positions", (Object)a))
502 	goto error;
503     a = NULL;
504 
505     if (!(a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3)))
506 	goto error;
507     if (!DXSetStringAttribute((Object)a, "dep", "positions"))
508 	goto error;
509     if (!DXSetComponentValue(f, "colors", (Object)a))
510 	goto error;
511     a = NULL;
512 
513     if (!DXSetMember(oo->g, "points", (Object)f))
514 	goto error;
515     oo->fpoints = f;
516     f = NULL;
517 
518 
519     return OK;
520 
521   error:
522     DXDelete((Object)oo->g);
523     DXDelete((Object)f);
524     DXDelete((Object)a);
525     return ERROR;
526 }
527 
addCube(OutObjInfo * oo,Node * n,RGBColor * colorptr)528 static Error addCube(OutObjInfo *oo, Node *n, RGBColor *colorptr)
529 {
530     Point *t;     /* center of this cube */
531     Point *cp;    /* corners of cube for child, centers of parent bottom (0)
532 		     and child top (1) for line */
533     Construct *l; /* the 'where' info */
534     int i, *ip;
535     int index;    /* next cube number */
536     int point;    /* point index numbers */
537     RGBColor *c;  /* quad and line colors */
538 
539 
540     l = &n->where;
541     t = &l->center;
542 
543     /* cube positions - each cube is 6 quads */
544     cp = oo->quaddata.pos;
545     index = oo->nquads;
546 
547     cp->x = t->x - l->di;  cp->y = t->y - l->dj;  cp->z = t->z - l->dk;  cp++;
548     cp->x = t->x - l->di;  cp->y = t->y - l->dj;  cp->z = t->z + l->dk;  cp++;
549     cp->x = t->x - l->di;  cp->y = t->y + l->dj;  cp->z = t->z - l->dk;  cp++;
550     cp->x = t->x - l->di;  cp->y = t->y + l->dj;  cp->z = t->z + l->dk;  cp++;
551 
552     cp->x = t->x + l->di;  cp->y = t->y - l->dj;  cp->z = t->z - l->dk;  cp++;
553     cp->x = t->x + l->di;  cp->y = t->y - l->dj;  cp->z = t->z + l->dk;  cp++;
554     cp->x = t->x + l->di;  cp->y = t->y + l->dj;  cp->z = t->z - l->dk;  cp++;
555     cp->x = t->x + l->di;  cp->y = t->y + l->dj;  cp->z = t->z + l->dk;  cp++;
556 
557     oo->quaddata.pos += 8;
558 
559 
560     /* quad connections */
561     ip = oo->quaddata.conn;
562     point = 8 * index/6;
563 
564     *ip++ = point+0; *ip++ = point+1; *ip++ = point+4; *ip++ = point+5;
565     *ip++ = point+0; *ip++ = point+2; *ip++ = point+1; *ip++ = point+3;
566     *ip++ = point+0; *ip++ = point+4; *ip++ = point+2; *ip++ = point+6;
567     *ip++ = point+7; *ip++ = point+3; *ip++ = point+6; *ip++ = point+2;
568     *ip++ = point+7; *ip++ = point+6; *ip++ = point+5; *ip++ = point+4;
569     *ip++ = point+7; *ip++ = point+5; *ip++ = point+3; *ip++ = point+1;
570 
571     oo->quaddata.conn += 6 * 4;
572 
573 
574     /* cube color */
575     c = oo->quaddata.color;
576 
577     for (i=0; i<6; i++) {
578 	*c = *colorptr; c++;
579     }
580 
581     oo->quaddata.color += 6;
582 
583     oo->nquads += 6;
584 
585 
586     /* line between child and parent */
587     if (n->parent) {
588 	index = oo->nlines;
589 
590 	/* line positions */
591 	cp = oo->linedata.pos;
592 
593 	cp[0] = n->parent->where.out;
594 	cp[1] = l->in;
595 
596 	oo->linedata.pos += 2;
597 
598 	/* line connections */
599 	ip = oo->linedata.conn;
600 	point = 2 * index;
601 
602 	for (i=0; i<2; i++)
603 	    ip[i] = point++;
604 
605 	oo->linedata.conn += 2;
606 
607 	/* line color */
608 	c = oo->linedata.color;
609 
610 	c->r = 0.9; c->g = 0.8; c->b = 0.1;
611 
612 	oo->linedata.color++;
613 
614 	oo->nlines++;
615     }
616 
617     return OK;
618 }
619 
initarray(Group g,char * member,char * component,int count,int mult)620 static Pointer initarray(Group g, char *member, char *component,
621     int count, int mult)
622 {
623     Field f;
624     Array a;
625     Pointer p;
626 
627     if (!(f = (Field) DXGetMember(g, member)))
628 	return NULL;
629 
630     if (!(a = (Array)DXGetComponentValue(f, component)))
631 	return NULL;
632 
633     if (!DXAddArrayData(a, 0, count * mult, NULL))
634 	return NULL;
635 
636     if (!(p = DXGetArrayData(a)))
637 	return NULL;
638 
639     return p;
640 }
641 
allocoutobj(OutObjInfo * oo)642 static Error allocoutobj(OutObjInfo *oo)
643 {
644     Quick *q;
645 
646     if (oo->totalquads > 0) {
647 	q = &oo->quaddata;
648 	if (!(q->pos = (Point *)initarray (oo->g, "quads", "positions",
649 					   oo->totalquads/6, 8)))
650 	    return ERROR;
651 
652 	if (!(q->conn = (int *)initarray (oo->g, "quads", "connections",
653 					  oo->totalquads, 1)))
654 	    return ERROR;
655 
656 	if (!(q->color = (RGBColor *)initarray (oo->g, "quads", "colors",
657 						oo->totalquads, 1)))
658 	    return ERROR;
659     }
660 
661     if (oo->totallines > 0) {
662 	q = &oo->linedata;
663 	if (!(q->pos = (Point *)initarray (oo->g, "lines", "positions",
664 					   oo->totallines, 2)))
665 	    return ERROR;
666 
667 	if (!(q->conn = (int *)initarray (oo->g, "lines", "connections",
668 					  oo->totallines, 1)))
669 	    return ERROR;
670 
671 	if (!(q->color = (RGBColor *)initarray (oo->g, "lines", "colors",
672 						oo->totallines, 1)))
673 	    return ERROR;
674     }
675 
676     if (oo->totaltris > 0) {
677 	q = &oo->tridata;
678 	if (!(q->pos = (Point *)initarray (oo->g, "tris", "positions",
679 					   oo->totaltris, 3)))
680 	    return ERROR;
681 
682 	if (!(q->conn = (int *)initarray (oo->g, "tris", "connections",
683 					  oo->totaltris, 1)))
684 	    return ERROR;
685 
686 	if (!(q->color = (RGBColor *)initarray (oo->g, "tris", "colors",
687 						oo->totaltris, 1)))
688 	    return ERROR;
689     }
690 
691     if (oo->totalpoints > 0) {
692 	q = &oo->pointdata;
693 	if (!(q->pos = (Point *)initarray (oo->g, "points", "positions",
694 					   oo->totalpoints, 1)))
695 	    return ERROR;
696 
697 	q->conn = NULL;
698 
699 	if (!(q->color = (RGBColor *)initarray (oo->g, "points", "colors",
700 						oo->totalpoints, 1)))
701 	    return ERROR;
702     }
703 
704     return OK;
705 }
706 
nextoutobj(OutObjInfo * oo,Node * np,Policy * p)707 static Error nextoutobj(OutObjInfo *oo, Node *np, Policy *p)
708 {
709     Node *thisnp;
710 
711     for (thisnp = np; thisnp; thisnp = thisnp->sibling) {
712 
713 	if (thisnp->attr)
714 	    nextoutobj(oo, thisnp->attr, p);
715 
716 	if (thisnp->child)
717 	    nextoutobj(oo, thisnp->child, p);
718 
719 	drawObject(oo, thisnp, p);
720     }
721 
722     return OK;
723 }
724 
725 
726 /* initialize a node and make the links to parents, siblings
727  */
newnode(int level,int isattr,int number,int dup,Class class,Node * parent,char * ptag)728 static Node *newnode(int level, int isattr, int number, int dup, Class class,
729 		     Node *parent, char *ptag)
730 {
731     Node *np = NULL;
732 
733     if (!(np = DXAllocateLocalZero(sizeof(Node))))
734 	return NULL;
735 
736 #if 1  /* debug */
737     if (!isattr) {
738 	DXDebug("V", "crNode: level %d, member %2d", level, number);
739     } else {
740 	DXDebug("V", "crAttr: level %d, member %2d", level, number);
741     }
742 #endif
743 
744     np->level = level;
745     np->isattr = isattr;
746     if (!isattr)
747 	np->levelnumber = number;
748     else
749 	np->attrnumber = number;
750     np->where.class = class;
751     np->where.isattr = isattr;
752     np->where.isshared = dup;
753     np->parent = parent;
754     setptag(np, ptag);
755 
756     if (parent) {
757 	if (isattr) {
758 	    if (parent->attr == NULL)
759 		parent->attr = np;
760 	    else {
761 		Node *lnext;
762 
763 		lnext = parent->attr;
764 		while (lnext->sibling)
765 		    lnext = lnext->sibling;
766 		lnext->sibling = np;
767 	    }
768 	} else {
769 	    if (parent->child == NULL)
770 		parent->child = np;
771 	    else {
772 		Node *lnext;
773 
774 		lnext = parent->child;
775 		while (lnext->sibling)
776 		    lnext = lnext->sibling;
777 		lnext->sibling = np;
778 	    }
779 	    parent->descendents++;
780 	}
781     }
782 
783     return np;
784 }
785 
786 /* inserts at the front of the list since that's cheap and insert
787  * order doesn't matter.
788  */
789 #if 0
790 static Error addparent(Node *np, Node *parent)
791 {
792     Nlist *lp;
793 
794     if (!(lp = DXAllocateLocal(sizeof(Nlist))))
795 	return ERROR;
796 
797     lp->this = parent;
798     lp->next = NULL;
799 
800     if (np->godparent)
801 	lp->next = np->godparent;
802 
803     np->godparent = lp;
804 
805     return OK;
806 }
807 #endif
808 
809 /* change the parent tag info for a node
810  */
setptag(Node * np,char * ptag)811 static Error setptag(Node *np, char *ptag)
812 {
813     int len;
814 
815     if (!ptag || !ptag[0])
816 	return OK;
817 
818     len = strlen(ptag) + 1;
819     np->ptag = DXAllocateLocal(len);
820     if (!np->ptag)
821 	return ERROR;
822 
823     strcpy(np->ptag, ptag);
824     return OK;
825 }
826 
827 /* change the child tag info for a node
828  */
setctag(Node * np,char * ctag)829 static Error setctag(Node *np, char *ctag)
830 {
831     int len;
832 
833     if (!ctag || !ctag[0])
834 	return OK;
835 
836     len = strlen(ctag) + 1;
837     np->ctag = DXAllocateLocal(len);
838     if (!np->ctag)
839 	return ERROR;
840 
841     strcpy(np->ctag, ctag);
842     return OK;
843 }
844 
845 /* recurse thru the data structure determining the placement of
846  *  each object node and the number of geometric objects it will
847  *  generate.
848  */
nodeplace(Node * np,Policy * p,Layout * l,OutObjInfo * oo)849 static int nodeplace(Node *np, Policy *p, Layout *l, OutObjInfo *oo)
850 {
851     Node *thisnp;
852     Construct *c;
853     int prev_width = 0;
854 
855 
856     /* if you have a parent, start out at the trailing edge of it */
857     if (np->parent)
858 	prev_width = np->parent->predescend;
859 
860 
861     for (thisnp = np; thisnp; thisnp=thisnp->sibling) {
862 
863 	/* figure out the width your node is centered over */
864 	thisnp->predescend = prev_width;
865 
866 	if (thisnp->child)
867 	    prev_width = nodeplace(thisnp->child, p, l, oo);
868 	else
869 	    prev_width++;
870 
871 	thisnp->lastdescend = prev_width;
872 
873 
874 	/* use policy and layout to determine location and size */
875 	c = &thisnp->where;
876 	nodecenter(thisnp, p, l, c->isshared);
877 	geomCount(oo, c->class, c->isattr, c->isshared);
878 
879 
880 	/* place the attributes after the owning node is placed */
881 	if (thisnp->attr)
882 	    attrplace(thisnp->attr, p, l, oo);
883 
884     }
885 
886     /* return the value for lastdescend for the parent to use */
887     return prev_width;
888 }
889 
890 /* determine placement for attribute nodes, and add up the number of
891  *  geometric objects which will be generated.  attributes don't
892  *  contribute to the overall placement of the object nodes so this
893  *  routine is much simpler than the nodeplace() routine.
894  */
attrplace(Node * np,Policy * p,Layout * l,OutObjInfo * oo)895 static void attrplace(Node *np, Policy *p, Layout *l, OutObjInfo *oo)
896 {
897     Node *thisnp;
898     Construct *c;
899 
900     for (thisnp = np; thisnp; thisnp=thisnp->sibling) {
901 
902 	/* use policy and layout to determine location and size */
903 	c = &thisnp->where;
904 	nodecenter(thisnp, p, l, c->isshared);
905 	geomCount(oo, c->class, c->isattr, c->isshared);
906 
907     }
908 }
909 
910 #define LEVELDEPTH 2.0
911 #define LEVELWIDTH 1.2
912 #define ATTRWIDTH  2.0
913 
914 /* use Policy, class, isShared and isAttr to determine location.
915 */
nodecenter(Node * np,Policy * p,Layout * l,int isShared)916 static void nodecenter(Node *np, Policy *p, Layout *l, int isShared)
917 {
918     Construct *c = &np->where;
919     Node *base;
920     int width = 0;
921 
922     base = (c->isattr) ? np->parent : np;
923 
924 #if 1  /* debug */
925     if (!c->isattr) {
926 	DXDebug("V",
927 		"ptNode: level %d, member %2d: pre=%2d, desc=%2d, last=%2d",
928 		np->level, np->levelnumber,
929 		np->predescend, np->descendents, np->lastdescend);
930     } else {
931 	DXDebug("V",
932 		"ptAttr: level %d, member %2d", np->level, np->attrnumber);
933     }
934 #endif
935 
936     switch (p->version) {
937       case 1:
938 	/* center the members of each level, independent of other levels */
939 	c->center.x = base->level * LEVELDEPTH;
940 	c->center.y = base->levelnumber - (l->levelmembers[base->level] / 2.0);
941 	c->center.z = 0.0;
942 	break;
943 
944       case 2:
945       default:
946 	/* center the parent over its children */
947 	c->center.x = base->level * LEVELDEPTH;
948 	c->center.y = (base->predescend +
949 		    (base->lastdescend - base->predescend)/2.0) * LEVELWIDTH;
950 	c->center.z = 0;
951 	break;
952 
953       case 3:
954 	/* same as 2 with each level in alternating between Y and Z
955 	 * NOT WORKING
956 	 */
957 	c->center.x = base->level * LEVELDEPTH;
958 	if (base->level % 2) {
959 	    c->center.y = (base->predescend +
960 		    (base->lastdescend - base->predescend)/2.0) * LEVELWIDTH;
961 	    c->center.z = 0;
962 	} else {
963 	    c->center.y = 0;
964 	    c->center.z = (base->predescend +
965 		    (base->lastdescend - base->predescend)/2.0) * LEVELWIDTH;
966 	}
967 	break;
968 
969       case 4:
970 	/* put parent over first child */
971 	c->center.x = base->level * LEVELDEPTH;
972 	c->center.y = base->predescend;
973 	c->center.z = 0.0;
974 	break;
975 
976       case 5:
977 	/* use 3rd dim, stack objects in depth at each level */
978 	if (base->parent)
979 	    width = base->parent->predescend;
980 
981 	c->center.x = base->level * LEVELDEPTH;
982 	c->center.y = width + base->descendents/2;
983 	c->center.z = base->levelnumber - (l->levelmembers[base->level] / 2.0);
984 	break;
985 
986     }
987 
988     c->di = 0.15;
989     c->dj = 0.15;
990     c->dk = 0.15;
991     c->in  = DXPt(c->center.x - c->di, c->center.y, c->center.z);
992     c->out = DXPt(c->center.x + c->di, c->center.y, c->center.z);
993 
994     if (c->isattr) {
995 	c->center.x += 0.25;
996 	if (p->vertical)
997 	    c->center.y += (c->dj * np->attrnumber) * ATTRWIDTH;
998 	else
999 	    c->center.y -= (c->dj * np->attrnumber) * ATTRWIDTH;
1000 	c->center.z = 0.0;
1001 
1002 	c->di *= 0.3;
1003 	c->dj *= 0.3;
1004 	c->dk *= 0.3;
1005 	c->in  = DXPt(c->center.x - c->di, c->center.y, c->center.z);
1006 	c->out = DXPt(c->center.x + c->di, c->center.y, c->center.z);
1007     }
1008 
1009     if (p->vertical) {
1010 	float tmp;
1011 
1012 	tmp = -c->center.x; c->center.x = c->center.y; c->center.y = tmp;
1013 	tmp = -c->in.x;     c->in.x = c->in.y;         c->in.y = tmp;
1014 	tmp = -c->out.x;    c->out.x = c->out.y;       c->out.y = tmp;
1015     }
1016 }
1017 
1018 
1019 /* count up the number of nodes in the tree.  whether this is unique
1020  *  objects or not depends on whether shared objects are given new nodes
1021  *  or not.  check the code that calls newnode to check.
1022  */
1023 #if 0
1024 static int numnodes(Node *np)
1025 {
1026     int count = 0;
1027 
1028     nodecount(np, &count);
1029 
1030     return count;
1031 }
1032 #endif
1033 
1034 /* recursive routine for numnodes
1035  */
nodecount(Node * np,int * count)1036 static void nodecount(Node *np, int *count)
1037 {
1038     Node *nextnp;
1039 
1040     for (nextnp = np; nextnp; ) {
1041 
1042 	if (nextnp->child)
1043 	    nodecount(nextnp->child, count);
1044 
1045 	nextnp = nextnp->sibling;
1046 
1047 	(*count)++;
1048     }
1049 
1050     return;
1051 
1052 }
1053 
1054 /* delete all members of the tree, including the shared parent linked lists,
1055  *  and return all the storage.
1056  */
freenodetree(Node * np)1057 static Error freenodetree(Node *np)
1058 {
1059     Node *this_np, *next_np;
1060     Nlist *this_lp, *next_lp;
1061 
1062     for (next_np = np; next_np; ) {
1063 
1064 	if (next_np->attr)
1065 	    freenodetree(next_np->attr);
1066 
1067 	if (next_np->child)
1068 	    freenodetree(next_np->child);
1069 
1070 	this_np = next_np;
1071 	next_np = next_np->sibling;
1072 
1073 	/* free multiple parent linked list if it exists */
1074 	next_lp = this_np->godparent;
1075 	while (next_lp) {
1076 	    DXFree((Pointer)next_lp->this);  /* the node */
1077 	    this_lp = next_lp;
1078 	    next_lp = next_lp->next;
1079 	    DXFree((Pointer)this_lp);        /* the link */
1080 	}
1081 
1082 	DXFree((Pointer)this_np->ptag);
1083 	DXFree((Pointer)this_np->ctag);
1084 
1085 	DXFree((Pointer)this_np);
1086     }
1087 
1088     return OK;
1089 }
1090 
1091 /* initialize policy struct */
setpolicyversion(VisInfo * vi,int version)1092 static Error setpolicyversion(VisInfo *vi, int version)
1093 {
1094     vi->oi.policy.version = version;
1095     return OK;
1096 }
1097 
setpolicyvertical(VisInfo * vi,int vertical)1098 static Error setpolicyvertical(VisInfo *vi, int vertical)
1099 {
1100     vi->oi.policy.vertical = vertical;
1101     return OK;
1102 }
1103 
1104 
1105 #if 0
1106 /* UNUSED */
1107 /* calls the per object routines to add geometry to output */
1108 static Error addConstruct(Node np, OutObjInfo *oo)
1109 {
1110 
1111 }
1112 
1113 /* UNUSED */
1114 /* add the geometry and connect to parent
1115  */
1116 static Error addGeometry(OutObjInfo *oo, Construct child, Construct parent)
1117 {
1118 }
1119 #endif
1120 
1121 
1122 /*
1123  * per object routines: names, geometry
1124  */
1125 
ClassName(Class c)1126 static char *ClassName (Class c)
1127 {
1128     switch(c) {
1129       case CLASS_MIN:            return "min";
1130       case CLASS_OBJECT:         return "object";
1131       case CLASS_PRIVATE:        return "private";
1132       case CLASS_STRING:	 return "string";
1133       case CLASS_FIELD:	       	 return "field";
1134       case CLASS_GROUP:	       	 return "group";
1135       case CLASS_SERIES:         return "series";
1136       case CLASS_COMPOSITEFIELD: return "compositefield";
1137       case CLASS_ARRAY:	       	 return "array";
1138       case CLASS_REGULARARRAY:   return "regulararray";
1139       case CLASS_PATHARRAY:      return "patharray";
1140       case CLASS_PRODUCTARRAY:   return "productarray";
1141       case CLASS_MESHARRAY:      return "mesharray";
1142       case CLASS_XFORM:	       	 return "xform";
1143       case CLASS_SCREEN:	 return "screen";
1144       case CLASS_CLIPPED:	 return "clipped";
1145       case CLASS_CAMERA:	 return "camera";
1146       case CLASS_LIGHT:	       	 return "light";
1147       case CLASS_MAX:            return "max";
1148       case CLASS_DELETED:        return "deleted";
1149       case CLASS_CONSTANTARRAY:  return "constantarray";
1150       case CLASS_MULTIGRID:	 return "multigrid";
1151       default: 			 return "unknown";
1152     }
1153     /* notreached */
1154 }
1155 
1156 #if 0
1157 static char *TypeName (Type t)
1158 {
1159     switch(t) {
1160       case TYPE_UBYTE:		return "ubyte";
1161       case TYPE_BYTE:		return "byte";
1162       case TYPE_USHORT:		return "ushort";
1163       case TYPE_SHORT:		return "short";
1164       case TYPE_UINT:		return "uint";
1165       case TYPE_INT:		return "int";
1166    /* case TYPE_UHYPER:		return "uhyper"; */
1167       case TYPE_HYPER:		return "hyper";
1168       case TYPE_FLOAT:		return "float";
1169       case TYPE_DOUBLE:		return "double";
1170       case TYPE_STRING:		return "string";
1171       default:			return "unknown";
1172     }
1173     /* notreached */
1174 }
1175 
1176 static char *CatName (Category c)
1177 {
1178     switch(c) {
1179       case CATEGORY_REAL:	return "real";
1180       case CATEGORY_COMPLEX:	return "complex";
1181       case CATEGORY_QUATERNION: return "quaternion";
1182       default:			return "unknown";
1183     }
1184     /* notreached */
1185 }
1186 #endif
1187 
geomCount(OutObjInfo * oo,Class class,int isAttr,int isShared)1188 static void geomCount (OutObjInfo *oo, Class class, int isAttr, int isShared)
1189 {
1190     switch (class) {
1191       default:
1192 	oo->totalquads += 6;
1193 	oo->totallines ++;
1194 	break;
1195     }
1196 
1197     return;
1198 }
1199 
1200 enum what { cube, tetra, hex };
1201 
1202 /*
1203  */
drawObject(OutObjInfo * oo,Node * np,Policy * p)1204 static Error drawObject (OutObjInfo *oo, Node *np, Policy *p)
1205 {
1206     Construct *c;
1207     RGBColor color;
1208     enum what w;
1209 
1210     c = &np->where;
1211     switch (c->class) {
1212       case CLASS_GROUP:
1213       case CLASS_SERIES:
1214       case CLASS_COMPOSITEFIELD:
1215       case CLASS_MULTIGRID:
1216 	color = DXRGB(0.1, 0.9, 0.1);
1217 	w = cube;
1218 	break;
1219 
1220       case CLASS_FIELD:
1221 	color = DXRGB(0.9, 0.5, 0.1);
1222 	w = cube;
1223 	break;
1224 
1225       case CLASS_ARRAY:
1226       case CLASS_CONSTANTARRAY:
1227       case CLASS_REGULARARRAY:
1228       case CLASS_PATHARRAY:
1229       case CLASS_PRODUCTARRAY:
1230       case CLASS_MESHARRAY:
1231 	color = DXRGB(0.9, 0.1, 0.1);
1232 	w = cube;
1233 	break;
1234 
1235       case CLASS_STRING:
1236 	color = DXRGB(0.5, 0.5, 0.1);
1237 	w = cube;
1238 	break;
1239 
1240       case CLASS_XFORM:
1241 	color = DXRGB(0.1, 0.5, 0.5);
1242 	w = cube;
1243 	break;
1244 
1245       case CLASS_SCREEN:
1246 	color = DXRGB(0.5, 0.1, 0.5);
1247 	w = cube;
1248 	break;
1249 
1250       case CLASS_LIGHT:
1251 	color = DXRGB(0.9, 0.9, 0.9);
1252 	w = cube;
1253 	break;
1254 
1255       case CLASS_CAMERA:
1256 	color = DXRGB(0.2, 0.2, 0.9);
1257 	w = cube;
1258 	break;
1259 
1260       default:
1261 	color = DXRGB(0.9, 0.1, 0.7);
1262 	w = cube;
1263 	break;
1264     }
1265 
1266     if (c->isshared)
1267 	color = DXRGB(color.r * 0.1, color.g * 0.1, color.b * 0.1);
1268 
1269     switch (w) {
1270       case cube:
1271 	if (!addCube(oo, np, &color))
1272 	    return ERROR;
1273       case tetra:
1274       case hex:
1275       default:
1276 	break;
1277     }
1278 
1279     if (!addLabel(oo->g, oo->font, c, p))
1280 	return ERROR;
1281 
1282     if (np->ptag && !addStringTag (np->ptag, 1, oo->g, oo->font, c, p))
1283 	return ERROR;
1284 
1285     if (np->ctag && !addStringTag (np->ctag, 2, oo->g, oo->font, c, p))
1286 	return ERROR;
1287 
1288     return OK;
1289 }
1290 
1291 #define LABELSIZE  0.7
1292 #define TAGSIZE    0.2
1293 
1294 /* object label
1295  */
addLabel(Group g,Object font,Construct * c,Policy * p)1296 static Error addLabel (Group g, Object font, Construct *c, Policy *p)
1297 {
1298     Xform x;
1299     Matrix m;
1300     Object o;
1301     Vector v;
1302 
1303     v.z = c->center.z;
1304     if (p->vertical) {
1305 	v.x = c->center.x - c->dj;
1306 	v.y = c->center.y + (c->di * 1.10);
1307 	m = DXConcatenate(DXScale(c->dj, c->di, LABELSIZE), DXTranslate(v));
1308     } else {
1309 	v.x = c->center.x - c->di;
1310 	v.y = c->center.y + (c->dj * 1.10);
1311 	m = DXConcatenate(DXScale(c->di, c->dj, LABELSIZE), DXTranslate(v));
1312     }
1313 
1314     o = DXGeometricText(ClassName(c->class), font, NULL);
1315     if (!o)
1316 	return ERROR;
1317 
1318     if (!(x = DXNewXform(o, m)))
1319 	return ERROR;
1320 
1321     if (!DXSetMember(g, NULL, (Object)x))
1322 	return ERROR;
1323 
1324     return OK;
1325 }
1326 
1327 
1328 /* additional string info.  type 1 is from parent, type 2 is from child.
1329  */
addStringTag(char * s,int type,Group g,Object font,Construct * c,Policy * p)1330 static Error addStringTag (char *s, int type, Group g, Object font,
1331 			    Construct *c, Policy *p)
1332 {
1333     Xform x;
1334     Matrix m;
1335     Object o;
1336     Vector v;
1337 
1338     v.z = c->center.z + (c->dk * 1.05);
1339     if (type == 2) {
1340 	if (p->vertical) {
1341 	    v.x = c->center.x - c->dj;
1342 	    v.y = c->center.y - c->di;
1343 	    m = DXConcatenate(DXScale(c->dj, c->di, TAGSIZE), DXTranslate(v));
1344 	} else {
1345 	    v.x = c->center.x - c->di;
1346 	    v.y = c->center.y - c->dj;
1347 	    m = DXConcatenate(DXScale(c->di, c->dj, TAGSIZE), DXTranslate(v));
1348 	}
1349     } else if (type == 1) {
1350 	if (p->vertical) {
1351 	    v.x = c->center.x - c->dj;
1352 	    v.y = c->center.y;
1353 	    m = DXConcatenate(DXScale(c->dj, c->di, TAGSIZE), DXTranslate(v));
1354 	} else {
1355 	    v.x = c->center.x - c->di;
1356 	    v.y = c->center.y;
1357 	    m = DXConcatenate(DXScale(c->di, c->dj, TAGSIZE), DXTranslate(v));
1358 	}
1359     } else {
1360 	DXSetError(ERROR_INTERNAL, "illegal type in addStringTag");
1361 	return ERROR;
1362     }
1363 
1364 
1365     o = DXGeometricText(s, font, NULL);
1366     if (!o)
1367 	return ERROR;
1368 
1369     if (!(x = DXNewXform(o, m)))
1370 	return ERROR;
1371 
1372 #if 0
1373     if (!DXSetFloatAttribute((Object)x, "fuzz", 1.0))
1374 	return ERROR;
1375 #endif
1376 
1377     if (!DXSetMember(g, NULL, (Object)x))
1378 	return ERROR;
1379 
1380     return OK;
1381 }
1382 
1383 
1384 /*
1385  *
1386  * routines which do the major functions.
1387  *
1388  */
1389 
1390 
1391 
1392 /* depth, width and counts of members of object.
1393  */
1394 static
traverse(Object o,VisInfo * vi,Node * parent,int isattr,int num,char * ptag)1395 Error traverse(Object o, VisInfo *vi, Node *parent, int isattr, int num,
1396 	       char *ptag)
1397 {
1398     InObjInfo *oi;
1399     Layout *y;
1400     int count, i;
1401     ulong obj_id;
1402     float pos;
1403     Error rc;
1404     Array terms[MAXRANK];
1405     Class class, subclass;
1406     Object subo, subo1, subo2;
1407     char *name;
1408     uint dup;
1409     Node *l = NULL;
1410     Matrix m;
1411     char cbuf[256];
1412 
1413     oi = &vi->oi;
1414     y = &oi->layout;
1415 
1416     /* if not an attribute, go down a level and start counting members */
1417     if (!isattr) {
1418 	y->level++;
1419 	if (y->level > y->maxlevel)
1420 	    y->maxlevel = y->level;
1421 
1422 	num = y->levelmembers[y->level];
1423 
1424 	y->levelmembers[y->level]++;
1425 	if (y->levelmembers[y->level] > y->maxlevelmembers) {
1426 	    y->maxlevelmembers = y->levelmembers[y->level];
1427 	    y->widestlevel = y->level;
1428 	}
1429     }
1430 
1431     /* check for shared objects
1432      */
1433     if (!FindIDbyObject(oi->ht, o, &obj_id)) {
1434 	rc = ERROR;
1435 	goto done;
1436     }
1437 
1438     /* if obj_id == 0, this is a new object.  if obj_id == anything else, this
1439      *  is a duplicate.
1440      */
1441     dup = (obj_id != 0);
1442 
1443     y->membercount++;
1444     if (!dup)
1445 	y->uniquemembers++;
1446 
1447     class = DXGetObjectClass(o);
1448     switch (class) {
1449       case CLASS_ARRAY:
1450 	subclass = DXGetArrayClass((Array)o);
1451 	break;
1452       case CLASS_GROUP:
1453 	subclass = DXGetGroupClass((Group)o);
1454 	break;
1455       default:
1456 	subclass = class;
1457     }
1458 
1459     l = newnode(y->level, isattr, num, dup, subclass, parent, ptag);
1460     if (!l) {
1461 	rc = ERROR;
1462 	goto done;
1463     }
1464 
1465     if (!oi->root)
1466 	oi->root = l;
1467 
1468     if (!isattr) {
1469 	/* if we aren't already processing the attributes of an object,
1470 	 *  check for attributes.
1471 	 */
1472 	for (i=0; (subo=DXGetEnumeratedAttribute(o, i, &name)); i++)
1473 	    traverse(subo, vi, l, 1, i, name);
1474     }
1475 
1476     switch (class) {
1477       case CLASS_STRING:
1478 	setctag(l, DXGetString((String)o));
1479 	break;
1480 
1481       case CLASS_ARRAY:
1482 	switch (subclass) {
1483 	  case CLASS_ARRAY:
1484 	  case CLASS_PATHARRAY:
1485 	  case CLASS_CONSTANTARRAY:
1486 	  case CLASS_REGULARARRAY:
1487 	    break;
1488 
1489 	  case CLASS_PRODUCTARRAY:
1490 	    DXGetProductArrayInfo((ProductArray)o, &count, terms);
1491 	    for (i=0; i<count; i++) {
1492 		sprintf(cbuf, "term %d", i);
1493 		traverse((Object)terms[i], vi, l, 0, 0, cbuf);
1494 	    }
1495 	    break;
1496 
1497 	  case CLASS_MESHARRAY:
1498 	    DXGetMeshArrayInfo((MeshArray)o, &count, terms);
1499 	    for (i=0; i<count; i++) {
1500 		sprintf(cbuf, "term %d", i);
1501 		traverse((Object)terms[i], vi, l, 0, 0, cbuf);
1502 	    }
1503 
1504 	    break;
1505 
1506 	  default:
1507 	    DXSetError(ERROR_INTERNAL, "unrecognized array subclass");
1508 	    break;
1509 	}
1510 	break;
1511 
1512       case CLASS_FIELD:
1513 	for (i=0;
1514 	     (subo=DXGetEnumeratedComponentValue((Field)o, i, &name)); i++) {
1515 	    traverse(subo, vi, l, 0, 0, name);
1516 	}
1517 
1518 	break;
1519 
1520       case CLASS_LIGHT:
1521 	break;
1522 
1523       case CLASS_CLIPPED:
1524 	DXGetClippedInfo((Clipped)o, &subo1, &subo2);
1525 	traverse(subo1, vi, l, 0, 0, "being clipped");
1526 	traverse(subo2, vi, l, 0, 0, "clipped by");
1527 	break;
1528 
1529       case CLASS_SCREEN:
1530 	DXGetScreenInfo((Screen)o, &subo, NULL, NULL);
1531 	traverse(subo, vi, l, 0, 0, NULL);
1532 	break;
1533 
1534       case CLASS_XFORM:
1535 	DXGetXformInfo((Xform)o, &subo1, &m);
1536 	sprintf(cbuf, "[ [%g %g %g] [%g %g %g] [%g %g %g] ] + [%g %g %g]",
1537 		(double)m.A[0][0], (double)m.A[0][1], (double)m.A[0][2],
1538 		(double)m.A[1][0], (double)m.A[1][1], (double)m.A[1][2],
1539 		(double)m.A[2][0], (double)m.A[2][1], (double)m.A[2][2],
1540 		(double)m.b[0], (double)m.b[1], (double)m.b[2]);
1541 
1542 	setctag(l, cbuf);
1543 	traverse(subo1, vi, l, 0, 0, NULL);
1544 	break;
1545 
1546       case CLASS_CAMERA:
1547 	/* ortho, perspective? */
1548 	break;
1549 
1550       case CLASS_GROUP:
1551 	switch (subclass) {
1552 	  case CLASS_GROUP:
1553 	  case CLASS_MULTIGRID:
1554 	  case CLASS_COMPOSITEFIELD:
1555 	    for (i=0; (subo=DXGetEnumeratedMember((Group)o, i, &name)); i++) {
1556 		if (name)
1557 		    traverse(subo, vi, l, 0, 0, name);
1558 		else {
1559 		    sprintf(cbuf, "member %d", i);
1560 		    traverse(subo, vi, l, 0, 0, cbuf);
1561 		}
1562 	    }
1563 
1564 	    break;
1565 
1566 	  case CLASS_SERIES:
1567 	    for (i=0; (subo=DXGetSeriesMember((Series)o, i, &pos)); i++) {
1568 		sprintf(cbuf, "position %g", pos);
1569 		traverse(subo, vi, l, 0, 0, cbuf);
1570 	    }
1571 
1572 	    break;
1573 
1574 	  default:
1575 	    DXSetError(ERROR_INTERNAL, "unrecognized group subclass");
1576 	    break;
1577 	}
1578 	break;
1579 
1580       default:
1581 	DXSetError(ERROR_INTERNAL, "unrecognized object class");
1582 	rc = ERROR;
1583 	goto done;
1584     }
1585 
1586     if (!dup && !AddIDbyObject(oi->ht, o, y->membercount+1)) {
1587 	rc = ERROR;
1588 	goto done;
1589     }
1590 
1591     rc = OK;
1592 
1593   done:
1594     if (!isattr)
1595 	y->level--;
1596     return rc;
1597 }
1598 
1599 /* decide the screen asthetics.
1600  */
layout(VisInfo * vi)1601 static Error layout(VisInfo *vi)
1602 {
1603     nodeplace(vi->oi.root, &vi->oi.policy, &vi->oi.layout, &vi->oo);
1604 
1605     /* patch this here until i decide how to fix this better.
1606      * there is one fewer line than number of nodes.
1607      */
1608     vi->oo.totallines--;
1609     return OK;
1610 }
1611 
1612 
1613 /* turn the node tree into a renderable thing.
1614  */
makevisual(VisInfo * vi)1615 static Object makevisual(VisInfo *vi)
1616 {
1617     if (!allocoutobj(&vi->oo))
1618 	return NULL;
1619 
1620     if (!nextoutobj(&vi->oo, vi->oi.root, &vi->oi.policy))
1621 	return NULL;
1622 
1623     if (!_dxfNormalsObject((Object)vi->oo.g, "connections"))
1624 	return NULL;
1625 
1626     return (Object) vi->oo.g;
1627 }
1628 
1629 
1630 
1631 /* external entry point
1632  */
m_VisualObject(Object * in,Object * out)1633 Error m_VisualObject(Object *in, Object *out)
1634 {
1635     VisInfo vi;
1636     int olddebug=0;
1637     char *options, *cp;
1638 
1639     out[0] = NULL;
1640 
1641     if (!in[0]) {
1642 	DXSetError(ERROR_BAD_PARAMETER, "#10000", "input");
1643 	return ERROR;
1644     }
1645 
1646 
1647     if (!initVisInfo(&vi))
1648 	goto error;
1649 
1650     olddebug = DXQueryDebug("V");
1651 
1652     if (in[1] && !DXExtractString(in[1], &options)) {
1653 	DXSetError(ERROR_BAD_PARAMETER, "bad options string");
1654 	return ERROR;
1655     }
1656 
1657     if (in[1] && options) {
1658 	for (cp = options; *cp; cp++) {
1659 	    switch (*cp) {
1660 	      case 'd':
1661 		DXEnableDebug("V", 1);
1662 		break;
1663 	      case '0': case '1': case '2': case '3': case '4':
1664 	      case '5': case '6': case '7': case '8': case '9':
1665 		setpolicyversion(&vi, *cp - '0');
1666 		break;
1667 	      case 'h':
1668 		setpolicyvertical(&vi, 0);
1669 		break;
1670 	      case 'v':
1671 		setpolicyvertical(&vi, 1);
1672 		break;
1673 	      case 'm':
1674 		/* every 1000 calls to the memmgr, check to be sure
1675 		 *  things haven't been corrupted.
1676 		 */
1677 		DXTraceAlloc(1000);
1678 		break;
1679 	    }
1680 	}
1681     }
1682 
1683     if (traverse(in[0], &vi, NULL, 0, 0, NULL) == ERROR)
1684 	goto error;
1685 
1686     if (layout(&vi) == ERROR)
1687 	goto error;
1688 
1689     if (!(out[0] = makevisual(&vi)))
1690 	goto error;
1691 
1692 
1693     endVisInfo(&vi);
1694     DXEnableDebug("V", olddebug);
1695     DXTraceAlloc(0);
1696     return OK;
1697 
1698   error:
1699     errdelVisInfo(&vi);
1700     DXEnableDebug("V", olddebug);
1701     DXTraceAlloc(0);
1702     return ERROR;
1703 
1704 }
1705