ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/parser.c
Revision: 1.14
Committed: Fri Mar 10 15:16:07 1995 UTC (29 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1 -1 lines
Log Message:
reduced significant digits in spectrum output

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