--- ray/src/util/wrapBSDF.c 2015/02/15 17:23:06 2.6 +++ ray/src/util/wrapBSDF.c 2020/10/26 21:12:20 2.26 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: wrapBSDF.c,v 2.6 2015/02/15 17:23:06 greg Exp $"; +static const char RCSid[] = "$Id: wrapBSDF.c,v 2.26 2020/10/26 21:12:20 greg Exp $"; #endif /* * Wrap BSDF data in valid WINDOW XML file @@ -7,9 +7,10 @@ static const char RCSid[] = "$Id: wrapBSDF.c,v 2.6 201 * G. Ward February 2015 */ +#include "platform.h" #include #include "rtio.h" -#include "rtprocess.h" +#include "paths.h" #include "ezxml.h" #include "bsdf.h" #include "bsdf_m.h" @@ -18,7 +19,6 @@ const char def_template[] = "minimalBSDFt.xml"; const char win6_template[] = "WINDOW6BSDFt.xml"; const char stdin_name[] = ""; - /* input files (can be stdin_name) */ const char *xml_input = NULL; /* unit for materials & geometry */ @@ -26,13 +26,23 @@ const char *attr_unit = "meter"; const char legal_units[] = "meter|foot|inch|centimeter|millimeter"; /* system materials & geometry */ const char *mgf_geometry = NULL; - + /* comment list */ +#define MAXCOMM 80 +const char *commlist[MAXCOMM]; +int ncomm = 0; /* angle bases */ enum { ABdefault=-1, ABklemsFull=0, ABklemsHalf, ABklemsQuarter, ABtensorTree3, ABtensorTree4, ABend }; int angle_basis = ABdefault; +int correct_solid_angle = 0; + +const char *klems_basis_name[] = { + "LBNL/Klems Full", + "LBNL/Klems Half", + "LBNL/Klems Quarter", +}; /* field IDs and nicknames */ struct s_fieldID { char nickName[4]; @@ -42,6 +52,7 @@ struct s_fieldID { } XMLfieldID[] = { {"m", 0, 1, "Manufacturer"}, {"n", 0, 1, "Name"}, + {"d", 0, 0, "DeviceType"}, {"c", 0, 0, "ThermalConductivity"}, {"ef", 0, 0, "EmissivityFront"}, {"eb", 0, 0, "EmissivityBack"}, @@ -53,16 +64,23 @@ struct s_fieldID { {"\0", 0, 0, NULL} /* terminator */ }; /* field assignments */ -#define MAXASSIGN 12 +#define MAXASSIGN 16 const char *field_assignment[MAXASSIGN]; int nfield_assign = 0; #define FASEP ';' - /* data file(s) & spectra */ -enum { DTtransForward, DTtransBackward, DTreflForward, DTreflBackward }; +enum { DTransFront, DTransBack, DTreflFront, DTreflBack }; -enum { DSsolar=-1, DSnir=-2, DSxbar31=-3, DSvisible=-4, DSzbar31=-5 }; +static const char component_name[4][20] = { + "Transmission Front", + "Transmission Back", + "Reflection Front", + "Reflection Back" +}; +enum { DSsolar=-1, DSnir=-2, DSxbar31=-3, DSvisible=-4, DSzbar31=-5, + DSuprime=-6, DSvprime=-7 }; + #define MAXFILES 20 struct s_dfile { @@ -73,6 +91,8 @@ struct s_dfile { int ndataf = 0; /* number of data files */ +int unlink_datafiles = 0; /* unlink data files when done */ + const char *spectr_file[MAXFILES]; /* custom spectral curve input */ const char top_level_name[] = "WindowElement"; @@ -109,6 +129,24 @@ static char basis_definition[][256] = { "\t\n", }; +/* Check that the last-added data file is unique */ +static int +check_new_data_file() +{ + int i = ndataf; + + while (i-- > 0) + if ((data_file[i].spectrum == data_file[ndataf].spectrum) & + (data_file[i].type == data_file[ndataf].type)) { + fprintf(stderr, + "%s: warning - ignoring duplicate component %s\n", + data_file[ndataf].fname, + component_name[data_file[i].type]); + return 0; + } + return 1; +} + /* Copy data from file descriptor to stdout and close */ static int copy_and_close(int fd) @@ -154,6 +192,8 @@ input2str(const char *inpspec) fprintf(stderr, "%s: cannot open\n", inpspec); return ""; } +#if !defined(_WIN32) && !defined(_WIN64) + /* XXX somehow broken on Windows */ len = lseek(fd, 0L, SEEK_END); if (len > 0) { lseek(fd, 0L, SEEK_SET); @@ -172,6 +212,7 @@ input2str(const char *inpspec) close(fd); return str; } +#endif fp = fdopen(fd, "r"); /* not a regular file */ } /* reading from stream */ @@ -289,14 +330,12 @@ mat_assignments(const char *caller, const char *fn, ez if (xml_input == win6_template) for (i = 0; XMLfieldID[i].nickName[0]; i++) if (XMLfieldID[i].win_need && - !ezxml_txt(ezxml_child(wtl,XMLfieldID[i].fullName))[0]) { + !ezxml_txt(ezxml_child(wtl,XMLfieldID[i].fullName))[0]) fprintf(stderr, - "%s: missing required '%s' assignment for WINDOW <%s>\n", + "%s: warning - missing '%s' assignment for WINDOW <%s>\n", caller, XMLfieldID[i].nickName, XMLfieldID[i].fullName); - return 0; - } - return 1; /* no errors */ + return 1; } /* Complete angle basis specification */ @@ -378,53 +417,46 @@ determine_angle_basis(const char *fn, ezxml_t wtl) return -1; } -/* Filter Klems angle basis, applying appropriate solid angle correction */ +/* Filter Klems angle basis, factoring out incident projected solid angle */ static int filter_klems_matrix(FILE *fp) { -#define MAX_COLUMNS 145 - float col_corr[MAX_COLUMNS]; - const char *bn; + const char *bn = klems_basis_name[angle_basis]; int i, j, n = nabases; /* get angle basis */ - switch (angle_basis) { - case ABklemsFull: bn = "LBNL/Klems Full"; break; - case ABklemsHalf: bn = "LBNL/Klems Half"; break; - case ABklemsQuarter: bn = "LBNL/Klems Quarter"; break; - default: - return 0; - } while (n-- > 0) if (!strcasecmp(bn, abase_list[n].name)) break; if (n < 0) return 0; - if (abase_list[n].nangles > MAX_COLUMNS) { - fprintf(stderr, "Internal error - too many Klems columns!\n"); - return 0; - } - /* get correction factors */ - for (j = abase_list[n].nangles; j--; ) - col_corr[j] = 1.f / io_getohm(j, &abase_list[n]); /* read/correct/write matrix */ for (i = 0; i < abase_list[n].nangles; i++) { + const double corr = 1./io_getohm(i, &abase_list[n]); for (j = 0; j < abase_list[n].nangles; j++) { double d; if (fscanf(fp, "%lf", &d) != 1) return 0; - printf(" %f", d*col_corr[j]); + if (d < -1e-3) { + fputs("Negative BSDF data!\n", stderr); + return 0; + } + printf(" %.3e", d*corr*(d > 0)); } fputc('\n', stdout); } - return 1; -#undef MAX_COLUMNS + while ((i = getc(fp)) != EOF) + if (!isspace(i)) { + fputs("Unexpected data past EOF\n", stderr); + return 0; + } + return 1; /* all is good */ } /* Write out BSDF data block with surrounding tags */ static int writeBSDFblock(const char *caller, struct s_dfile *df) { - int klems_data = 0; + int correct_klems = correct_solid_angle; char *cp; puts("\t"); @@ -432,27 +464,35 @@ writeBSDFblock(const char *caller, struct s_dfile *df) switch (df->spectrum) { case DSvisible: puts("\t\tVisible"); - puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tASTM E308 1931 Y.dsp"); break; case DSxbar31: puts("\t\tCIE-X"); - puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tASTM E308 1931 X.dsp"); break; case DSzbar31: puts("\t\tCIE-Z"); - puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tASTM E308 1931 Z.dsp"); break; + case DSuprime: + puts("\t\tCIE-u"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); + break; + case DSvprime: + puts("\t\tCIE-v"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); + break; case DSsolar: puts("\t\tSolar"); - puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tNone"); break; case DSnir: puts("\t\tNIR"); - puts("\t\tSourceSpectrum>PLACE_HOLDER"); + puts("\t\tPLACE_HOLDER"); puts("\t\tPLACE_HOLDER"); break; default: @@ -463,46 +503,30 @@ writeBSDFblock(const char *caller, struct s_dfile *df) spectr_file[df->spectrum]); if (cp != NULL) *cp = '.'; - puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp"); + puts("\t\tCIE Illuminant D65 1nm.ssp"); printf("\t\t%s\n", spectr_file[df->spectrum]); break; } puts("\t\t"); fputs("\t\t\t", stdout); - switch (df->type) { - case DTtransForward: - fputs("Transmission Front", stdout); - break; - case DTtransBackward: - fputs("Transmission Back", stdout); - break; - case DTreflForward: - fputs("Reflection Front", stdout); - break; - case DTreflBackward: - fputs("Reflection Back", stdout); - break; - default: - fprintf(stderr, "%s: internal - bad BSDF type (%d)\n", caller, df->type); - return 0; - } + fputs(component_name[df->type], stdout); puts(""); - klems_data = 1; switch (angle_basis) { case ABklemsFull: - puts("\t\t\tLBNL/Klems Full"); - break; case ABklemsHalf: - puts("\t\t\tLBNL/Klems Half"); - break; case ABklemsQuarter: - puts("\t\t\tLBNL/Klems Quarter"); + fputs("\t\t\t", stdout); + fputs(klems_basis_name[angle_basis], stdout); + puts(""); + fputs("\t\t\t", stdout); + fputs(klems_basis_name[angle_basis], stdout); + puts(""); break; case ABtensorTree3: case ABtensorTree4: puts("\t\t\tLBNL/Shirley-Chiu"); - klems_data = 0; + correct_klems = 0; break; default: fprintf(stderr, "%s: bad angle basis (%d)\n", caller, angle_basis); @@ -511,7 +535,7 @@ writeBSDFblock(const char *caller, struct s_dfile *df) puts("\t\t\tBTDF"); puts("\t\t\t"); fflush(stdout); - if (klems_data) { + if (correct_klems) { /* correct Klems matrix data */ FILE *fp = stdin; if (df->fname[0] == '!') fp = popen(df->fname+1, "r"); @@ -569,6 +593,9 @@ writeBSDF(const char *caller, ezxml_t fl) free(xml); return 0; } + puts(""); + for (i = 0; i < ncomm; i++) + printf("\n", commlist[i]); fflush(stdout); /* write previous XML info. */ if (write(fileno(stdout), xml, ei) != ei) { free(xml); @@ -582,7 +609,18 @@ writeBSDF(const char *caller, ezxml_t fl) fputs(xml+ei, stdout); /* write trailer */ free(xml); /* free string */ fputc('\n', stdout); - return (fflush(stdout) == 0); + if (fflush(stdout) != 0) + return 0; + /* unlink data files if req. */ + for (i = ndataf*(unlink_datafiles != 0); i--; ) + if (data_file[i].fname != stdin_name && + data_file[i].fname[0] != '!') + unlink(data_file[i].fname); + if (unlink_datafiles > 1 && mgf_geometry != NULL && + mgf_geometry != stdin_name && + mgf_geometry[0] != '!') + unlink(mgf_geometry); + return 1; } /* Insert BSDF data into XML wrapper */ @@ -700,8 +738,8 @@ UsageExit(const char *pname) { fputs("Usage: ", stderr); fputs(pname, stderr); - fputs(" [-W][-a {kf|kh|kq|t3|t4}][-u unit][-g geom][-f 'x=string;y=string']", stderr); - fputs(" [-s spectr][-tb inp][-tf inp][-rb inp][-rf inp]", stderr); + fputs(" [-W][-c][-a {kf|kh|kq|t3|t4}][-u unit][-g geom][-f 'x=string;y=string']", stderr); + fputs(" [-s spectr][-tb inp][-tf inp][-rb inp][-rf inp][-C comm]", stderr); fputs(" [input.xml]\n", stderr); exit(1); } @@ -746,6 +784,9 @@ main(int argc, char *argv[]) } attr_unit = argv[i]; continue; + case 'U': /* unlink data files when done */ + unlink_datafiles = 1 + (argv[i][2] == 'U'); + continue; case 'a': /* angle basis */ if (++i >= argc) UsageExit(argv[0]); @@ -767,6 +808,22 @@ main(int argc, char *argv[]) else UsageExit(argv[0]); continue; + case 'c': /* correct solid angle */ + correct_solid_angle = 1; + continue; + case 'C': /* comment */ + if (ncomm >= MAXCOMM) { + fprintf(stderr, "%s: too many comments\n", + argv[0]); + return 1; + } + if (strstr(argv[++i], "-->") != NULL) { + fprintf(stderr, "%s: illegal character in comment\n", + argv[0]); + return 1; + } + commlist[ncomm++] = argv[i]; + continue; case 't': /* transmission */ if (i >= argc-1) UsageExit(argv[0]); @@ -776,9 +833,9 @@ main(int argc, char *argv[]) return 1; } if (!strcmp(argv[i], "-tf")) - data_file[ndataf].type = DTtransForward; + data_file[ndataf].type = DTransFront; else if (!strcmp(argv[i], "-tb")) - data_file[ndataf].type = DTtransBackward; + data_file[ndataf].type = DTransBack; else UsageExit(argv[0]); if (!strcmp(argv[++i], "-")) { @@ -787,7 +844,7 @@ main(int argc, char *argv[]) } data_file[ndataf].fname = argv[i]; data_file[ndataf].spectrum = cur_spectrum; - ndataf++; + ndataf += check_new_data_file(); continue; case 'r': /* reflection */ if (i >= argc-1) @@ -798,9 +855,9 @@ main(int argc, char *argv[]) return 1; } if (!strcmp(argv[i], "-rf")) - data_file[ndataf].type = DTreflForward; + data_file[ndataf].type = DTreflFront; else if (!strcmp(argv[i], "-rb")) - data_file[ndataf].type = DTreflBackward; + data_file[ndataf].type = DTreflBack; else UsageExit(argv[0]); if (!strcmp(argv[++i], "-")) { @@ -808,7 +865,8 @@ main(int argc, char *argv[]) argv[i] = (char *)stdin_name; } data_file[ndataf].fname = argv[i]; - data_file[ndataf++].spectrum = cur_spectrum; + data_file[ndataf].spectrum = cur_spectrum; + ndataf += check_new_data_file(); continue; case 's': /* spectrum name or input file */ if (++i >= argc) @@ -822,6 +880,10 @@ main(int argc, char *argv[]) cur_spectrum = DSxbar31; else if (!strcasecmp(argv[i], "CIE-Z")) cur_spectrum = DSzbar31; + else if (!strcasecmp(argv[i], "CIE-u")) + cur_spectrum = DSuprime; + else if (!strcasecmp(argv[i], "CIE-v")) + cur_spectrum = DSvprime; else if (!strcasecmp(argv[i], "NIR")) cur_spectrum = DSnir; else { @@ -857,7 +919,7 @@ main(int argc, char *argv[]) } break; } -doneOptions: /* get XML input */ + /* get XML input */ if (i >= argc) { if (xml_input == NULL) xml_input = def_template; @@ -870,8 +932,6 @@ doneOptions: /* get XML input */ } else { xml_input = argv[i]; } - if ((xml_input == win6_template) & (angle_basis == ABdefault)) - angle_basis = ABklemsFull; /* wrap it! */ return !wrapBSDF(argv[0]); }