--- ray/src/cv/ies2rad.c 2018/06/04 18:53:09 2.29 +++ ray/src/cv/ies2rad.c 2021/09/30 20:05:09 2.34 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: ies2rad.c,v 2.29 2018/06/04 18:53:09 greg Exp $"; +static const char RCSid[] = "$Id: ies2rad.c,v 2.34 2021/09/30 20:05:09 greg Exp $"; #endif /* * ies2rad -- Convert IES luminaire data to Radiance description @@ -20,10 +20,9 @@ static const char RCSid[] = "$Id: ies2rad.c,v 2.29 201 * Radiance (θ,φ) luminaire coordinates and then apply photometric and * tilt data to generate Radiance light. θ is altitude from the * negative z-axis and φ is azimuth from the positive x-axis, - * increasing towards the positive y-axis. [??? Greg, is there a - * source for this convention?] This system matches none of the usual - * goniophotometric conventions, but it is closest to IES type C; V in - * type C photometry is θ in Radiance and L is -φ. + * increasing towards the positive y-axis. This system matches none of + * the usual goniophotometric conventions, but it is closest to IES + * type C; V in type C photometry is θ in Radiance and L is -φ. * * The ies2rad scene description for a luminaire LUM, with tilt data, * uses the following Radiance scene description primitives: @@ -70,10 +69,7 @@ static const char RCSid[] = "$Id: ies2rad.c,v 2.29 201 * Extensive comments added by Randolph Fritz May2018 */ -#include -#include #include -#include #include #include "rtio.h" @@ -92,6 +88,9 @@ static const char RCSid[] = "$Id: ies2rad.c,v 2.29 201 /* Since 1991, LM-63 files have begun with the magic keyword IESNA */ #define MAGICID "IESNA" #define LMAGICID 5 +/* But newer files start with IESNA:LM-63- */ +#define MAGICID2 "IESNA:LM-63-" +#define LMAGICID2 12 /* ies2rad supports the 1986, 1991, and 1995 versions of * LM-63. FIRSTREV describes the first version; LASTREV describes the * 1995 version. */ @@ -204,8 +203,8 @@ int filerev = FIRSTREV; #define U_METERS 2 /* string lengths */ -/* Maximum input line is 132 characters including CR LF at end. */ -#define MAXLINE 133 +/* Maximum input line is 256 characters including CR LF at end. */ +#define MAXLINE 257 #define RMAXWORD 76 /* End of LM-63-related #defines */ @@ -224,7 +223,7 @@ int filerev = FIRSTREV; #define DISK 2 #define SPHERE 3 -/* The diameter of a point source luminaire model. Also the minimum +/* 1mm. The diameter of a point source luminaire model. Also the minimum * size (in meters) that the luminous opening of a luminaire must have * to be treated as other than a point source. */ #define MINDIM .001 @@ -725,6 +724,9 @@ k_match( char *hdl /* header line */ ) { + /* Skip leading spaces */ + while (isspace(*hdl)) + hdl++; /* The line has to begin with '[' */ if (*hdl++ != '[') return(0); @@ -840,11 +842,11 @@ ies2rad( /* convert IES file */ continue; /* increment the header line count, and check for the * "TILT=" line that terminates the header */ - if (!lineno++ && strncmp(buf, MAGICID, LMAGICID) == 0) { - /* This code doesn't work for LM-63-95 and - * LM-63-02 files and will instead default to - * LM-63-86. */ - filerev = atoi(buf+LMAGICID); + if (!lineno++) { /* first line may be magic */ + if (!strncmp(buf, MAGICID2, LMAGICID2)) + filerev = atoi(buf+LMAGICID2) - 1900; + else if (!strncmp(buf, MAGICID, LMAGICID)) + filerev = atoi(buf+LMAGICID); if (filerev < FIRSTREV) filerev = FIRSTREV; else if (filerev > LASTREV) @@ -860,7 +862,7 @@ ies2rad( /* convert IES file */ * in the "[LAMP]" and "[LAMPCAT]" keyword lines; * otherwise check all lines. */ if (lampcolor == NULL && checklamp(buf)) - lampcolor = matchlamp( buf[0] == '[' ? + lampcolor = matchlamp(*sskip2(buf,0) == '[' ? keyargs(buf) : buf ); /* Look for a materials and geometry file in the keywords. */ if (keymatch(K_LMG, buf)) { @@ -881,6 +883,7 @@ ies2rad( /* convert IES file */ } else if (lamptype == NULL) fprintf(outfp,"# CIE(x,y) = (%f,%f)\n# Depreciation = %.1f%%\n", lampcolor[3], lampcolor[4], 100.*lampcolor[5]); + /* If the file ended before a "TILT=" line, that's an error. */ if (feof(inpfp)) { fprintf(stderr, "%s: not in IES format\n", inpname); @@ -965,7 +968,7 @@ dotilt( datin = in; strcpy(tltname, dfltname); } else { - /* If the line is "TILE=", use that file + /* If the line is "TILT=", use that file * name as the source of tilt data. */ if (ISDIRSEP(tltspec[0])) strcpy(buf, tltspec); @@ -1122,7 +1125,7 @@ dosource( /* Output distribution "brightdata" primitive. Start handling the various cases of symmetry of the distribution. */ strcat(strcpy(id, filename(name)), "_dist"); - fprintf(out, "\n%s brightdata %s\n", mod, id); + fprintf(out, "\n'%s' brightdata '%s'\n", mod, id); if (nangles[1] < 2) fprintf(out, "4 "); else if (pmtype == PM_B) @@ -1140,7 +1143,7 @@ dosource( dosides = (doupper & dolower && sinf->h > MINDIM); /* Sides */ /* Select the appropriate function and parameters from source.cal */ - fprintf(out, "%s %s source.cal ", + fprintf(out, "%s '%s' source.cal ", sinf->type==SPHERE ? "corr" : !dosides ? "flatcorr" : sinf->type==DISK ? "cylcorr" : "boxcorr", @@ -1210,7 +1213,7 @@ putsource( /* First, describe the light. If a materials and geometry * file is given, generate an illum instead. */ strcat(strcpy(lname, name), "_light"); - fprintf(fp, "\n%s %s %s\n", mod, + fprintf(fp, "\n'%s' %s '%s'\n", mod, shp->isillum ? "illum" : "light", lname); fprintf(fp, "0\n0\n3 %g %g %g\n", lampcolor[0], lampcolor[1], lampcolor[2]); @@ -1246,8 +1249,22 @@ putsource( /* makeshape -- decide what shape will be used * - * makeshape decides what Radiance geometry will be used to represent + * Makeshape decides what Radiance geometry will be used to represent * the light source and stores information about it in shp. + * + * The various versions of the IES LM-63 standard give a "luminous + * opening" (really a crude shape) a width, a length (or depth), and a + * height. If all three values are positive, they describe a box. If + * they are all zero, they describe a point. Various combinations of + * negative values are used to denote disks, circular or elliptical + * cylinders, spheres, and ellipsoids. This encoding differs from + * version to version of LM-63. + * + * Ies2rad simplifies this, reducing the geometry of LM-63 files to + * three forms which can be easily represented by Radiance primitives: + * boxes (RECT), cylinders or disks (DISK), and spheres (SPHERE.) A + * point is necessarily represented by a small sphere, since a point + * is not a Radiance object. */ int makeshape( @@ -1259,24 +1276,28 @@ makeshape( { /* Categorize the shape */ if (illumrad/meters2out >= MINDIM/2.) { - /* If the -i command line option is used, and the - * object is not a point source, output an "illum" - * sphere */ + /* If the -i command line option is used, output an + * "illum" sphere whose radius is given by the + * argument to -i. */ shp->isillum = 1; shp->type = SPHERE; shp->w = shp->l = shp->h = 2.*illumrad / meters2out; + /* Otherwise, use the dimensions in the IES file */ } else if (width < MINDIM) { - /* The width is either zero or negative. */ width = -width; if (width < MINDIM) { - /* The width is zero. Use a tiny sphere to - * represent a point source. */ + /* If the LM-63 width is zero, assume a point + * source is described. Output a small + * sphere. */ shp->type = SPHERE; shp->w = shp->l = shp->h = MINDIM; } else if (height < .5*width) { /* The width is negative and the height is - * modest; output either a disk or a thin - * vertical cylinder. */ + * less than half the width. Treat the + * luminous opening as a disk or short + * vertical cylinder. Disks will be + * represented as nearly flat cylinders of + * MINDIM/2 height. */ shp->type = DISK; shp->w = shp->l = width; if (height >= MINDIM) @@ -1284,14 +1305,13 @@ makeshape( else shp->h = .5*MINDIM; } else { - /* The width is negative and the object is - * tall; output a sphere. */ + /* Treat a tall cylinder as a sphere. */ shp->type = SPHERE; shp->w = shp->l = shp->h = width; } } else { - /* The width is positive. Output a box, possibly very - * thin. */ + /* The width is positive. The luminous opening is a + box or simple rectangle. */ shp->type = RECT; shp->w = width; if (length >= MINDIM) @@ -1405,7 +1425,7 @@ putrect( int d ) { - fprintf(fp, "\n%s polygon %s%s\n0\n0\n12\n", mod, name, suffix); + fprintf(fp, "\n'%s' polygon '%s%s'\n0\n0\n12\n", mod, name, suffix); putpoint(shp, fp, a); putpoint(shp, fp, b); putpoint(shp, fp, c); @@ -1450,13 +1470,13 @@ putdisksrc( /* put out a disk source */ ) { if (up) { - fprintf(fp, "\n%s ring %s.u\n", mod, name); + fprintf(fp, "\n'%s' ring '%s.u'\n", mod, name); fprintf(fp, "0\n0\n8\n"); fprintf(fp, "\t0 0 %g\n", .5*shp->h*meters2out); fprintf(fp, "\t0 0 1\n"); fprintf(fp, "\t0 %g\n", .5*shp->w*meters2out); } else { - fprintf(fp, "\n%s ring %s.d\n", mod, name); + fprintf(fp, "\n'%s' ring '%s.d'\n", mod, name); fprintf(fp, "0\n0\n8\n"); fprintf(fp, "\t0 0 %g\n", -.5*shp->h*meters2out); fprintf(fp, "\t0 0 -1\n"); @@ -1473,7 +1493,7 @@ putcyl( /* put out a cylinder */ char *name ) { - fprintf(fp, "\n%s cylinder %s.c\n", mod, name); + fprintf(fp, "\n'%s' cylinder '%s.c'\n", mod, name); fprintf(fp, "0\n0\n7\n"); fprintf(fp, "\t0 0 %g\n", .5*shp->h*meters2out); fprintf(fp, "\t0 0 %g\n", -.5*shp->h*meters2out); @@ -1490,7 +1510,7 @@ putspheresrc( /* put out a sphere source */ char *name ) { - fprintf(fp, "\n%s sphere %s.s\n", mod, name); + fprintf(fp, "\n'%s' sphere '%s.s'\n", mod, name); fprintf(fp, "0\n0\n4 0 0 0 %g\n", .5*shp->w*meters2out); }