ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/parser.c
Revision: 1.1
Committed: Tue Jun 21 14:45:46 1994 UTC (29 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# Content
1 /* Copyright (c) 1994 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * Parse an MGF file, converting or discarding unsupported entities
9 */
10
11 #include <stdio.h>
12 #include <math.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include "parser.h"
16 #include "lookup.h"
17 #include "messages.h"
18
19 /*
20 * Global definitions of variables declared in parser.h
21 */
22 /* entity names */
23
24 char mg_ename[MG_NENTITIES][MG_MAXELEN] = MG_NAMELIST;
25
26 /* Handler routines for each entity */
27
28 int (*mg_ehand[MG_NENTITIES])();
29
30 /* error messages */
31
32 char *mg_err[MG_NERRS] = MG_ERRLIST;
33
34 MG_FCTXT *mg_file; /* current file context pointer */
35
36 int mg_nqcdivs = MG_NQCD; /* number of divisions per quarter circle */
37
38 /*
39 * The idea with this parser is to compensate for any missing entries in
40 * mg_ehand with alternate handlers that express these entities in terms
41 * of others that the calling program can handle.
42 *
43 * In some cases, no alternate handler is possible because the entity
44 * has no approximate equivalent. These entities are simply discarded.
45 *
46 * Certain entities are dependent on others, and mg_init() will fail
47 * if the supported entities are not consistent.
48 *
49 * Some alternate entity handlers require that earlier entities be
50 * noted in some fashion, and we therefore keep another array of
51 * parallel support handlers to assist in this effort.
52 */
53
54 /* temporary settings for testing */
55 #define e_ies e_any_toss
56 /* alternate handler routines */
57
58 static int e_any_toss(), /* discard unneeded entity */
59 e_ies(); /* IES luminaire file */
60 e_include(), /* include file */
61 e_sph(), /* sphere */
62 e_cyl(), /* cylinder */
63 e_cone(), /* cone */
64 e_ring(), /* ring */
65 e_torus(); /* torus */
66
67 /* alternate handler support functions */
68
69 static int (*e_supp[MG_NENTITIES])();
70
71 static char FLTFMT[] = "%.12g";
72
73 static int warpconends; /* hack for generating good normals */
74
75
76 void
77 mg_init() /* initialize alternate entity handlers */
78 {
79 unsigned long ineed = 0, uneed = 0;
80 register int i;
81 /* pick up slack */
82 if (mg_ehand[MG_E_IES] == NULL)
83 mg_ehand[MG_E_IES] = e_ies;
84 if (mg_ehand[MG_E_INCLUDE] == NULL)
85 mg_ehand[MG_E_INCLUDE] = e_include;
86 if (mg_ehand[MG_E_SPH] == NULL) {
87 mg_ehand[MG_E_SPH] = e_sph;
88 ineed |= 1<<MG_E_POINT|1<<MG_E_VERTEX;
89 } else
90 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
91 if (mg_ehand[MG_E_CYL] == NULL) {
92 mg_ehand[MG_E_CYL] = e_cyl;
93 ineed |= 1<<MG_E_POINT|1<<MG_E_VERTEX;
94 } else
95 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
96 if (mg_ehand[MG_E_CONE] == NULL) {
97 mg_ehand[MG_E_CONE] = e_cone;
98 ineed |= 1<<MG_E_POINT|1<<MG_E_VERTEX;
99 } else
100 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
101 if (mg_ehand[MG_E_RING] == NULL) {
102 mg_ehand[MG_E_RING] = e_ring;
103 ineed |= 1<<MG_E_POINT|1<<MG_E_NORMAL|1<<MG_E_VERTEX;
104 } else
105 uneed |= 1<<MG_E_POINT|1<<MG_E_NORMAL|1<<MG_E_VERTEX|1<<MG_E_XF;
106 if (mg_ehand[MG_E_TORUS] == NULL) {
107 mg_ehand[MG_E_TORUS] = e_torus;
108 ineed |= 1<<MG_E_POINT|1<<MG_E_NORMAL|1<<MG_E_VERTEX;
109 } else
110 uneed |= 1<<MG_E_POINT|1<<MG_E_NORMAL|1<<MG_E_VERTEX|1<<MG_E_XF;
111 /* check for consistency */
112 if (mg_ehand[MG_E_FACE] != NULL)
113 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
114 if (mg_ehand[MG_E_CXY] != NULL)
115 uneed |= 1<<MG_E_COLOR;
116 if (mg_ehand[MG_E_RD] != NULL || mg_ehand[MG_E_TD] != NULL ||
117 mg_ehand[MG_E_ED] != NULL ||
118 mg_ehand[MG_E_RS] != NULL ||
119 mg_ehand[MG_E_TS] != NULL)
120 uneed |= 1<<MG_E_MATERIAL;
121 for (i = 0; i < MG_NENTITIES; i++)
122 if (uneed & 1<<i && mg_ehand[i] == NULL) {
123 fprintf(stderr, "Missing support for \"%s\" entity\n",
124 mg_ename[i]);
125 exit(1);
126 }
127 /* add support as needed */
128 if (ineed & 1<<MG_E_VERTEX && mg_ehand[MG_E_VERTEX] != c_hvertex)
129 e_supp[MG_E_VERTEX] = c_hvertex;
130 if (ineed & 1<<MG_E_POINT && mg_ehand[MG_E_POINT] != c_hvertex)
131 e_supp[MG_E_POINT] = c_hvertex;
132 if (ineed & 1<<MG_E_NORMAL && mg_ehand[MG_E_NORMAL] != c_hvertex)
133 e_supp[MG_E_NORMAL] = c_hvertex;
134 /* discard remaining entities */
135 for (i = 0; i < MG_NENTITIES; i++)
136 if (mg_ehand[i] == NULL)
137 mg_ehand[i] = e_any_toss;
138 }
139
140
141
142 int
143 mg_entity(name) /* get entity number from its name */
144 char *name;
145 {
146 static LUTAB ent_tab; /* entity lookup table */
147 register char *cp;
148
149 if (!ent_tab.tsiz) { /* initialize hash table */
150 if (!lu_init(&ent_tab, MG_NENTITIES))
151 return(-1); /* what to do? */
152 for (cp = mg_ename[MG_NENTITIES-1]; cp >= mg_ename[0];
153 cp -= sizeof(mg_ename[0]))
154 lu_find(&ent_tab, cp)->key = cp;
155 }
156 cp = lu_find(&ent_tab, name)->key;
157 if (cp == NULL)
158 return(-1);
159 return((cp - mg_ename[0])/sizeof(mg_ename[0]));
160 }
161
162
163 static int
164 handle_it(en, ac, av) /* pass entity to appropriate handler */
165 register int en;
166 int ac;
167 char **av;
168 {
169 int rv;
170
171 if (en < 0 && (en = mg_entity(av[0])) < 0)
172 return(MG_EUNK);
173 if (e_supp[en] != NULL) {
174 if ((rv = (*e_supp[en])(ac, av)) != MG_OK)
175 return(rv);
176 }
177 return((*mg_ehand[en])(ac, av));
178 }
179
180
181 int
182 mg_open(ctx, fn) /* open new input file */
183 register MG_FCTXT *ctx;
184 char *fn;
185 {
186 int olen;
187 register char *cp;
188
189 ctx->lineno = 0;
190 if (fn == NULL) {
191 ctx->fname = "<stdin>";
192 ctx->fp = stdin;
193 ctx->prev = mg_file;
194 mg_file = ctx;
195 return(MG_OK);
196 }
197 /* get name relative to this context */
198 if (mg_file != NULL &&
199 (cp = strrchr(mg_file->fname, '/')) != NULL)
200 olen = cp - mg_file->fname + 1;
201 else
202 olen = 0;
203 ctx->fname = (char *)malloc(olen+strlen(fn)+1);
204 if (ctx->fname == NULL)
205 return(MG_EMEM);
206 if (olen)
207 strcpy(ctx->fname, mg_file->fname);
208 strcpy(ctx->fname+olen, fn);
209 ctx->fp = fopen(ctx->fname, "r");
210 if (ctx->fp == NULL) {
211 free((MEM_PTR)ctx->fname);
212 return(MG_ENOFILE);
213 }
214 ctx->prev = mg_file; /* establish new context */
215 mg_file = ctx;
216 return(MG_OK);
217 }
218
219
220 void
221 mg_close() /* close input file */
222 {
223 register MG_FCTXT *ctx = mg_file;
224
225 mg_file = ctx->prev; /* restore enclosing context */
226 if (ctx->fp == stdin)
227 return; /* don't close standard input */
228 fclose(ctx->fp);
229 free((MEM_PTR)ctx->fname);
230 }
231
232
233 int
234 mg_rewind() /* rewind input file */
235 {
236 if (mg_file->lineno == 0)
237 return(MG_OK);
238 if (mg_file->fp == stdin)
239 return(MG_ESEEK); /* cannot seek on standard input */
240 if (fseek(mg_file->fp, 0L, 0) == EOF)
241 return(MG_ESEEK);
242 mg_file->lineno = 0;
243 return(MG_OK);
244 }
245
246
247 int
248 mg_read() /* read next line from file */
249 {
250 register int len = 0;
251
252 do {
253 if (fgets(mg_file->inpline+len,
254 MG_MAXLINE-len, mg_file->fp) == NULL)
255 return(len);
256 mg_file->lineno++;
257 len += strlen(mg_file->inpline+len);
258 if (len > 1 && mg_file->inpline[len-2] == '\\')
259 mg_file->inpline[--len-1] = ' ';
260 } while (mg_file->inpline[len]);
261
262 return(len);
263 }
264
265
266 int
267 mg_parse() /* parse current input line */
268 {
269 char abuf[MG_MAXLINE];
270 char *argv[MG_MAXARGC];
271 int en;
272 register char *cp, **ap;
273
274 strcpy(cp=abuf, mg_file->inpline);
275 ap = argv; /* break into words */
276 for ( ; ; ) {
277 while (isspace(*cp))
278 *cp++ = '\0';
279 if (!*cp)
280 break;
281 if (ap - argv >= MG_MAXARGC-1)
282 return(MG_EARGC);
283 *ap++ = cp;
284 while (*++cp && !isspace(*cp))
285 ;
286 }
287 if (ap == argv)
288 return(MG_OK); /* no words in line */
289 *ap = NULL;
290 /* else handle it */
291 return(handle_it(-1, ap-argv, argv));
292 }
293
294
295 int
296 mg_load(fn) /* load an MGF file */
297 char *fn;
298 {
299 MG_FCTXT cntxt;
300 int rval;
301
302 if ((rval = mg_open(&cntxt, fn)) != MG_OK) {
303 fprintf("%s: %s\n", fn, mg_err[rval]);
304 return(rval);
305 }
306 while (mg_read()) /* parse each line */
307 if ((rval = mg_parse()) != MG_OK) {
308 fprintf(stderr, "%s: %d: %s:\n%s", cntxt.fname,
309 cntxt.lineno, mg_err[rval],
310 cntxt.inpline);
311 break;
312 }
313 mg_close();
314 return(rval);
315 }
316
317
318 void
319 mg_clear() /* clear parser history */
320 {
321 c_clearall(); /* clear context tables */
322 mg_file = NULL; /* reset our context */
323 }
324
325
326 int
327 mg_iterate(ac, av, f) /* iterate on statement */
328 int ac;
329 register char **av;
330 int (*f)();
331 {
332 int niter, rval;
333 register int i, j;
334 char *argv[MG_MAXARGC];
335 char cntbuf[10];
336 /* build partial transformation */
337 for (i = 0; i < ac; i++) {
338 if (av[i][0] == '-' && av[i][1] == 'a' && av[i][2] == '\0')
339 break;
340 argv[i+1] = av[i];
341 }
342 argv[i+1] = NULL;
343 if (i) { /* handle transformation */
344 argv[0] = mg_ename[MG_E_XF];
345 if ((rval = handle_it(MG_E_XF, i+1, argv)) != MG_OK)
346 return(rval);
347 }
348 if (i < ac) { /* run array */
349 if (i+1 >= ac || !isint(av[i+1]))
350 return(MG_ETYPE);
351 niter = atoi(av[i+1]);
352 argv[0] = "-i";
353 argv[1] = cntbuf;
354 for (j = 2; j+i < ac; j++)
355 argv[j] = av[j+i];
356 argv[j] = NULL;
357 for (j = 0; j < niter; j++) {
358 sprintf(cntbuf, "%d", j);
359 if ((rval = mg_iterate(ac-i, argv, f)) != MG_OK)
360 return(rval);
361 }
362 } else if ((rval = (*f)()) != MG_OK) /* else do this instance */
363 return(rval);
364 if (i) { /* reset the transform */
365 argv[0] = mg_ename[MG_E_XF];
366 argv[1] = NULL;
367 (void)handle_it(MG_E_XF, 1, argv);
368 }
369 return(MG_OK);
370 }
371
372
373 /****************************************************************************
374 * The following routines handle unsupported entities
375 */
376
377
378 static int
379 e_any_toss(ac, av) /* discard an unwanted entity */
380 int ac;
381 char **av;
382 {
383 return(MG_OK);
384 }
385
386
387 static int
388 reload_file() /* reload current MGF file */
389 {
390 register int rval;
391
392 if ((rval = mg_rewind()) != MG_OK)
393 return(rval);
394 while (mg_read())
395 if ((rval = mg_parse()) != MG_OK)
396 return(rval);
397 return(MG_OK);
398 }
399
400
401 static int
402 e_include(ac, av) /* include file */
403 int ac;
404 char **av;
405 {
406 MG_FCTXT ictx;
407 int rv;
408
409 if (ac < 2)
410 return(MG_EARGC);
411 if ((rv = mg_open(&ictx, av[1])) != MG_OK)
412 return(rv);
413 if ((rv = mg_iterate(ac-2, av+2, reload_file)) != MG_OK) {
414 fprintf(stderr, "%s: %d: %s:\n%s", ictx.fname,
415 ictx.lineno, mg_err[rv], ictx.inpline);
416 mg_close();
417 return(MG_EINCL);
418 }
419 mg_close();
420 return(MG_OK);
421 }
422
423
424 static void
425 make_axes(u, v, w) /* compute u and v given w (normalized) */
426 FVECT u, v, w;
427 {
428 register int i;
429
430 v[0] = v[1] = v[2] = 0.;
431 for (i = 0; i < 3; i++)
432 if (w[i] < .6 && w[i] > -.6)
433 break;
434 v[i] = 1.;
435 fcross(u, v, w);
436 normalize(u);
437 fcross(v, w, u);
438 }
439
440
441 static int
442 e_sph(ac, av) /* expand a sphere into cones */
443 int ac;
444 char **av;
445 {
446 static char p2x[24], p2y[24], p2z[24], r1[24], r2[24];
447 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_sv1","=","_sv2"};
448 static char *v2ent[4] = {mg_ename[MG_E_VERTEX],"_sv2","="};
449 static char *p2ent[5] = {mg_ename[MG_E_POINT],p2x,p2y,p2z};
450 static char *conent[6] = {mg_ename[MG_E_CONE],"_sv1",r1,"_sv2",r2};
451 register C_VERTEX *cv;
452 register int i;
453 int rval;
454 double rad;
455 double theta;
456
457 if (ac != 3)
458 return(MG_EARGC);
459 if ((cv = c_getvert(av[1])) == NULL)
460 return(MG_EUNDEF);
461 if (!isflt(av[2]))
462 return(MG_ETYPE);
463 rad = atof(av[2]);
464 /* initialize */
465 warpconends = 1;
466 if ((rval = handle_it(MG_E_VERTEX, 3, v2ent)) != MG_OK)
467 return(rval);
468 sprintf(p2x, FLTFMT, cv->p[0]);
469 sprintf(p2y, FLTFMT, cv->p[1]);
470 sprintf(p2z, FLTFMT, cv->p[2]+rad);
471 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
472 return(rval);
473 r2[0] = '0'; r2[1] = '\0';
474 for (i = 1; i <= 2*mg_nqcdivs; i++) {
475 theta = i*(PI/2)/mg_nqcdivs;
476 if ((rval = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
477 return(rval);
478 sprintf(p2z, FLTFMT, cv->p[2]+rad*cos(theta));
479 if ((rval = handle_it(MG_E_VERTEX, 2, v2ent)) != MG_OK)
480 return(rval);
481 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
482 return(rval);
483 strcpy(r1, r2);
484 sprintf(r2, FLTFMT, rad*sin(theta));
485 if ((rval = handle_it(MG_E_CONE, 5, conent)) != MG_OK)
486 return(rval);
487 }
488 warpconends = 0;
489 return(MG_OK);
490 }
491
492
493 static int
494 e_torus(ac, av) /* expand a torus into cones */
495 int ac;
496 char **av;
497 {
498 static char p2[3][24], r1[24], r2[24];
499 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_tv1","=","_tv2"};
500 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_tv2","="};
501 static char *p2ent[5] = {mg_ename[MG_E_POINT],p2[0],p2[1],p2[2]};
502 static char *conent[6] = {mg_ename[MG_E_CONE],"_tv1",r1,"_tv2",r2};
503 register C_VERTEX *cv;
504 register int i, j;
505 int rval;
506 int sgn;
507 double minrad, maxrad, avgrad;
508 double theta;
509
510 if (ac != 4)
511 return(MG_EARGC);
512 if ((cv = c_getvert(av[1])) == NULL)
513 return(MG_EUNDEF);
514 if (cv->n[0]==0. && cv->n[1]==0. && cv->n[2]==0.)
515 return(MG_EILL);
516 if (!isflt(av[2]) || !isflt(av[3]))
517 return(MG_ETYPE);
518 minrad = atof(av[2]);
519 maxrad = atof(av[3]);
520 /* check orientation */
521 if (minrad > 0.)
522 sgn = 1;
523 else if (minrad < 0.)
524 sgn = -1;
525 else if (maxrad > 0.)
526 sgn = 1;
527 else if (maxrad < 0.)
528 sgn = -1;
529 else
530 return(MG_EILL);
531 if (sgn*(maxrad-minrad) <= 0.)
532 return(MG_EILL);
533 /* initialize */
534 warpconends = 1;
535 v2ent[3] = av[1];
536 for (j = 0; j < 3; j++)
537 sprintf(p2[j], FLTFMT, cv->p[j] +
538 .5*sgn*(maxrad-minrad)*cv->n[j]);
539 if ((rval = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
540 return(rval);
541 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
542 return(rval);
543 sprintf(r2, FLTFMT, avgrad=.5*(minrad+maxrad));
544 /* run outer section */
545 for (i = 1; i <= 2*mg_nqcdivs; i++) {
546 theta = i*(PI/2)/mg_nqcdivs;
547 if ((rval = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
548 return(rval);
549 for (j = 0; j < 3; j++)
550 sprintf(p2[j], FLTFMT, cv->p[j] +
551 .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
552 if ((rval = handle_it(MG_E_VERTEX, 2, v2ent)) != MG_OK)
553 return(rval);
554 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
555 return(rval);
556 strcpy(r1, r2);
557 sprintf(r2, FLTFMT, avgrad + .5*(maxrad-minrad)*sin(theta));
558 if ((rval = handle_it(MG_E_CONE, 5, conent)) != MG_OK)
559 return(rval);
560 }
561 /* run inner section */
562 sprintf(r2, FLTFMT, -.5*(minrad+maxrad));
563 for ( ; i <= 4*mg_nqcdivs; i++) {
564 theta = i*(PI/2)/mg_nqcdivs;
565 for (j = 0; j < 3; j++)
566 sprintf(p2[j], FLTFMT, cv->p[j] +
567 .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
568 if ((rval = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
569 return(rval);
570 if ((rval = handle_it(MG_E_VERTEX, 2, v2ent)) != MG_OK)
571 return(rval);
572 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
573 return(rval);
574 strcpy(r1, r2);
575 sprintf(r2, FLTFMT, -avgrad - .5*(maxrad-minrad)*sin(theta));
576 if ((rval = handle_it(MG_E_CONE, 5, conent)) != MG_OK)
577 return(rval);
578 }
579 warpconends = 0;
580 return(MG_OK);
581 }
582
583
584 static int
585 e_cyl(ac, av) /* replace a cylinder with equivalent cone */
586 int ac;
587 char **av;
588 {
589 static char *avnew[6] = {mg_ename[MG_E_CONE]};
590
591 if (ac != 4)
592 return(MG_EARGC);
593 avnew[1] = av[1];
594 avnew[2] = av[2];
595 avnew[3] = av[3];
596 avnew[4] = av[2];
597 return(handle_it(MG_E_CONE, 5, avnew));
598 }
599
600
601 static int
602 e_ring(ac, av) /* turn a ring into polygons */
603 int ac;
604 char **av;
605 {
606 static char p3[3][24], p4[3][24];
607 static char *nzent[5] = {mg_ename[MG_E_NORMAL],"0","0","0"};
608 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_rv1","="};
609 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_rv2","=","_rv3"};
610 static char *v3ent[4] = {mg_ename[MG_E_VERTEX],"_rv3","="};
611 static char *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
612 static char *v4ent[4] = {mg_ename[MG_E_VERTEX],"_rv4","="};
613 static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
614 static char *fent[6] = {mg_ename[MG_E_FACE],"_rv1","_rv2","_rv3","_rv4"};
615 register C_VERTEX *cv;
616 register int i, j;
617 FVECT u, v;
618 double minrad, maxrad;
619 int rv;
620 double theta, d;
621
622 if (ac != 4)
623 return(MG_EARGC);
624 if ((cv = c_getvert(av[1])) == NULL)
625 return(MG_EUNDEF);
626 if (cv->n[0]==0. && cv->n[1]==0. && cv->n[2]==0.)
627 return(MG_EILL);
628 if (!isflt(av[2]) || !isflt(av[3]))
629 return(MG_ETYPE);
630 minrad = atof(av[2]);
631 maxrad = atof(av[3]);
632 if (minrad < 0. || maxrad <= minrad)
633 return(MG_EILL);
634 /* initialize */
635 make_axes(u, v, cv->n);
636 for (j = 0; j < 3; j++)
637 sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*u[j]);
638 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
639 return(rv);
640 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
641 return(rv);
642 if (minrad == 0.) { /* closed */
643 v1ent[3] = av[1];
644 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
645 return(rv);
646 if ((rv = handle_it(MG_E_NORMAL, 4, nzent)) != MG_OK)
647 return(rv);
648 for (i = 1; i <= 4*mg_nqcdivs; i++) {
649 theta = i*(PI/2)/mg_nqcdivs;
650 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
651 return(rv);
652 for (j = 0; j < 3; j++)
653 sprintf(p3[j], FLTFMT, cv->p[j] +
654 maxrad*u[j]*cos(theta) +
655 maxrad*v[j]*sin(theta));
656 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
657 return(rv);
658 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
659 return(rv);
660 if ((rv = handle_it(MG_E_FACE, 4, fent)) != MG_OK)
661 return(rv);
662 }
663 } else { /* open */
664 if ((rv = handle_it(MG_E_VERTEX, 3, v4ent)) != MG_OK)
665 return(rv);
666 for (j = 0; j < 3; j++)
667 sprintf(p4[j], FLTFMT, cv->p[j] + minrad*u[j]);
668 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
669 return(rv);
670 v1ent[3] = "_rv4";
671 for (i = 1; i <= 4*mg_nqcdivs; i++) {
672 theta = i*(PI/2)/mg_nqcdivs;
673 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
674 return(rv);
675 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
676 return(rv);
677 for (j = 0; j < 3; j++) {
678 d = u[j]*cos(theta) + v[j]*sin(theta);
679 sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*d);
680 sprintf(p4[j], FLTFMT, cv->p[j] + minrad*d);
681 }
682 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
683 return(rv);
684 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
685 return(rv);
686 if ((rv = handle_it(MG_E_VERTEX, 3, v4ent)) != MG_OK)
687 return(rv);
688 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
689 return(rv);
690 if ((rv = handle_it(MG_E_FACE, 5, fent)) != MG_OK)
691 return(rv);
692 }
693 }
694 return(MG_OK);
695 }
696
697
698 static int
699 e_cone(ac, av) /* turn a cone into polygons */
700 int ac;
701 char **av;
702 {
703 static char p3[3][24], p4[3][24], n3[3][24], n4[3][24];
704 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_cv1","="};
705 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_cv2","=","_cv3"};
706 static char *v3ent[4] = {mg_ename[MG_E_VERTEX],"_cv3","="};
707 static char *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
708 static char *n3ent[5] = {mg_ename[MG_E_NORMAL],n3[0],n3[1],n3[2]};
709 static char *v4ent[4] = {mg_ename[MG_E_VERTEX],"_cv4","="};
710 static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
711 static char *n4ent[5] = {mg_ename[MG_E_NORMAL],n4[0],n4[1],n4[2]};
712 static char *fent[6] = {mg_ename[MG_E_FACE],"_cv1","_cv2","_cv3","_cv4"};
713 register C_VERTEX *cv1, *cv2;
714 register int i, j;
715 FVECT u, v, w;
716 double rad1, rad2;
717 int sgn;
718 double n1off, n2off;
719 double d;
720 int rv;
721 double theta;
722
723 if (ac != 5)
724 return(MG_EARGC);
725 if ((cv1 = c_getvert(av[1])) == NULL ||
726 (cv2 = c_getvert(av[3])) == NULL)
727 return(MG_EUNDEF);
728 if (!isflt(av[2]) || !isflt(av[4]))
729 return(MG_ETYPE);
730 rad1 = atof(av[2]);
731 rad2 = atof(av[4]);
732 if (rad1 == 0.) {
733 if (rad2 == 0.)
734 return(MG_EILL);
735 } else if (rad2 != 0.) {
736 if (rad1 < 0. ^ rad2 < 0.)
737 return(MG_EILL);
738 } else { /* swap */
739 C_VERTEX *cv;
740
741 cv = cv1;
742 cv1 = cv2;
743 cv2 = cv;
744 d = rad1;
745 rad1 = rad2;
746 rad2 = d;
747 }
748 sgn = rad2 < 0. ? -1 : 1;
749 /* initialize */
750 for (j = 0; j < 3; j++)
751 w[j] = cv1->p[j] - cv2->p[j];
752 if ((d = normalize(w)) == 0.)
753 return(MG_EILL);
754 n1off = n2off = (rad2 - rad1)/d;
755 if (warpconends) /* hack for e_sph and e_torus */
756 n2off = tan(atan(n2off)-(PI/4)/mg_nqcdivs);
757 n2off = sgn*n2off;
758 make_axes(u, v, w);
759 for (j = 0; j < 3; j++) {
760 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*u[j]);
761 sprintf(n3[j], FLTFMT, u[j] + w[j]*n2off);
762 }
763 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
764 return(rv);
765 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
766 return(rv);
767 if ((rv = handle_it(MG_E_NORMAL, 4, n3ent)) != MG_OK)
768 return(rv);
769 if (rad1 == 0.) { /* triangles */
770 v1ent[3] = av[1];
771 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
772 return(rv);
773 for (j = 0; j < 3; j++)
774 sprintf(n4[j], FLTFMT, w[j]);
775 if ((rv = handle_it(MG_E_NORMAL, 4, n4ent)) != MG_OK)
776 return(rv);
777 for (i = 1; i <= 4*mg_nqcdivs; i++) {
778 theta = sgn*i*(PI/2)/mg_nqcdivs;
779 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
780 return(rv);
781 for (j = 0; j < 3; j++) {
782 d = u[j]*cos(theta) + v[j]*sin(theta);
783 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
784 sprintf(n3[j], FLTFMT, d + w[j]*n2off);
785 }
786 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
787 return(rv);
788 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
789 return(rv);
790 if ((rv = handle_it(MG_E_NORMAL, 4, n3ent)) != MG_OK)
791 return(rv);
792 if ((rv = handle_it(MG_E_FACE, 4, fent)) != MG_OK)
793 return(rv);
794 }
795 } else { /* quads */
796 v1ent[3] = "_cv4";
797 if (warpconends) /* hack for e_sph and e_torus */
798 n1off = tan(atan(n1off)+(PI/4)/mg_nqcdivs);
799 n1off = sgn*n1off;
800 for (j = 0; j < 3; j++) {
801 sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*u[j]);
802 sprintf(n4[j], FLTFMT, u[j] + w[j]*n1off);
803 }
804 if ((rv = handle_it(MG_E_VERTEX, 3, v4ent)) != MG_OK)
805 return(rv);
806 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
807 return(rv);
808 if ((rv = handle_it(MG_E_NORMAL, 4, n4ent)) != MG_OK)
809 return(rv);
810 for (i = 1; i <= 4*mg_nqcdivs; i++) {
811 theta = sgn*i*(PI/2)/mg_nqcdivs;
812 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
813 return(rv);
814 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
815 return(rv);
816 for (j = 0; j < 3; j++) {
817 d = u[j]*cos(theta) + v[j]*sin(theta);
818 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
819 sprintf(n3[j], FLTFMT, d + w[j]*n2off);
820 sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*d);
821 sprintf(n4[j], FLTFMT, d + w[j]*n1off);
822 }
823 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
824 return(rv);
825 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
826 return(rv);
827 if ((rv = handle_it(MG_E_NORMAL, 4, n3ent)) != MG_OK)
828 return(rv);
829 if ((rv = handle_it(MG_E_VERTEX, 3, v4ent)) != MG_OK)
830 return(rv);
831 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
832 return(rv);
833 if ((rv = handle_it(MG_E_NORMAL, 4, n4ent)) != MG_OK)
834 return(rv);
835 if ((rv = handle_it(MG_E_FACE, 5, fent)) != MG_OK)
836 return(rv);
837 }
838 }
839 return(MG_OK);
840 }