ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/wrapBSDF.c
Revision: 2.2
Committed: Wed Feb 11 19:38:18 2015 UTC (9 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +48 -28 lines
Log Message:
Numerous bug fixes, but still untested

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: wrapBSDF.c,v 2.1 2015/02/11 18:08:10 greg Exp $";
3 #endif
4 /*
5 * Wrap BSDF data in valid WINDOW XML file
6 *
7 * G. Ward February 2015
8 */
9
10 #include <ctype.h>
11 #include "rtio.h"
12 #include "rtprocess.h"
13 #include "ezxml.h"
14 #include "bsdf.h"
15 #include "bsdf_m.h"
16 /* XML template file names */
17 const char def_template[] = "minimalBSDFt.xml";
18 const char win6_template[] = "window6BSDFt.xml";
19
20 const char stdin_name[] = "<stdin>";
21
22 /* input files (can be stdin_name) */
23 const char *xml_input = NULL;
24 /* unit for materials & geometry */
25 const char *attr_unit = "meter";
26 const char legal_units[] = "meter|foot|inch|centimeter|millimeter";
27 /* system materials & geometry */
28 const char *mgf_geometry = NULL;
29
30 /* angle basis */
31 enum { ABdefault=-1, ABklemsFull=0, ABklemsHalf, ABklemsQuarter,
32 ABtensorTree3, ABtensorTree4, ABend };
33
34 int angle_basis = ABdefault;
35
36 /* field IDs and nicknames */
37 struct s_fieldID {
38 char nickName[4];
39 int has_unit;
40 const char *fullName;
41 } XMLfieldID[] = {
42 {"m", 0, "Manufacturer"},
43 {"n", 0, "Name"},
44 {"c", 0, "ThermalConductivity"},
45 {"ef", 0, "EmissivityFront"},
46 {"eb", 0, "EmissivityBack"},
47 {"tir", 0, "TIR"},
48 {"eo", 0, "EffectiveOpennessFraction"},
49 {"t", 1, "Thickness"},
50 {"h", 1, "Height"},
51 {"w", 1, "Width"},
52 {"\0", 0, NULL} /* terminator */
53 };
54 /* field assignments */
55 #define MAXASSIGN 12
56 const char *field_assignment[MAXASSIGN];
57 int nfield_assign = 0;
58 #define FASEP ';'
59
60 /* data file(s) & spectra */
61 enum { DTtransForward, DTtransBackward, DTreflForward, DTreflBackward };
62
63 enum { DSsolar=-1, DSnir=-2, DSxbar31=-3, DSvisible=-4, DSzbar31=-5 };
64
65 #define MAXFILES 20
66
67 struct s_dfile {
68 const char *fname; /* input data file name */
69 short type; /* BSDF data type */
70 short spectrum; /* BSDF sensor spectrum */
71 } data_file[MAXFILES];
72
73 int ndataf = 0; /* number of data files */
74
75 const char *spectr_file[MAXFILES]; /* custom spectral curve input */
76
77 const char top_level_name[] = "WindowElement";
78
79 static char *basis_definition[] = {
80
81 "\t\t<IncidentDataStructure>Columns</IncidentDataStructure>\n"
82 "\t\t<AngleBasis>\n"
83 "\t\t\t<AngleBasisName>LBNL/Klems Full</AngleBasisName>\n"
84 "\t\t</AngleBasis>\n",
85
86 "\t\t<IncidentDataStructure>Columns</IncidentDataStructure>\n"
87 "\t\t<AngleBasis>\n"
88 "\t\t\t<AngleBasisName>LBNL/Klems Half</AngleBasisName>\n"
89 "\t\t</AngleBasis>\n",
90
91 "\t\t<IncidentDataStructure>Columns</IncidentDataStructure>\n"
92 "\t\t<AngleBasis>\n"
93 "\t\t\t<AngleBasisName>LBNL/Klems Quarter</AngleBasisName>\n"
94 "\t\t</AngleBasis>\n",
95
96 "\t\t<IncidentDataStructure>TensorTree3</IncidentDataStructure>\n",
97
98 "\t\t<IncidentDataStructure>TensorTree4</IncidentDataStructure>\n",
99 };
100
101 /* Copy data from file descriptor to stdout and close */
102 static int
103 copy_and_close(int fd)
104 {
105 int ok = 1;
106 char buf[8192];
107 int n;
108
109 if (fd < 0)
110 return 0;
111 while ((n = read(fd, buf, sizeof(buf))) > 0)
112 if (write(fileno(stdout), buf, n) != n) {
113 ok = 0;
114 break;
115 }
116 ok &= (n == 0);
117 close(fd);
118 return ok;
119 }
120
121 /* Allocate and assign string from file or stream */
122 static char *
123 input2str(const char *inpspec)
124 {
125 FILE *fp = NULL;
126 char *str;
127 int len, pos, n;
128
129 if (inpspec == NULL || !*inpspec)
130 return "";
131 if (inpspec == stdin_name) { /* read from stdin */
132 fp = stdin;
133 } else if (inpspec[0] == '!') { /* read from command */
134 fp = popen(inpspec+1, "r");
135 if (fp == NULL) {
136 fprintf(stderr, "Cannot start process '%s'\n",
137 inpspec);
138 return "";
139 }
140 } else { /* else load file */
141 int fd = open(inpspec, O_RDONLY);
142 if (fd < 0) {
143 fprintf(stderr, "%s: cannot open\n", inpspec);
144 return "";
145 }
146 len = lseek(fd, 0L, SEEK_END);
147 if (len < 0) {
148 fprintf(stderr, "%s: seek error\n", inpspec);
149 close(fd);
150 return "";
151 }
152 lseek(fd, 0L, SEEK_SET);
153 str = (char *)malloc(len+1);
154 if (str == NULL) {
155 close(fd);
156 goto memerr;
157 }
158 if (read(fd, str, len) != len) {
159 fprintf(stderr, "%s: read error\n", inpspec);
160 free(str);
161 close(fd);
162 return "";
163 }
164 str[len] = '\0';
165 close(fd);
166 return str;
167 }
168 /* reading from stream */
169 str = (char *)malloc((len=8192)+1);
170 if (str == NULL)
171 goto memerr;
172 pos = 0;
173 while ((n = read(fileno(fp), str+pos, len-pos)) > 0)
174 if ((pos += n) >= len) { /* need more space? */
175 str = (char *)realloc(str, (len += len>>2) + 1);
176 if (str == NULL)
177 goto memerr;
178 }
179 if (n < 0) {
180 fprintf(stderr, "%s: read error\n", inpspec);
181 free(str);
182 str = "";
183 } else { /* tidy up result */
184 str[pos] = '\0';
185 str = (char *)realloc(str, (len=pos)+1);
186 if (str == NULL)
187 goto memerr;
188 }
189 if (inpspec[0] != '!')
190 fclose(fp);
191 else if (pclose(fp))
192 fprintf(stderr, "Error running command '%s'\n", inpspec);
193 return str;
194 memerr:
195 fprintf(stderr, "%s: error allocating memory\n", inpspec);
196 if (fp != NULL)
197 (inpspec[0] == '!') ? pclose(fp) : fclose(fp);
198 return "";
199 }
200
201 /* Make material assignments in field_assignment to XML fields */
202 static int
203 mat_assignments(const char *caller, const char *fn, ezxml_t wtl)
204 {
205 int i;
206
207 if (!nfield_assign)
208 return 1;
209 wtl = ezxml_child(wtl, "Material");
210 if (wtl == NULL) {
211 fprintf(stderr, "%s: missing <Material> tag\n", fn);
212 return 0;
213 }
214 for (i = 0; i < nfield_assign; i++) {
215 const char *fnext = field_assignment[i];
216 for ( ; ; ) {
217 ezxml_t fld;
218 char sbuf[512];
219 int j;
220
221 while (isspace(*fnext))
222 ++fnext;
223 if (!*fnext)
224 break;
225 for (j = 0; (*fnext != '=') & !isspace(*fnext); ) {
226 if (!*fnext | (*fnext == FASEP) |
227 (j >= sizeof(sbuf)-1)) {
228 fprintf(stderr,
229 "%s: bad tag name in assignment '%s'\n",
230 caller, field_assignment[i]);
231 return 0;
232 }
233 sbuf[j++] = *fnext++;
234 }
235 sbuf[j] = '\0'; /* check known field */
236 for (j = 0; XMLfieldID[j].nickName[0]; j++)
237 if (!strcasecmp(sbuf, XMLfieldID[j].nickName) ||
238 !strcasecmp(sbuf, XMLfieldID[j].fullName)) {
239 strcpy(sbuf, XMLfieldID[j].fullName);
240 break;
241 }
242 /* check if tag exists */
243 fld = ezxml_child(wtl, sbuf);
244 if (fld == NULL) { /* otherwise, create one */
245 fprintf(stderr, "%s: warning - adding tag <%s>\n",
246 fn, sbuf);
247 fld = ezxml_add_child_d(wtl, sbuf, strlen(wtl->txt));
248 }
249 if (XMLfieldID[j].has_unit)
250 ezxml_set_attr(fld, "unit", attr_unit);
251 while (isspace(*fnext))
252 ++fnext;
253 if (*fnext++ != '=') {
254 fprintf(stderr,
255 "%s: missing '=' in assignment '%s'\n",
256 caller, field_assignment[i]);
257 return 0;
258 }
259 for (j = 0; *fnext & (*fnext != FASEP); ) {
260 if (j >= sizeof(sbuf)-1) {
261 fprintf(stderr,
262 "%s: field too long in '%s'\n",
263 caller, field_assignment[i]);
264 return 0;
265 }
266 sbuf[j++] = *fnext++;
267 }
268 sbuf[j] = '\0';
269 ezxml_set_txt_d(fld, sbuf);
270 fnext += (*fnext == FASEP);
271 }
272 }
273 return 1; /* no errors */
274 }
275
276 /* Complete angle basis specification */
277 static int
278 finish_angle_basis(ezxml_t ab)
279 {
280 const char *bn = ezxml_txt(ezxml_child(ab, "AngleBasisName"));
281 int i, n = nabases;
282 char buf[32];
283
284 if (!*bn) {
285 fputs("Internal error - missing <AngleBasisName>!\n", stderr);
286 return 0;
287 }
288 while (n-- > 0)
289 if (!strcasecmp(bn, abase_list[n].name))
290 break;
291 if (n < 0) {
292 fprintf(stderr, "Internal error - unknown angle basis '%s'", bn);
293 return 0;
294 }
295 for (i = 0; abase_list[n].lat[i].nphis; i++) {
296 ezxml_t tb, abb = ezxml_add_child(ab, "AngleBasisBlock",
297 strlen(ab->txt));
298 sprintf(buf, "%g", i ?
299 .5*(abase_list[n].lat[i].tmin + abase_list[n].lat[i+1].tmin) :
300 .0);
301 ezxml_set_txt_d(ezxml_add_child(abb,"Theta",strlen(abb->txt)), buf);
302 sprintf(buf, "%d", abase_list[n].lat[i].nphis);
303 ezxml_set_txt_d(ezxml_add_child(abb,"nPhis",strlen(abb->txt)), buf);
304 tb = ezxml_add_child(abb, "ThetaBounds", strlen(abb->txt));
305 sprintf(buf, "%g", abase_list[n].lat[i].tmin);
306 ezxml_set_txt(ezxml_add_child(tb,"LowerTheta",strlen(tb->txt)), buf);
307 sprintf(buf, "%g", abase_list[n].lat[i+1].tmin);
308 ezxml_set_txt(ezxml_add_child(tb,"UpperTheta",strlen(tb->txt)), buf);
309 }
310 return 1;
311 }
312
313 /* Determine our angle basis from current tags */
314 static int
315 determine_angle_basis(const char *fn, ezxml_t wtl)
316 {
317 const char *ids;
318 int i;
319
320 wtl = ezxml_child(wtl, "DataDefinition");
321 if (wtl == NULL)
322 return -1;
323 ids = ezxml_txt(ezxml_child(wtl, "IncidentDataStructure"));
324 if (ids == NULL)
325 return -1;
326 for (i = 0; i < ABend; i++) {
327 ezxml_t parsed = ezxml_parse_str(basis_definition[i],
328 strlen(basis_definition[i]));
329 int match = 0;
330 if (!strcmp(ids, ezxml_txt(ezxml_child(parsed,
331 "IncidentDataStructure")))) {
332 const char *abn0 = ezxml_txt(
333 ezxml_child(ezxml_child(wtl,
334 "AngleBasis"), "AngleBasisName"));
335 const char *abn1 = ezxml_txt(
336 ezxml_child(ezxml_child(parsed,
337 "AngleBasis"), "AngleBasisName"));
338 match = !strcmp(abn0, abn1);
339 }
340 ezxml_free(parsed);
341 if (match)
342 return i;
343 }
344 return -1;
345 }
346
347 /* Write out BSDF data block with surrounding tags */
348 static int
349 writeBSDFblock(const char *caller, struct s_dfile *df)
350 {
351 char *cp;
352
353 puts("\t<WavelengthData>");
354 puts("\t\t<LayerNumber>System</LayerNumber>");
355 switch (df->spectrum) {
356 case DSvisible:
357 puts("\t\t<Wavelength unit=\"Integral\">Visible</Wavelength>");
358 puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
359 puts("\t\t<DetectorSpectrum>ASTM E308 1931 Y.dsp</DetectorSpectrum>");
360 break;
361 case DSxbar31:
362 puts("\t\t<Wavelength unit=\"Integral\">CIE-X</Wavelength>");
363 puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
364 puts("\t\t<DetectorSpectrum>ASTM E308 1931 X.dsp</DetectorSpectrum>");
365 break;
366 case DSzbar31:
367 puts("\t\t<Wavelength unit=\"Integral\">CIE-Z</Wavelength>");
368 puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
369 puts("\t\t<DetectorSpectrum>ASTM E308 1931 Z.dsp</DetectorSpectrum>");
370 break;
371 case DSsolar:
372 puts("\t\t<Wavelength unit=\"Integral\">Solar</Wavelength>");
373 puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
374 puts("\t\t<DetectorSpectrum>None</DetectorSpectrum>");
375 break;
376 case DSnir:
377 puts("\t\t<Wavelength unit=\"Integral\">NIR</Wavelength>");
378 puts("\t\tSourceSpectrum>PLACE_HOLDER</SourceSpectrum>");
379 puts("\t\t<DetectorSpectrum>PLACE_HOLDER</DetectorSpectrum>");
380 break;
381 default:
382 cp = strrchr(spectr_file[df->spectrum], '.');
383 if (cp != NULL)
384 *cp = '\0';
385 printf("\t\t<Wavelength unit=\"Integral\">%s</Wavelength>\n",
386 spectr_file[df->spectrum]);
387 if (cp != NULL)
388 *cp = '.';
389 puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
390 printf("\t\t<DetectorSpectrum>%s</DetectorSpectrum>\n",
391 spectr_file[df->spectrum]);
392 break;
393 }
394 puts("\t\t<WavelengthDataBlock>");
395 fputs("\t\t\t<WavelengthDataDirection>", stdout);
396 switch (df->type) {
397 case DTtransForward:
398 fputs("Transmission Front", stdout);
399 break;
400 case DTtransBackward:
401 fputs("Transmission Back", stdout);
402 break;
403 case DTreflForward:
404 fputs("Reflection Front", stdout);
405 break;
406 case DTreflBackward:
407 fputs("Reflection Back", stdout);
408 break;
409 default:
410 fprintf(stderr, "%s: internal - bad BSDF type (%d)\n", caller, df->type);
411 return 0;
412 }
413 puts("</WavelengthDataDirection>");
414 switch (angle_basis) {
415 case ABklemsFull:
416 puts("\t\t\t<ColumnAngleBasis>LBNL/Klems Full</ColumnAngleBasis>");
417 break;
418 case ABklemsHalf:
419 puts("\t\t\t<ColumnAngleBasis>LBNL/Klems Half</ColumnAngleBasis>");
420 break;
421 case ABklemsQuarter:
422 puts("\t\t\t<ColumnAngleBasis>LBNL/Klems Quarter</ColumnAngleBasis>");
423 break;
424 case ABtensorTree3:
425 case ABtensorTree4:
426 puts("\t\t\t<AngleBasis>LBNL/Shirley-Chiu</AngleBasis>");
427 break;
428 default:
429 fprintf(stderr, "%s: bad angle basis (%d)\n", caller, angle_basis);
430 return 0;
431 }
432 puts("\t\t\t<ScatteringDataType>BTDF</ScatteringDataType>");
433 puts("\t\t\t<ScatteringData>");
434 fflush(stdout);
435 if (df->fname == stdin_name) {
436 copy_and_close(fileno(stdin));
437 } else if (df->fname[0] != '!') {
438 if (!copy_and_close(open(df->fname, O_RDONLY))) {
439 fprintf(stderr, "%s: error reading from '%s'\n",
440 caller, df->fname);
441 return 0;
442 }
443 } else if (system(df->fname+1)) {
444 fprintf(stderr, "%s: error running '%s'\n", caller, df->fname);
445 return 0;
446 }
447 puts("\t\t\t</ScatteringData>");
448 puts("\t\t</WavelengthDataBlock>");
449 puts("\t</WavelengthData>");
450 return 1;
451 }
452
453 /* Write out XML, interpolating BSDF data block(s) */
454 static int
455 writeBSDF(const char *caller, ezxml_t fl)
456 {
457 char *xml = ezxml_toxml(fl); /* store XML in string */
458 int ei, i;
459 /* locate trailer */
460 for (ei = strlen(xml)-strlen("</Layer></Optical></WindowElement>");
461 ei >= 0; ei--)
462 if (!strncmp(xml+ei, "</Layer>", 8))
463 break;
464 if (ei < 0) {
465 fprintf(stderr, "%s: internal - cannot find trailer\n",
466 caller);
467 free(xml);
468 return 0;
469 }
470 fflush(stdout); /* write previous XML info. */
471 if (write(fileno(stdout), xml, ei) != ei) {
472 free(xml);
473 return 0;
474 }
475 for (i = 0; i < ndataf; i++) /* interpolate new data */
476 if (!writeBSDFblock(caller, &data_file[i])) {
477 free(xml);
478 return 0;
479 }
480 fputs(xml+ei, stdout); /* write trailer */
481 free(xml); /* free string */
482 return (fflush(stdout) == 0);
483 }
484
485 /* Insert BSDF data into XML wrapper */
486 static int
487 wrapBSDF(const char *caller)
488 {
489 const char *xml_path = xml_input;
490 ezxml_t fl, wtl;
491 /* load previous XML/template */
492 if (xml_input == stdin_name) {
493 fl = ezxml_parse_fp(stdin);
494 } else if (xml_input[0] == '!') {
495 FILE *pfp = popen(xml_input+1, "r");
496 if (pfp == NULL) {
497 fprintf(stderr, "%s: cannot start process '%s'\n",
498 caller, xml_input);
499 return 0;
500 }
501 fl = ezxml_parse_fp(pfp);
502 if (pclose(pfp)) {
503 fprintf(stderr, "%s: error running '%s'\n",
504 caller, xml_input);
505 return 0;
506 }
507 } else {
508 xml_path = getpath((char *)xml_input, getrlibpath(), R_OK);
509 if (xml_path == NULL) {
510 fprintf(stderr, "%s: cannot find XML file named '%s'\n",
511 caller, xml_input==NULL ? "NULL" : xml_input);
512 return 0;
513 }
514 fl = ezxml_parse_file(xml_path);
515 }
516 if (fl == NULL) {
517 fprintf(stderr, "%s: cannot load XML '%s'\n", caller, xml_path);
518 return 0;
519 }
520 if (ezxml_error(fl)[0]) {
521 fprintf(stderr, "%s: error in XML '%s': %s\n", caller, xml_path,
522 ezxml_error(fl));
523 goto failure;
524 }
525 if (strcmp(ezxml_name(fl), top_level_name)) {
526 fprintf(stderr, "%s: top level in XML '%s' not '%s'\n",
527 caller, xml_path, top_level_name);
528 goto failure;
529 }
530 wtl = ezxml_child(fl, "FileType");
531 if (wtl != NULL && strcmp(ezxml_txt(wtl), "BSDF")) {
532 fprintf(stderr, "%s: wrong FileType in XML '%s' (must be 'BSDF')",
533 caller, xml_path);
534 goto failure;
535 }
536 wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer");
537 if (wtl == NULL) {
538 fprintf(stderr, "%s: no optical layers in XML '%s'",
539 caller, xml_path);
540 goto failure;
541 }
542 /* make material assignments */
543 if (!mat_assignments(caller, xml_path, wtl)) {
544 goto failure;
545 }
546 if (mgf_geometry != NULL) { /* add geometry if specified */
547 ezxml_t geom = ezxml_child(wtl, "Geometry");
548 if (geom == NULL)
549 geom = ezxml_add_child(wtl, "Geometry", 0);
550 ezxml_set_attr(geom, "format", "MGF");
551 geom = ezxml_child(geom, "MGFblock");
552 if (geom == NULL) {
553 geom = ezxml_child(wtl, "Geometry");
554 geom = ezxml_add_child(geom, "MGFblock", strlen(geom->txt));
555 }
556 ezxml_set_attr(geom, "unit", attr_unit);
557 ezxml_set_txt(geom, input2str(mgf_geometry));
558 if (geom->txt[0])
559 ezxml_set_flag(geom, EZXML_TXTM);
560 }
561 /* check basis */
562 if (angle_basis != ABdefault) {
563 ezxml_t ab, dd = ezxml_child(wtl, "DataDefinition");
564 if (dd == NULL) {
565 dd = ezxml_add_child(wtl, "DataDefinition", 0);
566 } else {
567 if (ezxml_child(dd, "DataDefinition") != NULL)
568 fprintf(stderr,
569 "%s: warning - replacing existing <DataDefinition> in '%s'\n",
570 caller, xml_path);
571 while (dd->child != NULL)
572 ezxml_remove(dd->child);
573 }
574 ezxml_insert(ezxml_parse_str(basis_definition[angle_basis],
575 strlen(basis_definition[angle_basis])),
576 dd, 0);
577 if ((ab = ezxml_child(dd, "AngleBasis")) != NULL &&
578 !finish_angle_basis(ab))
579 goto failure;
580 } else if ((angle_basis = determine_angle_basis(xml_path, wtl)) < 0) {
581 fprintf(stderr, "%s: need -a option to set angle basis\n",
582 caller);
583 goto failure;
584 }
585 /* write & add BSDF data blocks */
586 if (!writeBSDF(caller, fl))
587 goto failure;
588 ezxml_free(fl); /* all done */
589 return 1;
590 failure:
591 ezxml_free(fl);
592 return 0;
593 }
594
595 /* Report usage and exit */
596 static void
597 UsageExit(const char *pname)
598 {
599 fputs("Usage: ", stderr);
600 fputs(pname, stderr);
601 fputs(" [-W][-a {kf|kh|kq|t3|t4}][-u unit][-g geom][-f 'x=string;y=string']", stderr);
602 fputs(" [-s spectr][-tb inp][-tf inp][-rb inp][-rf inp]", stderr);
603 fputs(" [input.xml]\n", stderr);
604 exit(1);
605 }
606
607 /* Load XML file and use to wrap BSDF data (or modify fields) */
608 int
609 main(int argc, char *argv[])
610 {
611 int cur_spectrum = DSvisible;
612 int ncust_spec = 0;
613 int used_stdin = 0;
614 int units_set = 0;
615 int i;
616 /* get/check arguments */
617 for (i = 1; i < argc && argv[i][0] == '-'; i++) {
618 switch (argv[i][1]) {
619 case 'W': /* customize for WINDOW 6 output */
620 xml_input = win6_template;
621 continue;
622 case 'f': /* field assignment(s) */
623 if (++i >= argc)
624 UsageExit(argv[0]);
625 if (nfield_assign >= MAXASSIGN) {
626 fprintf(stderr, "%s: too many -f options",
627 argv[0]);
628 return 1;
629 }
630 field_assignment[nfield_assign++] = argv[i];
631 continue;
632 case 'u': /* unit */
633 if (++i >= argc)
634 UsageExit(argv[0]);
635 if (units_set++) {
636 fprintf(stderr, "%s: only one -u option allowed\n",
637 argv[0]);
638 return 1;
639 }
640 if (strstr(legal_units, argv[i]) == NULL) {
641 fprintf(stderr, "%s: -u unit must be one of (%s)\n",
642 argv[0], legal_units);
643 return 1;
644 }
645 attr_unit = argv[i];
646 continue;
647 case 'a': /* angle basis */
648 if (++i >= argc)
649 UsageExit(argv[0]);
650 if (angle_basis != ABdefault) {
651 fprintf(stderr, "%s: only one -a option allowed\n",
652 argv[0]);
653 return 1;
654 }
655 if (!strcasecmp(argv[i], "kf"))
656 angle_basis = ABklemsFull;
657 else if (!strcasecmp(argv[i], "kh"))
658 angle_basis = ABklemsHalf;
659 else if (!strcasecmp(argv[i], "kq"))
660 angle_basis = ABklemsQuarter;
661 else if (!strcasecmp(argv[i], "t3"))
662 angle_basis = ABtensorTree3;
663 else if (!strcasecmp(argv[i], "t4"))
664 angle_basis = ABtensorTree4;
665 else
666 UsageExit(argv[0]);
667 continue;
668 case 't': /* transmission */
669 if (i >= argc-1)
670 UsageExit(argv[0]);
671 if (ndataf >= MAXFILES) {
672 fprintf(stderr, "%s: too many data files\n",
673 argv[0]);
674 return 1;
675 }
676 if (!strcmp(argv[i], "-tf"))
677 data_file[ndataf].type = DTtransForward;
678 else if (!strcmp(argv[i], "-tb"))
679 data_file[ndataf].type = DTtransBackward;
680 else
681 UsageExit(argv[0]);
682 if (!strcmp(argv[++i], "-")) {
683 if (used_stdin++) UsageExit(argv[i]);
684 argv[i] = (char *)stdin_name;
685 }
686 data_file[ndataf].fname = argv[i];
687 data_file[ndataf].spectrum = cur_spectrum;
688 ndataf++;
689 continue;
690 case 'r': /* reflection */
691 if (i >= argc-1)
692 UsageExit(argv[0]);
693 if (ndataf >= MAXFILES) {
694 fprintf(stderr, "%s: too many data files\n",
695 argv[0]);
696 return 1;
697 }
698 if (!strcmp(argv[i], "-rf"))
699 data_file[ndataf].type = DTreflForward;
700 else if (!strcmp(argv[i], "-rb"))
701 data_file[ndataf].type = DTreflBackward;
702 else
703 UsageExit(argv[0]);
704 if (!strcmp(argv[++i], "-")) {
705 if (used_stdin++) UsageExit(argv[i]);
706 argv[i] = (char *)stdin_name;
707 }
708 data_file[ndataf].fname = argv[i];
709 data_file[ndataf++].spectrum = cur_spectrum;
710 continue;
711 case 's': /* spectrum name or input file */
712 if (++i >= argc)
713 UsageExit(argv[0]);
714 if (!strcasecmp(argv[i], "Solar"))
715 cur_spectrum = DSsolar;
716 else if (!strcasecmp(argv[i], "Visible") ||
717 !strcasecmp(argv[i], "CIE-Y"))
718 cur_spectrum = DSvisible;
719 else if (!strcasecmp(argv[i], "CIE-X"))
720 cur_spectrum = DSxbar31;
721 else if (!strcasecmp(argv[i], "CIE-Z"))
722 cur_spectrum = DSzbar31;
723 else if (!strcasecmp(argv[i], "NIR"))
724 cur_spectrum = DSnir;
725 else {
726 if (!strcmp(argv[i], "-")) {
727 fprintf(stderr,
728 "%s: cannot read spectra from stdin",
729 argv[0]);
730 return 1;
731 }
732 cur_spectrum = ncust_spec;
733 spectr_file[ncust_spec++] = argv[i];
734 }
735 continue;
736 case 'g': /* MGF geometry file */
737 if (i >= argc-1)
738 UsageExit(argv[0]);
739 if (mgf_geometry != NULL) {
740 fprintf(stderr, "%s: only one -g option allowed\n",
741 argv[0]);
742 return 1;
743 }
744 if (!strcmp(argv[++i], "-")) {
745 if (used_stdin++) UsageExit(argv[i]);
746 argv[i] = (char *)stdin_name;
747 }
748 mgf_geometry = argv[i];
749 continue;
750 case '\0': /* input XML from stdin */
751 break;
752 default:
753 UsageExit(argv[0]);
754 break;
755 }
756 break;
757 }
758 doneOptions: /* get XML input */
759 if (i >= argc) {
760 if (xml_input == NULL)
761 xml_input = def_template;
762 } else if ((i < argc-1) | (xml_input != NULL)) {
763 fprintf(stderr, "%s: only one XML input allowed\n", argv[0]);
764 UsageExit(argv[0]);
765 } else if (!strcmp(argv[i], "-")) {
766 if (used_stdin++) UsageExit(argv[0]);
767 xml_input = stdin_name;
768 } else {
769 xml_input = argv[i];
770 }
771 if ((xml_input == win6_template) & (angle_basis == ABdefault))
772 angle_basis = ABklemsFull;
773 /* wrap it! */
774 return !wrapBSDF(argv[0]);
775 }