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