ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/wrapBSDF.c
Revision: 2.16
Committed: Fri May 29 07:45:48 2015 UTC (8 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R0
Changes since 2.15: +21 -3 lines
Log Message:
Fixed issue with missing character type in genBSDF output

File Contents

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