--- ray/src/cv/ies2rad.c 2018/05/30 22:12:17 2.28 +++ ray/src/cv/ies2rad.c 2021/09/20 02:00:05 2.33 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: ies2rad.c,v 2.28 2018/05/30 22:12:17 greg Exp $"; +static const char RCSid[] = "$Id: ies2rad.c,v 2.33 2021/09/20 02:00:05 greg Exp $"; #endif /* * ies2rad -- Convert IES luminaire data to Radiance description @@ -20,10 +20,9 @@ static const char RCSid[] = "$Id: ies2rad.c,v 2.28 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.28 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.28 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); @@ -735,7 +737,7 @@ k_match( /* If we have come to the end of the keyword, and the keyword * at the beginning of the matched line is terminated with * ']', return 1 */ - return((!*kwd) & (*hdl == ']')); + return(!kwd[-1] & (*hdl == ']')); } /* keyargs - return the argument of a keyword, without leading spaces @@ -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); @@ -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)