ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/parser.c
Revision: 1.4
Committed: Fri Jun 24 09:32:51 1994 UTC (29 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +97 -0 lines
Log Message:
added prism entity and minor changes

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 #define e_cmix e_any_toss
57 #define e_cspec e_any_toss
58 /* alternate handler routines */
59
60 static int e_any_toss(), /* discard unneeded entity */
61 e_ies(), /* IES luminaire file */
62 e_include(), /* include file */
63 e_sph(), /* sphere */
64 e_cmix(), /* color mixtures */
65 e_cspec(); /* color spectra */
66 e_cyl(), /* cylinder */
67 e_cone(), /* cone */
68 e_prism(), /* prism */
69 e_ring(), /* ring */
70 e_torus(); /* torus */
71
72 /* alternate handler support functions */
73
74 static int (*e_supp[MG_NENTITIES])();
75
76 static char FLTFMT[] = "%.12g";
77
78 static int warpconends; /* hack for generating good normals */
79
80
81 void
82 mg_init() /* initialize alternate entity handlers */
83 {
84 unsigned long ineed = 0, uneed = 0;
85 register int i;
86 /* pick up slack */
87 if (mg_ehand[MG_E_IES] == NULL)
88 mg_ehand[MG_E_IES] = e_ies;
89 if (mg_ehand[MG_E_INCLUDE] == NULL)
90 mg_ehand[MG_E_INCLUDE] = e_include;
91 if (mg_ehand[MG_E_SPH] == NULL) {
92 mg_ehand[MG_E_SPH] = e_sph;
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_CYL] == NULL) {
97 mg_ehand[MG_E_CYL] = e_cyl;
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_CONE] == NULL) {
102 mg_ehand[MG_E_CONE] = e_cone;
103 ineed |= 1<<MG_E_POINT|1<<MG_E_VERTEX;
104 } else
105 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
106 if (mg_ehand[MG_E_RING] == NULL) {
107 mg_ehand[MG_E_RING] = e_ring;
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 if (mg_ehand[MG_E_PRISM] == NULL) {
112 mg_ehand[MG_E_PRISM] = e_prism;
113 ineed |= 1<<MG_E_POINT|1<<MG_E_VERTEX;
114 } else
115 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
116 if (mg_ehand[MG_E_TORUS] == NULL) {
117 mg_ehand[MG_E_TORUS] = e_torus;
118 ineed |= 1<<MG_E_POINT|1<<MG_E_NORMAL|1<<MG_E_VERTEX;
119 } else
120 uneed |= 1<<MG_E_POINT|1<<MG_E_NORMAL|1<<MG_E_VERTEX|1<<MG_E_XF;
121 if (mg_ehand[MG_E_COLOR] != NULL) {
122 if (mg_ehand[MG_E_CMIX] == NULL)
123 mg_ehand[MG_E_CMIX] = e_cmix;
124 if (mg_ehand[MG_E_CSPEC] == NULL)
125 mg_ehand[MG_E_CSPEC] = e_cspec;
126 }
127 /* check for consistency */
128 if (mg_ehand[MG_E_FACE] != NULL)
129 uneed |= 1<<MG_E_POINT|1<<MG_E_VERTEX|1<<MG_E_XF;
130 if (mg_ehand[MG_E_CXY] != NULL)
131 uneed |= 1<<MG_E_COLOR;
132 if (mg_ehand[MG_E_RD] != NULL || mg_ehand[MG_E_TD] != NULL ||
133 mg_ehand[MG_E_ED] != NULL ||
134 mg_ehand[MG_E_RS] != NULL ||
135 mg_ehand[MG_E_TS] != NULL)
136 uneed |= 1<<MG_E_MATERIAL;
137 for (i = 0; i < MG_NENTITIES; i++)
138 if (uneed & 1<<i && mg_ehand[i] == NULL) {
139 fprintf(stderr, "Missing support for \"%s\" entity\n",
140 mg_ename[i]);
141 exit(1);
142 }
143 /* add support as needed */
144 if (ineed & 1<<MG_E_VERTEX && mg_ehand[MG_E_VERTEX] != c_hvertex)
145 e_supp[MG_E_VERTEX] = c_hvertex;
146 if (ineed & 1<<MG_E_POINT && mg_ehand[MG_E_POINT] != c_hvertex)
147 e_supp[MG_E_POINT] = c_hvertex;
148 if (ineed & 1<<MG_E_NORMAL && mg_ehand[MG_E_NORMAL] != c_hvertex)
149 e_supp[MG_E_NORMAL] = c_hvertex;
150 /* discard remaining entities */
151 for (i = 0; i < MG_NENTITIES; i++)
152 if (mg_ehand[i] == NULL)
153 mg_ehand[i] = e_any_toss;
154 }
155
156
157
158 int
159 mg_entity(name) /* get entity number from its name */
160 char *name;
161 {
162 static LUTAB ent_tab; /* entity lookup table */
163 register char *cp;
164
165 if (!ent_tab.tsiz) { /* initialize hash table */
166 if (!lu_init(&ent_tab, MG_NENTITIES))
167 return(-1); /* what to do? */
168 for (cp = mg_ename[MG_NENTITIES-1]; cp >= mg_ename[0];
169 cp -= sizeof(mg_ename[0]))
170 lu_find(&ent_tab, cp)->key = cp;
171 }
172 cp = lu_find(&ent_tab, name)->key;
173 if (cp == NULL)
174 return(-1);
175 return((cp - mg_ename[0])/sizeof(mg_ename[0]));
176 }
177
178
179 static int
180 handle_it(en, ac, av) /* pass entity to appropriate handler */
181 register int en;
182 int ac;
183 char **av;
184 {
185 int rv;
186
187 if (en < 0 && (en = mg_entity(av[0])) < 0)
188 return(MG_EUNK);
189 if (e_supp[en] != NULL) {
190 if ((rv = (*e_supp[en])(ac, av)) != MG_OK)
191 return(rv);
192 }
193 return((*mg_ehand[en])(ac, av));
194 }
195
196
197 int
198 mg_open(ctx, fn) /* open new input file */
199 register MG_FCTXT *ctx;
200 char *fn;
201 {
202 int olen;
203 register char *cp;
204
205 ctx->lineno = 0;
206 if (fn == NULL) {
207 ctx->fname = "<stdin>";
208 ctx->fp = stdin;
209 ctx->prev = mg_file;
210 mg_file = ctx;
211 return(MG_OK);
212 }
213 /* get name relative to this context */
214 if (mg_file != NULL &&
215 (cp = strrchr(mg_file->fname, '/')) != NULL)
216 olen = cp - mg_file->fname + 1;
217 else
218 olen = 0;
219 ctx->fname = (char *)malloc(olen+strlen(fn)+1);
220 if (ctx->fname == NULL)
221 return(MG_EMEM);
222 if (olen)
223 strcpy(ctx->fname, mg_file->fname);
224 strcpy(ctx->fname+olen, fn);
225 ctx->fp = fopen(ctx->fname, "r");
226 if (ctx->fp == NULL) {
227 free((MEM_PTR)ctx->fname);
228 return(MG_ENOFILE);
229 }
230 ctx->prev = mg_file; /* establish new context */
231 mg_file = ctx;
232 return(MG_OK);
233 }
234
235
236 void
237 mg_close() /* close input file */
238 {
239 register MG_FCTXT *ctx = mg_file;
240
241 mg_file = ctx->prev; /* restore enclosing context */
242 if (ctx->fp == stdin)
243 return; /* don't close standard input */
244 fclose(ctx->fp);
245 free((MEM_PTR)ctx->fname);
246 }
247
248
249 int
250 mg_rewind() /* rewind input file */
251 {
252 if (mg_file->lineno == 0)
253 return(MG_OK);
254 if (mg_file->fp == stdin)
255 return(MG_ESEEK); /* cannot seek on standard input */
256 if (fseek(mg_file->fp, 0L, 0) == EOF)
257 return(MG_ESEEK);
258 mg_file->lineno = 0;
259 return(MG_OK);
260 }
261
262
263 int
264 mg_read() /* read next line from file */
265 {
266 register int len = 0;
267
268 do {
269 if (fgets(mg_file->inpline+len,
270 MG_MAXLINE-len, mg_file->fp) == NULL)
271 return(len);
272 mg_file->lineno++;
273 len += strlen(mg_file->inpline+len);
274 if (len > 1 && mg_file->inpline[len-2] == '\\')
275 mg_file->inpline[--len-1] = ' ';
276 } while (mg_file->inpline[len]);
277
278 return(len);
279 }
280
281
282 int
283 mg_parse() /* parse current input line */
284 {
285 char abuf[MG_MAXLINE];
286 char *argv[MG_MAXARGC];
287 int en;
288 register char *cp, **ap;
289
290 strcpy(cp=abuf, mg_file->inpline);
291 ap = argv; /* break into words */
292 for ( ; ; ) {
293 while (isspace(*cp))
294 *cp++ = '\0';
295 if (!*cp)
296 break;
297 if (ap - argv >= MG_MAXARGC-1)
298 return(MG_EARGC);
299 *ap++ = cp;
300 while (*++cp && !isspace(*cp))
301 ;
302 }
303 if (ap == argv)
304 return(MG_OK); /* no words in line */
305 *ap = NULL;
306 /* else handle it */
307 return(handle_it(-1, ap-argv, argv));
308 }
309
310
311 int
312 mg_load(fn) /* load an MGF file */
313 char *fn;
314 {
315 MG_FCTXT cntxt;
316 int rval;
317
318 if ((rval = mg_open(&cntxt, fn)) != MG_OK) {
319 fprintf(stderr, "%s: %s\n", fn, mg_err[rval]);
320 return(rval);
321 }
322 while (mg_read()) /* parse each line */
323 if ((rval = mg_parse()) != MG_OK) {
324 fprintf(stderr, "%s: %d: %s:\n%s", cntxt.fname,
325 cntxt.lineno, mg_err[rval],
326 cntxt.inpline);
327 break;
328 }
329 mg_close();
330 return(rval);
331 }
332
333
334 void
335 mg_clear() /* clear parser history */
336 {
337 c_clearall(); /* clear context tables */
338 mg_file = NULL; /* reset our context */
339 }
340
341
342 int
343 mg_iterate(ac, av, f) /* iterate on statement */
344 int ac;
345 register char **av;
346 int (*f)();
347 {
348 int niter, rval;
349 register int i, j;
350 char *argv[MG_MAXARGC];
351 char cntbuf[10];
352 /* build partial transformation */
353 for (i = 0; i < ac; i++) {
354 if (av[i][0] == '-' && av[i][1] == 'a' && av[i][2] == '\0')
355 break;
356 argv[i+1] = av[i];
357 }
358 argv[i+1] = NULL;
359 if (i) { /* handle transformation */
360 argv[0] = mg_ename[MG_E_XF];
361 if ((rval = handle_it(MG_E_XF, i+1, argv)) != MG_OK)
362 return(rval);
363 }
364 if (i < ac) { /* run array */
365 if (i+1 >= ac || !isint(av[i+1]))
366 return(MG_ETYPE);
367 niter = atoi(av[i+1]);
368 argv[0] = mg_ename[MG_E_OBJECT];
369 argv[1] = cntbuf;
370 for (j = 2; j+i < ac; j++)
371 argv[j] = av[j+i];
372 argv[j] = NULL;
373 for (j = 0; j < niter; j++) {
374 sprintf(cntbuf, "%d", j);
375 if ((rval = handle_it(MG_E_OBJECT, 2, argv)) != MG_OK)
376 return(rval);
377 argv[0] = "-i";
378 if ((rval = mg_iterate(ac-i, argv, f)) != MG_OK)
379 return(rval);
380 argv[0] = mg_ename[MG_E_OBJECT];
381 if ((rval = handle_it(MG_E_OBJECT, 1, argv)) != MG_OK)
382 return(rval);
383 }
384 } else if ((rval = (*f)()) != MG_OK) /* else do this instance */
385 return(rval);
386 if (i) { /* reset the transform */
387 argv[0] = mg_ename[MG_E_XF];
388 argv[1] = NULL;
389 (void)handle_it(MG_E_XF, 1, argv);
390 }
391 return(MG_OK);
392 }
393
394
395 /****************************************************************************
396 * The following routines handle unsupported entities
397 */
398
399
400 static int
401 e_any_toss(ac, av) /* discard an unwanted entity */
402 int ac;
403 char **av;
404 {
405 return(MG_OK);
406 }
407
408
409 static int
410 reload_file() /* reload current MGF file */
411 {
412 register int rval;
413
414 if ((rval = mg_rewind()) != MG_OK)
415 return(rval);
416 while (mg_read())
417 if ((rval = mg_parse()) != MG_OK)
418 return(rval);
419 return(MG_OK);
420 }
421
422
423 static int
424 e_include(ac, av) /* include file */
425 int ac;
426 char **av;
427 {
428 MG_FCTXT ictx;
429 int rv;
430
431 if (ac < 2)
432 return(MG_EARGC);
433 if ((rv = mg_open(&ictx, av[1])) != MG_OK)
434 return(rv);
435 if ((rv = mg_iterate(ac-2, av+2, reload_file)) != MG_OK) {
436 fprintf(stderr, "%s: %d: %s:\n%s", ictx.fname,
437 ictx.lineno, mg_err[rv], ictx.inpline);
438 mg_close();
439 return(MG_EINCL);
440 }
441 mg_close();
442 return(MG_OK);
443 }
444
445
446 static void
447 make_axes(u, v, w) /* compute u and v given w (normalized) */
448 FVECT u, v, w;
449 {
450 register int i;
451
452 v[0] = v[1] = v[2] = 0.;
453 for (i = 0; i < 3; i++)
454 if (w[i] < .6 && w[i] > -.6)
455 break;
456 v[i] = 1.;
457 fcross(u, v, w);
458 normalize(u);
459 fcross(v, w, u);
460 }
461
462
463 static int
464 e_sph(ac, av) /* expand a sphere into cones */
465 int ac;
466 char **av;
467 {
468 static char p2x[24], p2y[24], p2z[24], r1[24], r2[24];
469 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_sv1","=","_sv2"};
470 static char *v2ent[4] = {mg_ename[MG_E_VERTEX],"_sv2","="};
471 static char *p2ent[5] = {mg_ename[MG_E_POINT],p2x,p2y,p2z};
472 static char *conent[6] = {mg_ename[MG_E_CONE],"_sv1",r1,"_sv2",r2};
473 register C_VERTEX *cv;
474 register int i;
475 int rval;
476 double rad;
477 double theta;
478
479 if (ac != 3)
480 return(MG_EARGC);
481 if ((cv = c_getvert(av[1])) == NULL)
482 return(MG_EUNDEF);
483 if (!isflt(av[2]))
484 return(MG_ETYPE);
485 rad = atof(av[2]);
486 /* initialize */
487 warpconends = 1;
488 if ((rval = handle_it(MG_E_VERTEX, 3, v2ent)) != MG_OK)
489 return(rval);
490 sprintf(p2x, FLTFMT, cv->p[0]);
491 sprintf(p2y, FLTFMT, cv->p[1]);
492 sprintf(p2z, FLTFMT, cv->p[2]+rad);
493 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
494 return(rval);
495 r2[0] = '0'; r2[1] = '\0';
496 for (i = 1; i <= 2*mg_nqcdivs; i++) {
497 theta = i*(PI/2)/mg_nqcdivs;
498 if ((rval = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
499 return(rval);
500 sprintf(p2z, FLTFMT, cv->p[2]+rad*cos(theta));
501 if ((rval = handle_it(MG_E_VERTEX, 2, v2ent)) != MG_OK)
502 return(rval);
503 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
504 return(rval);
505 strcpy(r1, r2);
506 sprintf(r2, FLTFMT, rad*sin(theta));
507 if ((rval = handle_it(MG_E_CONE, 5, conent)) != MG_OK)
508 return(rval);
509 }
510 warpconends = 0;
511 return(MG_OK);
512 }
513
514
515 static int
516 e_torus(ac, av) /* expand a torus into cones */
517 int ac;
518 char **av;
519 {
520 static char p2[3][24], r1[24], r2[24];
521 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_tv1","=","_tv2"};
522 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_tv2","="};
523 static char *p2ent[5] = {mg_ename[MG_E_POINT],p2[0],p2[1],p2[2]};
524 static char *conent[6] = {mg_ename[MG_E_CONE],"_tv1",r1,"_tv2",r2};
525 register C_VERTEX *cv;
526 register int i, j;
527 int rval;
528 int sgn;
529 double minrad, maxrad, avgrad;
530 double theta;
531
532 if (ac != 4)
533 return(MG_EARGC);
534 if ((cv = c_getvert(av[1])) == NULL)
535 return(MG_EUNDEF);
536 if (is0vect(cv->n))
537 return(MG_EILL);
538 if (!isflt(av[2]) || !isflt(av[3]))
539 return(MG_ETYPE);
540 minrad = atof(av[2]);
541 round0(minrad);
542 maxrad = atof(av[3]);
543 /* check orientation */
544 if (minrad > 0.)
545 sgn = 1;
546 else if (minrad < 0.)
547 sgn = -1;
548 else if (maxrad > 0.)
549 sgn = 1;
550 else if (maxrad < 0.)
551 sgn = -1;
552 else
553 return(MG_EILL);
554 if (sgn*(maxrad-minrad) <= 0.)
555 return(MG_EILL);
556 /* initialize */
557 warpconends = 1;
558 v2ent[3] = av[1];
559 for (j = 0; j < 3; j++)
560 sprintf(p2[j], FLTFMT, cv->p[j] +
561 .5*sgn*(maxrad-minrad)*cv->n[j]);
562 if ((rval = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
563 return(rval);
564 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
565 return(rval);
566 sprintf(r2, FLTFMT, avgrad=.5*(minrad+maxrad));
567 /* run outer section */
568 for (i = 1; i <= 2*mg_nqcdivs; i++) {
569 theta = i*(PI/2)/mg_nqcdivs;
570 if ((rval = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
571 return(rval);
572 for (j = 0; j < 3; j++)
573 sprintf(p2[j], FLTFMT, cv->p[j] +
574 .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
575 if ((rval = handle_it(MG_E_VERTEX, 2, v2ent)) != MG_OK)
576 return(rval);
577 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
578 return(rval);
579 strcpy(r1, r2);
580 sprintf(r2, FLTFMT, avgrad + .5*(maxrad-minrad)*sin(theta));
581 if ((rval = handle_it(MG_E_CONE, 5, conent)) != MG_OK)
582 return(rval);
583 }
584 /* run inner section */
585 sprintf(r2, FLTFMT, -.5*(minrad+maxrad));
586 for ( ; i <= 4*mg_nqcdivs; i++) {
587 theta = i*(PI/2)/mg_nqcdivs;
588 for (j = 0; j < 3; j++)
589 sprintf(p2[j], FLTFMT, cv->p[j] +
590 .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
591 if ((rval = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
592 return(rval);
593 if ((rval = handle_it(MG_E_VERTEX, 2, v2ent)) != MG_OK)
594 return(rval);
595 if ((rval = handle_it(MG_E_POINT, 4, p2ent)) != MG_OK)
596 return(rval);
597 strcpy(r1, r2);
598 sprintf(r2, FLTFMT, -avgrad - .5*(maxrad-minrad)*sin(theta));
599 if ((rval = handle_it(MG_E_CONE, 5, conent)) != MG_OK)
600 return(rval);
601 }
602 warpconends = 0;
603 return(MG_OK);
604 }
605
606
607 static int
608 e_cyl(ac, av) /* replace a cylinder with equivalent cone */
609 int ac;
610 char **av;
611 {
612 static char *avnew[6] = {mg_ename[MG_E_CONE]};
613
614 if (ac != 4)
615 return(MG_EARGC);
616 avnew[1] = av[1];
617 avnew[2] = av[2];
618 avnew[3] = av[3];
619 avnew[4] = av[2];
620 return(handle_it(MG_E_CONE, 5, avnew));
621 }
622
623
624 static int
625 e_ring(ac, av) /* turn a ring into polygons */
626 int ac;
627 char **av;
628 {
629 static char p3[3][24], p4[3][24];
630 static char *nzent[5] = {mg_ename[MG_E_NORMAL],"0","0","0"};
631 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_rv1","="};
632 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_rv2","=","_rv3"};
633 static char *v3ent[4] = {mg_ename[MG_E_VERTEX],"_rv3","="};
634 static char *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
635 static char *v4ent[4] = {mg_ename[MG_E_VERTEX],"_rv4","="};
636 static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
637 static char *fent[6] = {mg_ename[MG_E_FACE],"_rv1","_rv2","_rv3","_rv4"};
638 register C_VERTEX *cv;
639 register int i, j;
640 FVECT u, v;
641 double minrad, maxrad;
642 int rv;
643 double theta, d;
644
645 if (ac != 4)
646 return(MG_EARGC);
647 if ((cv = c_getvert(av[1])) == NULL)
648 return(MG_EUNDEF);
649 if (is0vect(cv->n))
650 return(MG_EILL);
651 if (!isflt(av[2]) || !isflt(av[3]))
652 return(MG_ETYPE);
653 minrad = atof(av[2]);
654 round0(minrad);
655 maxrad = atof(av[3]);
656 if (minrad < 0. || maxrad <= minrad)
657 return(MG_EILL);
658 /* initialize */
659 make_axes(u, v, cv->n);
660 for (j = 0; j < 3; j++)
661 sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*u[j]);
662 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
663 return(rv);
664 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
665 return(rv);
666 if (minrad == 0.) { /* closed */
667 v1ent[3] = av[1];
668 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
669 return(rv);
670 if ((rv = handle_it(MG_E_NORMAL, 4, nzent)) != MG_OK)
671 return(rv);
672 for (i = 1; i <= 4*mg_nqcdivs; i++) {
673 theta = i*(PI/2)/mg_nqcdivs;
674 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
675 return(rv);
676 for (j = 0; j < 3; j++)
677 sprintf(p3[j], FLTFMT, cv->p[j] +
678 maxrad*u[j]*cos(theta) +
679 maxrad*v[j]*sin(theta));
680 if ((rv = handle_it(MG_E_VERTEX, 2, v3ent)) != MG_OK)
681 return(rv);
682 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
683 return(rv);
684 if ((rv = handle_it(MG_E_FACE, 4, fent)) != MG_OK)
685 return(rv);
686 }
687 } else { /* open */
688 if ((rv = handle_it(MG_E_VERTEX, 3, v4ent)) != MG_OK)
689 return(rv);
690 for (j = 0; j < 3; j++)
691 sprintf(p4[j], FLTFMT, cv->p[j] + minrad*u[j]);
692 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
693 return(rv);
694 v1ent[3] = "_rv4";
695 for (i = 1; i <= 4*mg_nqcdivs; i++) {
696 theta = i*(PI/2)/mg_nqcdivs;
697 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
698 return(rv);
699 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
700 return(rv);
701 for (j = 0; j < 3; j++) {
702 d = u[j]*cos(theta) + v[j]*sin(theta);
703 sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*d);
704 sprintf(p4[j], FLTFMT, cv->p[j] + minrad*d);
705 }
706 if ((rv = handle_it(MG_E_VERTEX, 2, v3ent)) != MG_OK)
707 return(rv);
708 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
709 return(rv);
710 if ((rv = handle_it(MG_E_VERTEX, 2, v4ent)) != MG_OK)
711 return(rv);
712 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
713 return(rv);
714 if ((rv = handle_it(MG_E_FACE, 5, fent)) != MG_OK)
715 return(rv);
716 }
717 }
718 return(MG_OK);
719 }
720
721
722 static int
723 e_cone(ac, av) /* turn a cone into polygons */
724 int ac;
725 char **av;
726 {
727 static char p3[3][24], p4[3][24], n3[3][24], n4[3][24];
728 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_cv1","="};
729 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_cv2","=","_cv3"};
730 static char *v3ent[4] = {mg_ename[MG_E_VERTEX],"_cv3","="};
731 static char *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
732 static char *n3ent[5] = {mg_ename[MG_E_NORMAL],n3[0],n3[1],n3[2]};
733 static char *v4ent[4] = {mg_ename[MG_E_VERTEX],"_cv4","="};
734 static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
735 static char *n4ent[5] = {mg_ename[MG_E_NORMAL],n4[0],n4[1],n4[2]};
736 static char *fent[6] = {mg_ename[MG_E_FACE],"_cv1","_cv2","_cv3","_cv4"};
737 register C_VERTEX *cv1, *cv2;
738 register int i, j;
739 FVECT u, v, w;
740 double rad1, rad2;
741 int sgn;
742 double n1off, n2off;
743 double d;
744 int rv;
745 double theta;
746
747 if (ac != 5)
748 return(MG_EARGC);
749 if ((cv1 = c_getvert(av[1])) == NULL ||
750 (cv2 = c_getvert(av[3])) == NULL)
751 return(MG_EUNDEF);
752 if (!isflt(av[2]) || !isflt(av[4]))
753 return(MG_ETYPE);
754 rad1 = atof(av[2]);
755 round0(rad1);
756 rad2 = atof(av[4]);
757 round0(rad2);
758 if (rad1 == 0.) {
759 if (rad2 == 0.)
760 return(MG_EILL);
761 } else if (rad2 != 0.) {
762 if (rad1 < 0. ^ rad2 < 0.)
763 return(MG_EILL);
764 } else { /* swap */
765 C_VERTEX *cv;
766
767 cv = cv1;
768 cv1 = cv2;
769 cv2 = cv;
770 d = rad1;
771 rad1 = rad2;
772 rad2 = d;
773 }
774 sgn = rad2 < 0. ? -1 : 1;
775 /* initialize */
776 for (j = 0; j < 3; j++)
777 w[j] = cv1->p[j] - cv2->p[j];
778 if ((d = normalize(w)) == 0.)
779 return(MG_EILL);
780 n1off = n2off = (rad2 - rad1)/d;
781 if (warpconends) { /* hack for e_sph and e_torus */
782 d = atan(n2off) - (PI/4)/mg_nqcdivs;
783 if (d <= -PI/2+FTINY)
784 n2off = -FHUGE;
785 else
786 n2off = tan(d);
787 }
788 make_axes(u, v, w);
789 for (j = 0; j < 3; j++) {
790 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*u[j]);
791 if (n2off <= -FHUGE)
792 sprintf(n3[j], FLTFMT, -w[j]);
793 else
794 sprintf(n3[j], FLTFMT, u[j] + w[j]*n2off);
795 }
796 if ((rv = handle_it(MG_E_VERTEX, 3, v3ent)) != MG_OK)
797 return(rv);
798 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
799 return(rv);
800 if ((rv = handle_it(MG_E_NORMAL, 4, n3ent)) != MG_OK)
801 return(rv);
802 if (rad1 == 0.) { /* triangles */
803 v1ent[3] = av[1];
804 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
805 return(rv);
806 for (j = 0; j < 3; j++)
807 sprintf(n4[j], FLTFMT, w[j]);
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, v2ent)) != MG_OK)
813 return(rv);
814 for (j = 0; j < 3; j++) {
815 d = u[j]*cos(theta) + v[j]*sin(theta);
816 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
817 if (n2off > -FHUGE)
818 sprintf(n3[j], FLTFMT, d + w[j]*n2off);
819 }
820 if ((rv = handle_it(MG_E_VERTEX, 2, v3ent)) != MG_OK)
821 return(rv);
822 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
823 return(rv);
824 if (n2off > -FHUGE &&
825 (rv = handle_it(MG_E_NORMAL, 4, n3ent)) != MG_OK)
826 return(rv);
827 if ((rv = handle_it(MG_E_FACE, 4, fent)) != MG_OK)
828 return(rv);
829 }
830 } else { /* quads */
831 v1ent[3] = "_cv4";
832 if (warpconends) { /* hack for e_sph and e_torus */
833 d = atan(n1off) + (PI/4)/mg_nqcdivs;
834 if (d >= PI/2-FTINY)
835 n1off = FHUGE;
836 else
837 n1off = tan(atan(n1off)+(PI/4)/mg_nqcdivs);
838 }
839 for (j = 0; j < 3; j++) {
840 sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*u[j]);
841 if (n1off >= FHUGE)
842 sprintf(n4[j], FLTFMT, w[j]);
843 else
844 sprintf(n4[j], FLTFMT, u[j] + w[j]*n1off);
845 }
846 if ((rv = handle_it(MG_E_VERTEX, 3, v4ent)) != MG_OK)
847 return(rv);
848 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
849 return(rv);
850 if ((rv = handle_it(MG_E_NORMAL, 4, n4ent)) != MG_OK)
851 return(rv);
852 for (i = 1; i <= 4*mg_nqcdivs; i++) {
853 theta = sgn*i*(PI/2)/mg_nqcdivs;
854 if ((rv = handle_it(MG_E_VERTEX, 4, v1ent)) != MG_OK)
855 return(rv);
856 if ((rv = handle_it(MG_E_VERTEX, 4, v2ent)) != MG_OK)
857 return(rv);
858 for (j = 0; j < 3; j++) {
859 d = u[j]*cos(theta) + v[j]*sin(theta);
860 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
861 if (n2off > -FHUGE)
862 sprintf(n3[j], FLTFMT, d + w[j]*n2off);
863 sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*d);
864 if (n1off < FHUGE)
865 sprintf(n4[j], FLTFMT, d + w[j]*n1off);
866 }
867 if ((rv = handle_it(MG_E_VERTEX, 2, v3ent)) != MG_OK)
868 return(rv);
869 if ((rv = handle_it(MG_E_POINT, 4, p3ent)) != MG_OK)
870 return(rv);
871 if (n2off > -FHUGE &&
872 (rv = handle_it(MG_E_NORMAL, 4, n3ent)) != MG_OK)
873 return(rv);
874 if ((rv = handle_it(MG_E_VERTEX, 2, v4ent)) != MG_OK)
875 return(rv);
876 if ((rv = handle_it(MG_E_POINT, 4, p4ent)) != MG_OK)
877 return(rv);
878 if (n1off < FHUGE &&
879 (rv = handle_it(MG_E_NORMAL, 4, n4ent)) != MG_OK)
880 return(rv);
881 if ((rv = handle_it(MG_E_FACE, 5, fent)) != MG_OK)
882 return(rv);
883 }
884 }
885 return(MG_OK);
886 }
887
888
889 static int
890 e_prism(ac, av) /* turn a prism into polygons */
891 int ac;
892 char **av;
893 {
894 static char p[3][24];
895 static char *vent[4] = {mg_ename[MG_E_VERTEX],NULL,"="};
896 static char *pent[5] = {mg_ename[MG_E_POINT],p[0],p[1],p[2]};
897 char *newav[MG_MAXARGC], nvn[MG_MAXARGC-1][8];
898 double length;
899 FVECT v1, v2, v3, norm;
900 register C_VERTEX *cv;
901 C_VERTEX *cv0;
902 int rv;
903 register int i, j;
904
905 if (ac < 5)
906 return(MG_EARGC);
907 if (!isflt(av[1]))
908 return(MG_ETYPE);
909 length = atof(av[1]);
910 if (length <= FTINY && length >= -FTINY)
911 return(MG_EILL);
912 /* do bottom face */
913 newav[0] = mg_ename[MG_E_FACE];
914 for (i = 1; i < ac-1; i++)
915 newav[i] = av[i+1];
916 newav[i] = NULL;
917 if ((rv = handle_it(MG_E_FACE, i, newav)) != MG_OK)
918 return(rv);
919 /* compute face normal */
920 if ((cv0 = c_getvert(av[2])) == NULL)
921 return(MG_EUNDEF);
922 norm[0] = norm[1] = norm[2] = 0.;
923 v1[0] = v1[1] = v1[2] = 0.;
924 for (i = 2; i < ac-1; i++) {
925 if ((cv = c_getvert(av[i+1])) == NULL)
926 return(MG_EUNDEF);
927 v2[0] = cv->p[0] - cv0->p[0];
928 v2[1] = cv->p[1] - cv0->p[1];
929 v2[2] = cv->p[2] - cv0->p[2];
930 fcross(v3, v1, v2);
931 norm[0] += v3[0];
932 norm[1] += v3[1];
933 norm[2] += v3[2];
934 VCOPY(v1, v2);
935 }
936 if (normalize(norm) == 0.)
937 return(MG_EILL);
938 /* create moved vertices */
939 for (i = 1; i < ac-1; i++) {
940 sprintf(nvn[i-1], "_pv%d", i);
941 vent[1] = nvn[i-1];
942 if ((rv = handle_it(MG_E_VERTEX, 3, vent)) != MG_OK)
943 return(rv);
944 cv = c_getvert(av[i+1]); /* checked above */
945 for (j = 0; j < 3; j++)
946 sprintf(p[j], FLTFMT, cv->p[j] - length*norm[j]);
947 if ((rv = handle_it(MG_E_POINT, 4, pent)) != MG_OK)
948 return(rv);
949 newav[ac-1-i] = nvn[i-1]; /* reverse */
950 }
951 /* do top face */
952 if ((rv = handle_it(MG_E_FACE, ac-1, newav)) != MG_OK)
953 return(rv);
954 /* do the side faces */
955 newav[5] = NULL;
956 newav[3] = av[ac-1];
957 newav[4] = nvn[ac-3];
958 for (i = 1; i < ac-1; i++) {
959 newav[1] = nvn[i-1];
960 newav[2] = av[i+1];
961 if ((rv = handle_it(MG_E_FACE, 5, newav)) != MG_OK)
962 return(rv);
963 newav[3] = newav[2];
964 newav[4] = newav[1];
965 }
966 return(MG_OK);
967 }