ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/ies2rad.c
(Generate patch)

Comparing ray/src/cv/ies2rad.c (file contents):
Revision 2.7 by greg, Mon Apr 5 16:40:07 1993 UTC vs.
Revision 2.31 by greg, Tue Jun 5 16:04:00 2018 UTC

# Line 1 | Line 1
1 /* Copyright (c) 1992 Regents of the University of California */
2
1   #ifndef lint
2 < static char SCCSid[] = "$SunId$ LBL";
2 > static const char       RCSid[] = "$Id$";
3   #endif
6
4   /*
5 < * Convert IES luminaire data to Radiance description
5 > * ies2rad -- Convert IES luminaire data to Radiance description
6   *
7 + * ies2rad converts an IES LM-63 luminare description to a Radiance
8 + * luminaire description.  In addition, ies2rad manages a local
9 + * database of Radiance luminaire files.
10 + *
11 + * Ies2rad generates two or three files for each luminaire. For a
12 + * luminaire named LUM, ies2rad will generate LUM.rad, a Radiance
13 + * scene description file which describes the light source, LUM.dat,
14 + * which contains the photometric data from the IES LM-63 file, and
15 + * (if tilt data is provided) LUM%.dat, which contains the tilt data
16 + * from the IES file.
17 + *
18 + * Ies2rad is supported by the Radiance function files source.cal and
19 + * tilt.cal, which transform the coordinates in the IES data into
20 + * Radiance (θ,φ) luminaire coordinates and then apply photometric and
21 + * tilt data to generate Radiance light. θ is altitude from the
22 + * negative z-axis and φ is azimuth from the positive x-axis,
23 + * increasing towards the positive y-axis. This system matches none of
24 + * the usual goniophotometric conventions, but it is closest to IES
25 + * type C; V in type C photometry is θ in Radiance and L is -φ.
26 + *
27 + * The ies2rad scene description for a luminaire LUM, with tilt data,
28 + * uses the following Radiance scene description primitives:
29 + *
30 + *     void brightdata LUM_tilt
31 + *     …
32 + *     LUM_tilt brightdata LUM_dist
33 + *     …
34 + *     LUM_dist light LUM_light
35 + *     …
36 + *     LUM_light surface1 name1
37 + *     …
38 + *     LUM_light surface2 name2
39 + *     …
40 + *     LUM_light surface_n name_n
41 + *
42 + * Without tilt data, the primitives are:
43 + *
44 + *     void brightdata LUM_dist
45 + *     …
46 + *     LUM_dist light LUM_light
47 + *     …
48 + *     LUM_light surface1 name1
49 + *     …
50 + *     LUM_light surface2 name2
51 + *     …
52 + *     LUM_light surface_n name_n
53 + *
54 + * As many surfaces are given as required to describe the light
55 + * source. Illum may be used rather than light so that a visible form
56 + * (impostor) may be given to the luminaire, rather than a simple
57 + * glowing shape. If an impostor is provided, it must be wholly
58 + * contained within the illum and if it provides impostor light
59 + * sources, those must be given with glow, so that they do not
60 + * themselves illuminate the scene, providing incorrect results.
61 + *
62 + * The ies2rad code uses the "bsd" style. For emacs, this is set up
63 + * automatically in the "Local Variables" section at the end of the
64 + * file. For vim, use ":set tabstop=8 shiftwidth=8".
65 + *
66   *      07Apr90         Greg Ward
67 + *
68 + *  Fixed correction factor for flat sources 29Oct2001 GW
69 + *  Extensive comments added by Randolph Fritz May2018
70   */
71  
72   #include <stdio.h>
73 + #include <string.h>
74 + #include <math.h>
75 + #include <sys/types.h>
76   #include <ctype.h>
77 +
78 + #include "rtio.h"
79   #include "color.h"
80   #include "paths.h"
81  
82   #define PI              3.14159265358979323846
83 <                                        /* floating comparisons */
83 >
84 > /* floating comparisons -- floating point numbers within FTINY of each
85 > * other are considered equal */
86   #define FTINY           1e-6
87   #define FEQ(a,b)        ((a)<=(b)+FTINY&&(a)>=(b)-FTINY)
88 <                                        /* tilt specs */
88 >
89 >
90 > /* IESNA LM-63 keywords and constants */
91 > /* Since 1991, LM-63 files have begun with the magic keyword IESNA */
92 > #define MAGICID         "IESNA"
93 > #define LMAGICID        5
94 > /* But newer files start with IESNA:LM-63- */
95 > #define MAGICID2        "IESNA:LM-63-"
96 > #define LMAGICID2       12
97 > /* ies2rad supports the 1986, 1991, and 1995 versions of
98 > * LM-63. FIRSTREV describes the first version; LASTREV describes the
99 > * 1995 version. */
100 > #define FIRSTREV        86
101 > #define LASTREV         95
102 >
103 > /* The following definitions support LM-63 file keyword reading and
104 > * analysis.
105 > *
106 > * This section defines two function-like macros: keymatch(i,s), which
107 > * checks to see if keyword i matches string s, and checklamp(s),
108 > * which checks to see if a string matches the keywords "LAMP" or
109 > * "LAMPCAT".
110 > *
111 > * LM-63-1986 files begin with a list of free-form label lines.
112 > * LM-63-1991 files begin with the identifying line "IESNA91" followed
113 > * by a list of formatted keywords.  LM-63-1995 files begin with the
114 > * identifying line "IESNA:LM-63-1995" followed by a list of formatted
115 > * keywords.
116 > *
117 > * The K_* #defines enumerate the keywords used in the different
118 > * versions of the file and give them symbolic names.
119 > *
120 > * The D86, D91, and D95 #defines validate the keywords in the 1986,
121 > * 1991, and 1995 versions of the standard, one bit per keyword.
122 > * Since the 1986 standard does not use keywords, D86 is zero.  The
123 > * 1991 standard has 13 keywords, and D91 has the lower 13 bits set.
124 > * The 1995 standard has 14 keywords, and D95 has the lower 14 bits
125 > * set.
126 > *
127 > */
128 > #define D86             0
129 >
130 > #define K_TST           0
131 > #define K_MAN           1
132 > #define K_LMC           2
133 > #define K_LMN           3
134 > #define K_LPC           4
135 > #define K_LMP           5
136 > #define K_BAL           6
137 > #define K_MTC           7
138 > #define K_OTH           8
139 > #define K_SCH           9
140 > #define K_MOR           10
141 > #define K_BLK           11
142 > #define K_EBK           12
143 >
144 > /* keywords defined in LM-63-1991 */
145 > #define D91             ((1L<<13)-1)
146 >
147 > #define K_LMG           13
148 >
149 > /* keywords defined in LM-63-1995 */
150 > #define D95             ((1L<<14)-1)
151 >
152 > char    k_kwd[][20] = {"TEST", "MANUFAC", "LUMCAT", "LUMINAIRE", "LAMPCAT",
153 >                        "LAMP", "BALLAST", "MAINTCAT", "OTHER", "SEARCH",
154 >                        "MORE", "BLOCK", "ENDBLOCK", "LUMINOUSGEOMETRY"};
155 >
156 > long k_defined[] = {D86, D86, D86, D86, D86, D91, D91, D91, D91, D95};
157 >
158 > int     filerev = FIRSTREV;
159 >
160 > #define keymatch(i,s)   (k_defined[filerev-FIRSTREV]&1L<<(i) &&\
161 >                                k_match(k_kwd[i],s))
162 >
163 > #define checklamp(s)    (!(k_defined[filerev-FIRSTREV]&(1<<K_LMP|1<<K_LPC)) ||\
164 >                                keymatch(K_LMP,s) || keymatch(K_LPC,s))
165 >
166 > /* tilt specs
167 > *
168 > * This next series of definitions address metal-halide lamps, which
169 > * change their brightness depending on the angle at which they are
170 > * mounted. The section begins with "TILT=".  The constants in this
171 > * section are all defined in LM-63.
172 > *
173 > */
174 >
175   #define TLTSTR          "TILT="
176   #define TLTSTRLEN       5
177   #define TLTNONE         "NONE"
# Line 27 | Line 179 | static char SCCSid[] = "$SunId$ LBL";
179   #define TLT_VERT        1
180   #define TLT_H0          2
181   #define TLT_H90         3
182 <                                        /* photometric types */
182 >
183 > /* Constants from LM-63 files */
184 >
185 > /* photometric types
186 > *
187 > * This enumeration reflects three different methods of measuring the
188 > * distribution of light from a luminaire -- "goniophotometry" -- and
189 > * the different coordinate systems related to these
190 > * goniophotometers.  All are described in IES standard LM-75-01.
191 > * Earlier and shorter descriptions may be found the LM-63 standards
192 > * from 1986, 1991, and 1995.
193 > *
194 > * ies2rad does not support type A photometry.
195 > *
196 > * In the 1986 file format, LM-63-86, 1 is used for type C and type A
197 > * photometric data.
198 > *
199 > */
200   #define PM_C            1
201   #define PM_B            2
202 <                                        /* unit types */
202 > #define PM_A            3
203 >
204 > /* unit types */
205   #define U_FEET          1
206   #define U_METERS        2
207 <                                        /* string lengths */
208 < #define MAXLINE         132
209 < #define MAXWORD         76
210 <                                        /* file types */
207 >
208 > /* string lengths */
209 > /* Maximum input line is 256 characters including CR LF at end. */
210 > #define MAXLINE         257
211 > #define RMAXWORD        76
212 >
213 > /* End of LM-63-related #defines */
214 >
215 > /* file extensions */
216   #define T_RAD           ".rad"
217   #define T_DST           ".dat"
218 < #define T_TLT           "+.dat"
219 <                                        /* shape types */
218 > #define T_TLT           "%.dat"
219 > #define T_OCT           ".oct"
220 >
221 > /* shape types
222 > * These #defines enumerate the shapes of the Radiance objects which
223 > * emit the light.
224 > */
225   #define RECT            1
226   #define DISK            2
227   #define SPHERE          3
228  
229 < #define MINDIM          .001            /* minimum dimension (point source) */
229 > /* The diameter of a point source luminaire model. Also the minimum
230 > * size (in meters) that the luminous opening of a luminaire must have
231 > * to be treated as other than a point source. */
232 > #define MINDIM          .001
233  
234 < #define F_M             .3048           /* feet to meters */
234 > /* feet to meters */
235 > /* length_in_meters = length_in_feet * F_M */
236 > #define F_M             .3048
237  
238 + /* abspath - return true if a path begins with a directory separator
239 + * or a '.' (current directory) */
240   #define abspath(p)      (ISDIRSEP((p)[0]) || (p)[0] == '.')
241  
242 + /* Global variables.
243 + *
244 + * Mostly, these are a way of communicating command line parameters to
245 + * the rest of the program.
246 + */
247   static char     default_name[] = "default";
248  
249   char    *libdir = NULL;                 /* library directory location */
# Line 64 | Line 257 | float  defcolor[3] = {1.,1.,1.};       /* default lamp color
257   float   *lampcolor = defcolor;          /* pointer to current lamp color */
258   double  multiplier = 1.0;               /* multiplier for all light sources */
259   char    units[64] = "meters";           /* output units */
260 + int     out2stdout = 0;                 /* put out to stdout r.t. file */
261 + int     instantiate = 0;                /* instantiate geometry */
262   double  illumrad = 0.0;                 /* radius for illum sphere */
263  
264 + /* This struct describes the Radiance source object */
265   typedef struct {
266 +        int     isillum;                        /* do as illum */
267          int     type;                           /* RECT, DISK, SPHERE */
268 +        double  mult;                           /* candela multiplier */
269          double  w, l, h;                        /* width, length, height */
270          double  area;                           /* max. projected area */
271 < } SHAPE;                                /* a source shape */
271 > } SRCINFO;                              /* a source shape (units=meters) */
272  
273 < int     gargc;                          /* global argc (minus filenames) */
273 > /* A count and pointer to the list of input file names */
274 > int     gargc;                          /* global argc */
275   char    **gargv;                        /* global argv */
276  
277 < extern char     *strcpy(), *strcat(), *stradd(), *tailtrunc(), *filetrunc(),
278 <                *filename(), *libname(), *fullname(), *malloc(),
279 <                *getword(), *atos();
280 < extern float    *matchlamp();
281 <
277 > /* macros to scan numbers out of IES files
278 > *
279 > * fp is a file pointer.  scnint() places the number in the integer
280 > * indicated by ip; scnflt() places the number in the double indicated
281 > * by rp. The macros return 1 if successful, 0 if not.
282 > *
283 > */
284   #define scnint(fp,ip)   cvtint(ip,getword(fp))
285   #define scnflt(fp,rp)   cvtflt(rp,getword(fp))
85 #define isint           isflt                   /* IES allows real as integer */
286  
287 + /* The original (1986) version of LM-63 allows decimals points in
288 + * integers, so that, for instance, the number of lamps may be written
289 + * 3.0 (the number, obviously, must still be an integer.) This
290 + * confusing define accommodates that.  */
291 + #define isint           isflt
292  
293 < main(argc, argv)
294 < int     argc;
295 < char    *argv[];
293 > /* Function declarations */
294 > static int ies2rad(char *inpname, char *outname);
295 > static void initlamps(void);
296 > static int dosource(SRCINFO *sinf, FILE *in, FILE *out, char *mod, char *name);
297 > static int dotilt(FILE *in, FILE *out, char *dir, char *tltspec,
298 >                char *dfltname, char *tltid);
299 > static int cvgeometry(char *inpname, SRCINFO *sinf, char *outname, FILE *outfp);
300 > static int cvtint(int *ip, char *wrd);
301 > static int cvdata(FILE *in, FILE *out, int ndim, int npts[], double mult,
302 >                double lim[][2]);
303 > static int cvtflt(double *rp, char *wrd);
304 > static int makeshape(SRCINFO *shp, double width, double length, double height);
305 > static int putsource(SRCINFO *shp, FILE *fp, char *mod, char *name,
306 >                int dolower, int doupper, int dosides);
307 > static void putrectsrc(SRCINFO *shp, FILE *fp, char *mod, char *name, int up);
308 > static void putsides(SRCINFO *shp, FILE *fp, char *mod, char *name);
309 > static void putdisksrc(SRCINFO *shp, FILE *fp, char *mod, char *name, int up);
310 > static void putspheresrc(SRCINFO *shp, FILE *fp, char *mod, char *name);
311 > static void putrect(SRCINFO *shp, FILE *fp, char *mod, char *name, char *suffix,
312 >                int a, int b, int c, int d);
313 > static void putpoint(SRCINFO *shp, FILE *fp, int p);
314 > static void putcyl(SRCINFO *shp, FILE *fp, char *mod, char *name);
315 > static char * tailtrunc(char *name);
316 > static char * filename(char *path);
317 > static char * libname(char *path, char *fname, char *suffix);
318 > static char * getword(FILE *fp);
319 > static char * fullnam(char *path, char *fname, char *suffix);
320 >
321 > /* main - process arguments and run the conversion
322 > *
323 > * Refer to the man page for details of the arguments.
324 > *
325 > * Following Unix environment conventions, main() exits with 0 on
326 > * success and 1 on failure.
327 > *
328 > * ies2rad outputs either two or three files for a given IES
329 > * file. There is always a .rad file containing Radiance scene
330 > * description primitives and a .dat file for the photometric data. If
331 > * tilt data is given, that is placed in a separate .dat file.  So
332 > * ies2rad must have a filename to operate. Sometimes this name is the
333 > * input file name, shorn of its extension; sometimes it is given in
334 > * the -o option. But an output file name is required for ies2rad to
335 > * do its work.
336 > *
337 > * Older versions of the LM-63 standard allowed inclusion of multiple
338 > * luminaires in one IES file; this is not supported by ies2rad.
339 > *
340 > * This code sometimes does not check to make sure it has not run out
341 > * of arguments; this can lead to segmentation faults and perhaps
342 > * other errors.
343 > *
344 > */
345 > int
346 > main(
347 >        int     argc,
348 >        char    *argv[]
349 > )
350   {
351          char    *outfile = NULL;
352          int     status;
353 <        char    outname[MAXWORD];
353 >        char    outname[RMAXWORD];
354          double  d1;
355          int     i;
356 <        
356 >
357 >        /* Scan the options */
358          for (i = 1; i < argc && argv[i][0] == '-'; i++)
359                  switch (argv[i][1]) {
360                  case 'd':               /* dimensions */
# Line 156 | Line 416 | char   *argv[];
416                  case 'f':               /* lamp data file */
417                          lampdat = argv[++i];
418                          break;
419 <                case 'o':               /* output file name */
419 >                case 'o':               /* output file root name */
420                          outfile = argv[++i];
421                          break;
422 +                case 's':               /* output to stdout */
423 +                        out2stdout = !out2stdout;
424 +                        break;
425                  case 'i':               /* illum */
426                          illumrad = atof(argv[++i]);
164                        if (illumrad < MINDIM)
165                                illumrad = MINDIM;
427                          break;
428 +                case 'g':               /* instantiate geometry? */
429 +                        instantiate = !instantiate;
430 +                        break;
431                  case 't':               /* override lamp type */
432                          lamptype = argv[++i];
433                          break;
# Line 184 | Line 448 | char   *argv[];
448                                          argv[0], argv[i]);
449                          exit(1);
450                  }
451 +        /* Save pointers to the list of input file names */
452          gargc = i;
453          gargv = argv;
454 <        initlamps();                    /* get lamp data (if needed) */
455 <                                        /* convert ies file(s) */
454 >
455 >        /* get lamp data (if needed) */
456 >        initlamps();
457 >
458 >        /* convert ies file(s) */
459 >        /* If an output file name is specified */
460          if (outfile != NULL) {
461                  if (i == argc)
462 +                        /* If no input filename is given, use stdin as
463 +                         * the source for the IES file */
464                          exit(ies2rad(NULL, outfile) == 0 ? 0 : 1);
465                  else if (i == argc-1)
466 +                        /* If exactly one input file name is given, use it. */
467                          exit(ies2rad(argv[i], outfile) == 0 ? 0 : 1);
468 <                else {
469 <                        fprintf(stderr, "%s: single input file required\n",
198 <                                        argv[0]);
199 <                        exit(1);
200 <                }
468 >                else
469 >                        goto needsingle; /* Otherwise, error. */
470          } else if (i >= argc) {
471 +                /* If an output file and an input file are not give, error. */
472                  fprintf(stderr, "%s: missing output file specification\n",
473                                  argv[0]);
474                  exit(1);
475          }
476 +        /* If no input or output file is given, error. */
477 +        if (out2stdout && i != argc-1)
478 +                goto needsingle;
479 +        /* Otherwise, process each input file in turn. */
480          status = 0;
481          for ( ; i < argc; i++) {
482                  tailtrunc(strcpy(outname,filename(argv[i])));
# Line 210 | Line 484 | char   *argv[];
484                          status = 1;
485          }
486          exit(status);
487 + needsingle:
488 +        fprintf(stderr, "%s: single input file required\n", argv[0]);
489 +        exit(1);
490   }
491  
492 <
493 < initlamps()                             /* set up lamps */
492 > /* Initlamps -- If necessary, read lamp data table */
493 > void
494 > initlamps(void)                         /* set up lamps */
495   {
496          float   *lcol;
497          int     status;
498  
499 +        /* If the lamp name is set to default, don't bother to read
500 +         * the lamp data table. */
501          if (lamptype != NULL && !strcmp(lamptype, default_name) &&
502                          deflamp == NULL)
503 <                return;                         /* no need for data */
504 <                                                /* else load file */
505 <        if ((status = loadlamps(lampdat)) < 0)
506 <                exit(1);
503 >                return;
504 >
505 >        if ((status = loadlamps(lampdat)) < 0) /* Load the lamp data table */
506 >                exit(1);                       /* Exit if problems
507 >                                                * with the file. */
508          if (status == 0) {
509 +                /* If can't open the file, just use the standard default lamp */
510                  fprintf(stderr, "%s: warning - no lamp data\n", lampdat);
511                  lamptype = default_name;
512                  return;
513          }
514 <        if (deflamp != NULL) {                  /* match default type */
514 >        if (deflamp != NULL) {
515 >                /* Look up the specified default lamp type */
516                  if ((lcol = matchlamp(deflamp)) == NULL)
517 +                        /* If it can't be found, use the default */
518                          fprintf(stderr,
519                                  "%s: warning - unknown default lamp type\n",
520                                          deflamp);
521                  else
522 +                        /* Use the selected default lamp color */
523                          copycolor(defcolor, lcol);
524          }
525 <        if (lamptype != NULL) {                 /* match selected type */
525 >        /* If a lamp type is specified and can be found, use it, and
526 >         * release the lamp data table memory; it won't be needed any more. */
527 >        if (lamptype != NULL) {
528                  if (strcmp(lamptype, default_name)) {
529                          if ((lcol = matchlamp(lamptype)) == NULL) {
530                                  fprintf(stderr,
# Line 249 | Line 536 | initlamps()                            /* set up lamps */
536                  }
537                  freelamps();                    /* all done with data */
538          }
539 <                                                /* else keep lamp data */
539 >        /* else keep lamp data */
540   }
541  
542 + /*
543 + * File path operations
544 + *
545 + * These provide file path operations that operate on both MS-Windows
546 + * and *nix. They will ignore and pass, but will not necessarily
547 + * process correctly, Windows drive letters. Paths including Windows
548 + * UNC network names (\\server\folder\file) may also cause problems.
549 + *
550 + */
551  
552 + /*
553 + * stradd()
554 + *
555 + * Add a string to the end of a string, optionally concatenating a
556 + * file path separator character.  If the path already ends with a
557 + * path separator, no additional separator is appended.
558 + *
559 + */
560   char *
561 < stradd(dst, src, sep)                   /* add a string at dst */
562 < register char   *dst, *src;
563 < int     sep;
561 > stradd(                 /* add a string at dst */
562 >        char    *dst,
563 >        char    *src,
564 >        int     sep
565 > )
566   {
567          if (src && *src) {
568                  do
# Line 269 | Line 575 | int    sep;
575          return(dst);
576   }
577  
578 <
578 > /*
579 > * fullnam () - return a usable path name for an output file
580 > */
581   char *
582 < fullname(path, fname, suffix)           /* return full path name */
583 < char    *path, *fname, *suffix;
582 > fullnam(
583 >        char    *path,          /* The base directory path */
584 >        char    *fname,         /* The file name */
585 >        char    *suffix         /* A suffix, which usually contains
586 >                                 * a file name extension. */
587 > )
588   {
589 +        extern char *prefdir;
590 +        extern char *libdir;
591 +
592          if (prefdir != NULL && abspath(prefdir))
593 +                /* If the subdirectory path is absolute or '.', just
594 +                 * concatenate the names together */
595                  libname(path, fname, suffix);
596          else if (abspath(fname))
597 +                /* If there is no subdirectory, and the file name is
598 +                 * an absolute path or '.', concatenate the path,
599 +                 * filename, and suffix. */
600                  strcpy(stradd(path, fname, 0), suffix);
601          else
602 +                /* If the file name is relative, concatenate path,
603 +                 * library directory, directory separator, file name,
604 +                 * and suffix.  */
605                  libname(stradd(path, libdir, DIRSEP), fname, suffix);
606  
607          return(path);
608   }
609  
610  
611 + /*
612 + * libname - convert a file name to a path
613 + */
614   char *
615 < libname(path, fname, suffix)            /* return library relative name */
616 < char    *path, *fname, *suffix;
615 > libname(
616 >        char    *path,          /* The base directory path */
617 >        char    *fname,         /* The file name */
618 >        char    *suffix         /* A suffix, which usually contains
619 >                                 * a file name extension. */
620 > )
621   {
622 +        extern char *prefdir;   /* The subdirectory where the file
623 +                                 * name is stored. */
624 +
625          if (abspath(fname))
626 +                /* If the file name begins with '/' or '.', combine
627 +                 * it with the path and attach the suffix */
628                  strcpy(stradd(path, fname, 0), suffix);
629          else
630 +                /* If the file name is relative, attach it to the
631 +                 * path, include the subdirectory, and append the suffix. */
632                  strcpy(stradd(stradd(path, prefdir, DIRSEP), fname, 0), suffix);
633  
634          return(path);
635   }
636  
637 <
637 > /* filename - find the base file name in a buffer containing a path
638 > *
639 > * The pointer is to a character within the buffer, not a string in itself;
640 > * it will become invalid when the buffer is freed.
641 > *
642 > */
643   char *
644 < filename(path)                  /* get final component of pathname */
645 < register char   *path;
644 > filename(
645 >        char    *path
646 > )
647   {
648 <        register char   *cp;
648 >        char    *cp;
649  
650          for (cp = path; *path; path++)
651                  if (ISDIRSEP(*path))
# Line 311 | Line 654 | register char  *path;
654   }
655  
656  
657 + /* filetrunc() - return the directory portion of a path
658 + *
659 + * The path is passed in in a pointer to a buffer; a null character is
660 + * inserted in the buffer after the last directory separator
661 + *
662 + */
663   char *
664 < filetrunc(path)                         /* truncate filename at end of path */
665 < char    *path;
664 > filetrunc(
665 >        char    *path
666 > )
667   {
668 <        register char   *p1, *p2;
668 >        char    *p1, *p2;
669  
670          for (p1 = p2 = path; *p2; p2++)
671                  if (ISDIRSEP(*p2))
672                          p1 = p2;
673 +        if (p1 == path && ISDIRSEP(*p1))
674 +                p1++;
675          *p1 = '\0';
676          return(path);
677   }
678  
679 <
679 > /* tailtrunc() - trim a file name extension, if any.
680 > *
681 > * The file name is passed in in a buffer indicated by *name; the
682 > * period which begins the extension is replaced with a 0 byte.
683 > */
684   char *
685 < tailtrunc(name)                         /* truncate tail of filename */
686 < char    *name;
685 > tailtrunc(
686 >        char    *name
687 > )
688   {
689 <        register char   *p1, *p2;
689 >        char    *p1, *p2;
690  
691 +        /* Skip leading periods */
692          for (p1 = filename(name); *p1 == '.'; p1++)
693                  ;
694 +        /* Find the last period in a file name */
695          p2 = NULL;
696          for ( ; *p1; p1++)
697                  if (*p1 == '.')
698                          p2 = p1;
699 +        /* If present, trim the filename at that period */
700          if (p2 != NULL)
701                  *p2 = '\0';
702          return(name);
703   }
704  
705 <
706 < blanktrunc(s)                           /* truncate spaces at end of line */
707 < char    *s;
705 > /* blanktrunc() - trim spaces at the end of a string
706 > *
707 > * the string is passed in a character array, which is modified
708 > */
709 > void
710 > blanktrunc(
711 >        char    *s
712 > )
713   {
714 <        register char   *cp;
714 >        char    *cp;
715  
716          for (cp = s; *cp; cp++)
717                  ;
# Line 355 | Line 720 | char   *s;
720          *++cp = '\0';
721   }
722  
723 + /* k_match - return true if keyword matches header line */
724 + int
725 + k_match(
726 +        char    *kwd,           /* keyword */
727 +        char    *hdl            /* header line */
728 + )
729 + {
730 +        /* Skip leading spaces */
731 +        while (isspace(*hdl))
732 +                hdl++;
733 +        /* The line has to begin with '[' */
734 +        if (*hdl++ != '[')
735 +                return(0);
736 +        /* case-independent keyword match */
737 +        while (toupper(*hdl) == *kwd++)
738 +                if (!*hdl++)
739 +                        return(0);
740 +        /* If we have come to the end of the keyword, and the keyword
741 +         * at the beginning of the matched line is terminated with
742 +         * ']', return 1 */
743 +        return(!kwd[-1] & (*hdl == ']'));
744 + }
745  
746 < putheader(out)                          /* print header */
747 < FILE    *out;
746 > /* keyargs - return the argument of a keyword, without leading spaces
747 > *
748 > * keyargs is passed a pointer to a buffer; it returns a pointer to
749 > * where the argument starts in the buffer
750 > *
751 > */
752 > char *
753 > keyargs(
754 >        char    *hdl /* header line */
755 > )
756   {
757 <        register int    i;
758 <        
757 >        while (*hdl && *hdl++ != ']')
758 >                ;
759 >        while (isspace(*hdl))
760 >                hdl++;
761 >        return(hdl);
762 > }
763 >
764 >
765 > /* putheader - output the header of the .rad file
766 > *
767 > * Header is:
768 > *   # <file> <file> <file> (all files from input line)
769 > *   # Dimensions in [feet,meters,etc.]
770 > *
771 > * ??? Is listing all the input file names correct behavior?
772 > *
773 > */
774 > void
775 >
776 > putheader(
777 >        FILE    *out
778 > )
779 > {
780 >        int     i;
781 >
782          putc('#', out);
783          for (i = 0; i < gargc; i++) {
784                  putc(' ', out);
# Line 371 | Line 789 | FILE   *out;
789          putc('\n', out);
790   }
791  
792 <
793 < ies2rad(inpname, outname)               /* convert IES file */
794 < char    *inpname, *outname;
792 > /* ies2rad - convert an IES LM-63 file to a Radiance light source desc.
793 > *
794 > * Return -1 in case of failure, 0 in case of success.
795 > *
796 > * The file version recognition is confused and will treat 1995 and
797 > * 2002 version files as 1986 version files.
798 > *
799 > */
800 > int
801 > ies2rad(                /* convert IES file */
802 >        char    *inpname,
803 >        char    *outname
804 > )
805   {
806 <        char    buf[MAXLINE], tltid[MAXWORD];
806 >        SRCINFO srcinfo;
807 >        char    buf[MAXLINE], tltid[RMAXWORD];
808 >        char    geomfile[128];
809          FILE    *inpfp, *outfp;
810 +        int     lineno = 0;
811  
812 +        /* Open input and output files */
813 +        geomfile[0] = '\0';
814 +        srcinfo.isillum = 0;
815          if (inpname == NULL) {
816                  inpname = "<stdin>";
817                  inpfp = stdin;
# Line 385 | Line 819 | char   *inpname, *outname;
819                  perror(inpname);
820                  return(-1);
821          }
822 <        if ((outfp = fopen(fullname(buf,outname,T_RAD), "w")) == NULL) {
822 >        if (out2stdout)
823 >                outfp = stdout;
824 >        else if ((outfp = fopen(fullnam(buf,outname,T_RAD), "w")) == NULL) {
825                  perror(buf);
826                  fclose(inpfp);
827                  return(-1);
828          }
829 +
830 +        /* Output the output file header */
831          putheader(outfp);
832 +
833 +        /* If the lamp type wasn't given on the command line, mark
834 +         * the lamp color as missing */
835          if (lamptype == NULL)
836                  lampcolor = NULL;
837 +
838 +        /* Read the input file header, copying lines to the .rad file
839 +         * and looking for a lamp type. Stop at EOF or a line
840 +         * beginning with "TILT=". */
841          while (fgets(buf,sizeof(buf),inpfp) != NULL
842                          && strncmp(buf,TLTSTR,TLTSTRLEN)) {
843 <                blanktrunc(buf);
844 <                if (!buf[0])
843 >                blanktrunc(buf); /* Trim trailing spaces, CR, LF. */
844 >                if (!buf[0])     /* Skip blank lines */
845                          continue;
846 +                /* increment the header line count, and check for the
847 +                 * "TILT=" line that terminates the header */
848 +                if (!lineno++) {        /* first line may be magic */
849 +                        if (!strncmp(buf, MAGICID2, LMAGICID2))
850 +                                filerev = atoi(buf+LMAGICID2) - 1900;
851 +                        else if (!strncmp(buf, MAGICID, LMAGICID))
852 +                                filerev = atoi(buf+LMAGICID);
853 +                        if (filerev < FIRSTREV)
854 +                                filerev = FIRSTREV;
855 +                        else if (filerev > LASTREV)
856 +                                filerev = LASTREV;
857 +                }
858 +                /* Output the header line as a comment in the .rad file. */
859                  fputs("#<", outfp);
860                  fputs(buf, outfp);
861                  putc('\n', outfp);
862 <                if (lampcolor == NULL)
863 <                        lampcolor = matchlamp(buf);
862 >
863 >                /* If the header line is a keyword line (file version
864 >                 * later than 1986 and begins with '['), check a lamp
865 >                 * in the "[LAMP]" and "[LAMPCAT]" keyword lines;
866 >                 * otherwise check all lines.  */
867 >                if (lampcolor == NULL && checklamp(buf))
868 >                        lampcolor = matchlamp(*sskip2(buf,0) == '[' ?
869 >                                                keyargs(buf) : buf );
870 >                /* Look for a materials and geometry file in the keywords. */
871 >                if (keymatch(K_LMG, buf)) {
872 >                        strcpy(geomfile, inpname);
873 >                        strcpy(filename(geomfile), keyargs(buf));
874 >                        srcinfo.isillum = 1;
875 >                }
876          }
877 +
878 +        /* Done reading header information. If a lamp color still
879 +         * hasn't been found, print a warning and use the default
880 +         * color; if a lamp type hasn't been found, but a color has
881 +         * been specified, used the specified color. */
882          if (lampcolor == NULL) {
883                  fprintf(stderr, "%s: warning - no lamp type\n", inpname);
884 +                fputs("# Unknown lamp type (used default)\n", outfp);
885                  lampcolor = defcolor;
886 <        }
886 >        } else if (lamptype == NULL)
887 >                fprintf(outfp,"# CIE(x,y) = (%f,%f)\n# Depreciation = %.1f%%\n",
888 >                                lampcolor[3], lampcolor[4], 100.*lampcolor[5]);
889 >
890 >        /* If the file ended before a "TILT=" line, that's an error. */
891          if (feof(inpfp)) {
892                  fprintf(stderr, "%s: not in IES format\n", inpname);
893                  goto readerr;
894          }
895 <        atos(tltid, MAXWORD, buf+TLTSTRLEN);
895 >
896 >        /* Process the tilt section of the file. */
897 >        /* Get the tilt file name, or the keyword "INCLUDE". */
898 >        atos(tltid, RMAXWORD, buf+TLTSTRLEN);
899          if (inpfp == stdin)
900                  buf[0] = '\0';
901          else
902                  filetrunc(strcpy(buf, inpname));
903 +        /* Process the tilt data. */
904          if (dotilt(inpfp, outfp, buf, tltid, outname, tltid) != 0) {
905                  fprintf(stderr, "%s: bad tilt data\n", inpname);
906                  goto readerr;
907          }
908 <        if (dosource(inpfp, outfp, tltid, outname) != 0) {
908 >
909 >        /* Process the luminaire data. */
910 >        if (dosource(&srcinfo, inpfp, outfp, tltid, outname) != 0) {
911                  fprintf(stderr, "%s: bad luminaire data\n", inpname);
912                  goto readerr;
913          }
914 <        fclose(outfp);
914 >
915 >        /* Close the input file */
916          fclose(inpfp);
917 +
918 +        /* Process an MGF file, if present. cvgeometry() closes outfp. */
919 +        if (cvgeometry(geomfile, &srcinfo, outname, outfp) != 0) {
920 +                fprintf(stderr, "%s: bad geometry file\n", geomfile);
921 +                return(-1);
922 +        }
923          return(0);
924 +
925   readerr:
926 <        fclose(outfp);
926 >        /* If there is an error reading the file, close the input and
927 >         * .rad output files, and delete the .rad file, returning -1. */
928          fclose(inpfp);
929 <        unlink(fullname(buf,outname,T_RAD));
929 >        fclose(outfp);
930 >        unlink(fullnam(buf,outname,T_RAD));
931          return(-1);
932   }
933  
934 <
935 < dotilt(in, out, dir, tltspec, dfltname, tltid)  /* convert tilt data */
936 < FILE    *in, *out;
937 < char    *dir, *tltspec, *dfltname, *tltid;
934 > /* dotilt -- process tilt data
935 > *
936 > * Generate a brightdata primitive which describes the effect of
937 > * luminaire tilt on luminaire output and return its identifier in tltid.
938 > *
939 > * Tilt data (if present) is given as a number 1, 2, or 3, which
940 > * specifies the orientation of the lamp within the luminaire, a
941 > * number, n, of (angle, multiplier) pairs, followed by n angles and n
942 > * multipliers.
943 > *
944 > * returns 0 for success, -1 for error
945 > */
946 > int
947 > dotilt(
948 >        FILE    *in,
949 >        FILE    *out,
950 >        char    *dir,
951 >        char    *tltspec,
952 >        char    *dfltname,
953 >        char    *tltid
954 > )
955   {
956          int     nangles, tlt_type;
957 <        double  minmax[2];
958 <        char    buf[MAXPATH], tltname[MAXWORD];
957 >        double  minmax[1][2];
958 >        char    buf[PATH_MAX], tltname[RMAXWORD];
959          FILE    *datin, *datout;
960  
961 +        /* Decide where the tilt data is; if the luminaire description
962 +         * doesn't have a tilt section, set the identifier to "void". */
963          if (!strcmp(tltspec, TLTNONE)) {
964 +                /* If the line is "TILT=NONE", set the input file
965 +                 * pointer to NULL and the identifier to "void". */
966                  datin = NULL;
967                  strcpy(tltid, "void");
968          } else if (!strcmp(tltspec, TLTINCL)) {
969 +                /* If the line is "TILT=INCLUDE" use the main IES
970 +                 * file as the source of tilt data. */
971                  datin = in;
972                  strcpy(tltname, dfltname);
973          } else {
974 +                /* If the line is "TILE=<filename>", use that file
975 +                 * name as the source of tilt data. */
976                  if (ISDIRSEP(tltspec[0]))
977                          strcpy(buf, tltspec);
978                  else
# Line 462 | Line 983 | char   *dir, *tltspec, *dfltname, *tltid;
983                  }
984                  tailtrunc(strcpy(tltname,filename(tltspec)));
985          }
986 +        /* If tilt data is present, read, process, and output it. */
987          if (datin != NULL) {
988 <                if ((datout = fopen(fullname(buf,tltname,T_TLT),"w")) == NULL) {
988 >                /* Try to open the output file */
989 >                if ((datout = fopen(fullnam(buf,tltname,T_TLT),"w")) == NULL) {
990                          perror(buf);
991                          if (datin != in)
992                                  fclose(datin);
993                          return(-1);
994                  }
995 +                /* Try to copy the tilt data to the tilt data file */
996                  if (!scnint(datin,&tlt_type) || !scnint(datin,&nangles)
997                          || cvdata(datin,datout,1,&nangles,1.,minmax) != 0) {
998                          fprintf(stderr, "%s: data format error\n", tltspec);
999                          fclose(datout);
1000                          if (datin != in)
1001                                  fclose(datin);
1002 <                        unlink(fullname(buf,tltname,T_TLT));
1002 >                        unlink(fullnam(buf,tltname,T_TLT));
1003                          return(-1);
1004                  }
1005                  fclose(datout);
1006                  if (datin != in)
1007                          fclose(datin);
1008 +
1009 +                /* Generate the identifier of the brightdata; the filename
1010 +                 * with "_tilt" appended. */
1011                  strcat(strcpy(tltid, filename(tltname)), "_tilt");
1012 +                /* Write out the brightdata primitive */
1013                  fprintf(out, "\nvoid brightdata %s\n", tltid);
1014                  libname(buf,tltname,T_TLT);
1015 +                /* Generate the tilt description */
1016                  switch (tlt_type) {
1017 <                case TLT_VERT:                  /* vertical */
1017 >                case TLT_VERT:
1018 >                        /* The lamp is mounted vertically; either
1019 >                         * base up or base down. */
1020                          fprintf(out, "4 noop %s tilt.cal %s\n", buf,
1021 <                                minmax[1]>90.+FTINY ? "tilt_ang" : "tilt_ang2");
1021 >                                minmax[0][1]>90.+FTINY ? "tilt_ang" : "tilt_ang2");
1022                          break;
1023 <                case TLT_H0:                    /* horiz. in 0 deg. plane */
1023 >                case TLT_H0:
1024 >                        /* The lamp is mounted horizontally and
1025 >                         * rotates but does not tilt when the
1026 >                         * luminaire is tilted. */
1027                          fprintf(out, "6 noop %s tilt.cal %s -rz 90\n", buf,
1028 <                        minmax[1]>90.+FTINY ? "tilt_xang" : "tilt_xang2");
1028 >                        minmax[0][1]>90.+FTINY ? "tilt_xang" : "tilt_xang2");
1029                          break;
1030                  case TLT_H90:
1031 +                        /* The lamp is mounted horizontally, and
1032 +                         * tilts when the luminaire is tilted. */
1033                          fprintf(out, "4 noop %s tilt.cal %s\n", buf,
1034 <                        minmax[1]>90.+FTINY ? "tilt_xang" : "tilt_xang2");
1034 >                        minmax[0][1]>90.+FTINY ? "tilt_xang" : "tilt_xang2");
1035                          break;
1036                  default:
1037 +                        /* otherwise, this is a bad IES file */
1038                          fprintf(stderr,
1039                                  "%s: illegal lamp to luminaire geometry (%d)\n",
1040                                  tltspec, tlt_type);
1041                          return(-1);
1042                  }
1043 +                /* And finally output the numbers of integer and real
1044 +                 * arguments, of which there are none. */
1045                  fprintf(out, "0\n0\n");
1046          }
1047          return(0);
1048   }
1049  
1050 <
1051 < dosource(in, out, mod, name)            /* create source and distribution */
1052 < FILE    *in, *out;
1053 < char    *mod, *name;
1050 > /* dosource -- create the source and distribution primitives */
1051 > int
1052 > dosource(
1053 >        SRCINFO *sinf,
1054 >        FILE    *in,
1055 >        FILE    *out,
1056 >        char    *mod,
1057 >        char    *name
1058 > )
1059   {
1060 <        SHAPE   srcshape;
517 <        char    buf[MAXPATH], id[MAXWORD];
1060 >        char    buf[PATH_MAX], id[RMAXWORD];
1061          FILE    *datout;
1062          double  mult, bfactor, pfactor, width, length, height, wattage;
1063          double  bounds[2][2];
1064          int     nangles[2], pmtype, unitype;
1065          double  d1;
1066 +        int     doupper, dolower, dosides;
1067  
1068 +        /* Read in the luminaire description header */
1069          if (!isint(getword(in)) || !isflt(getword(in)) || !scnflt(in,&mult)
1070                          || !scnint(in,&nangles[0]) || !scnint(in,&nangles[1])
1071                          || !scnint(in,&pmtype) || !scnint(in,&unitype)
# Line 530 | Line 1075 | char   *mod, *name;
1075                  fprintf(stderr, "dosource: bad lamp specification\n");
1076                  return(-1);
1077          }
1078 +        /* Type A photometry is not supported */
1079 +        if (pmtype != PM_C && pmtype != PM_B) {
1080 +                fprintf(stderr, "dosource: unsupported photometric type (%d)\n",
1081 +                                pmtype);
1082 +                return(-1);
1083 +        }
1084 +
1085 +        /* Multiplier = the multiplier from the -m option, times the
1086 +         * multiplier from the IES file, times the ballast factor,
1087 +         * times the "ballast lamp photometric factor," which was part
1088 +         * of the 1986 and 1991 standards. In the 1995 standard, it is
1089 +         * always supposed to be 1. */
1090 +        sinf->mult = multiplier*mult*bfactor*pfactor;
1091 +
1092 +        /* If the count of angles is wrong, raise an error and quit. */
1093          if (nangles[0] < 2 || nangles[1] < 1) {
1094                  fprintf(stderr, "dosource: too few measured angles\n");
1095                  return(-1);
1096          }
1097 +
1098 +        /* For internal computation, convert units to meters. */
1099          if (unitype == U_FEET) {
1100                  width *= F_M;
1101                  length *= F_M;
1102                  height *= F_M;
1103          }
1104 <        if (makeshape(&srcshape, width, length, height) != 0) {
1104 >
1105 >        /* Make decisions about the shape of the light source
1106 >         * geometry, and store them in sinf. */
1107 >        if (makeshape(sinf, width, length, height) != 0) {
1108                  fprintf(stderr, "dosource: illegal source dimensions");
1109                  return(-1);
1110          }
1111 <        if ((datout = fopen(fullname(buf,name,T_DST), "w")) == NULL) {
1111 >
1112 >        /* Copy the candela values into a Radiance data file. */
1113 >        if ((datout = fopen(fullnam(buf,name,T_DST), "w")) == NULL) {
1114                  perror(buf);
1115                  return(-1);
1116          }
1117          if (cvdata(in, datout, 2, nangles, 1./WHTEFFICACY, bounds) != 0) {
1118                  fprintf(stderr, "dosource: bad distribution data\n");
1119                  fclose(datout);
1120 <                unlink(fullname(buf,name,T_DST));
1120 >                unlink(fullnam(buf,name,T_DST));
1121                  return(-1);
1122          }
1123          fclose(datout);
1124 +
1125 +        /* Output explanatory comment */
1126          fprintf(out, "# %g watt luminaire, lamp*ballast factor = %g\n",
1127                          wattage, bfactor*pfactor);
1128 +        /* Output distribution "brightdata" primitive. Start handling
1129 +           the various cases of symmetry of the distribution. */
1130          strcat(strcpy(id, filename(name)), "_dist");
1131          fprintf(out, "\n%s brightdata %s\n", mod, id);
1132          if (nangles[1] < 2)
# Line 566 | Line 1137 | char   *mod, *name;
1137                  fprintf(out, "7 ");
1138          else
1139                  fprintf(out, "5 ");
1140 +
1141 +        /* If the generated source geometry will be a box, a flat
1142 +         * rectangle, or a disk figure out if it needs a top, a
1143 +         * bottom, and/or sides. */
1144 +        dolower = (bounds[0][0] < 90.-FTINY); /* Bottom */
1145 +        doupper = (bounds[0][1] > 90.+FTINY); /* Top */
1146 +        dosides = (doupper & dolower && sinf->h > MINDIM); /* Sides */
1147 +
1148 +        /* Select the appropriate function and parameters from source.cal */
1149          fprintf(out, "%s %s source.cal ",
1150 <                        srcshape.type==SPHERE ? "corr" : "flatcorr",
1150 >                        sinf->type==SPHERE ? "corr" :
1151 >                        !dosides ? "flatcorr" :
1152 >                        sinf->type==DISK ? "cylcorr" : "boxcorr",
1153                          libname(buf,name,T_DST));
1154          if (pmtype == PM_B) {
1155                  if (FEQ(bounds[1][0],0.))
# Line 575 | Line 1157 | char   *mod, *name;
1157                  else
1158                          fprintf(out, "srcB_horiz ");
1159                  fprintf(out, "srcB_vert ");
1160 <        } else {
1160 >        } else /* pmtype == PM_C */ {
1161                  if (nangles[1] >= 2) {
1162                          d1 = bounds[1][1] - bounds[1][0];
1163                          if (d1 <= 90.+FTINY)
1164                                  fprintf(out, "src_phi4 ");
1165 <                        else if (d1 <= 180.+FTINY)
1166 <                                fprintf(out, "src_phi2 ");
1167 <                        else
1165 >                        else if (d1 <= 180.+FTINY) {
1166 >                                if (FEQ(bounds[1][0],90.))
1167 >                                        fprintf(out, "src_phi2+90 ");
1168 >                                else
1169 >                                        fprintf(out, "src_phi2 ");
1170 >                        } else
1171                                  fprintf(out, "src_phi ");
1172                          fprintf(out, "src_theta ");
1173                          if (FEQ(bounds[1][0],90.) && FEQ(bounds[1][1],270.))
# Line 590 | Line 1175 | char   *mod, *name;
1175                  } else
1176                          fprintf(out, "src_theta ");
1177          }
1178 <        fprintf(out, "\n0\n1 %g\n", multiplier*mult*bfactor*pfactor);
1179 <        if (putsource(&srcshape, out, id, filename(name),
1180 <                        bounds[0][0]<90., bounds[0][1]>90.) != 0)
1178 >        /* finish the brightdata primitive with appropriate data */
1179 >        if (!dosides || sinf->type == SPHERE)
1180 >                fprintf(out, "\n0\n1 %g\n", sinf->mult/sinf->area);
1181 >        else if (sinf->type == DISK)
1182 >                fprintf(out, "\n0\n3 %g %g %g\n", sinf->mult,
1183 >                                sinf->w, sinf->h);
1184 >        else
1185 >                fprintf(out, "\n0\n4 %g %g %g %g\n", sinf->mult,
1186 >                                sinf->l, sinf->w, sinf->h);
1187 >        /* Brightdata primitive written out. */
1188 >
1189 >        /* Finally, output the descriptions of the actual radiant
1190 >         * surfaces. */
1191 >        if (putsource(sinf, out, id, filename(name),
1192 >                        dolower, doupper, dosides) != 0)
1193                  return(-1);
1194          return(0);
1195   }
1196  
1197 <
1198 < putsource(shp, fp, mod, name, dolower, doupper)         /* put out source */
1199 < SHAPE   *shp;
1200 < FILE    *fp;
1201 < char    *mod, *name;
1202 < int     dolower, doupper;
1197 > /* putsource - output the actual light emitting geometry
1198 > *
1199 > * Three kinds of geometry are produced: rectangles and boxes, disks
1200 > * ("ring" primitive, but the radius of the hole is always zero) and
1201 > * cylinders, and spheres.
1202 > */
1203 > int
1204 > putsource(
1205 >        SRCINFO *shp,
1206 >        FILE    *fp,
1207 >        char    *mod,
1208 >        char    *name,
1209 >        int     dolower,
1210 >        int     doupper,
1211 >        int     dosides
1212 > )
1213   {
1214 <        char    buf[MAXWORD];
1215 <        
1216 <        fprintf(fp, "\n%s %s %s_light\n", mod,
1217 <                        illumrad>=MINDIM/2. ? "illum" : "light",
1218 <                        name);
1214 >        char    lname[RMAXWORD];
1215 >
1216 >        /* First, describe the light. If a materials and geometry
1217 >         * file is given, generate an illum instead. */
1218 >        strcat(strcpy(lname, name), "_light");
1219 >        fprintf(fp, "\n%s %s %s\n", mod,
1220 >                        shp->isillum ? "illum" : "light", lname);
1221          fprintf(fp, "0\n0\n3 %g %g %g\n",
1222 <                        lampcolor[0]/shp->area,
614 <                        lampcolor[1]/shp->area,
615 <                        lampcolor[2]/shp->area);
616 <        if (doupper && dolower && shp->type != SPHERE && shp->h > MINDIM) {
617 <                fprintf(fp, "\n%s glow %s_glow\n", mod, name);
618 <                fprintf(fp, "0\n0\n4 %g %g %g -1\n",
619 <                                lampcolor[0]/shp->area,
620 <                                lampcolor[1]/shp->area,
621 <                                lampcolor[2]/shp->area);
622 <        }
1222 >                        lampcolor[0], lampcolor[1], lampcolor[2]);
1223          switch (shp->type) {
1224          case RECT:
1225 <                strcat(strcpy(buf, name), "_light");
1225 >                /* Output at least one rectangle. If light is radiated
1226 >                 * from the sides of the luminaire, output rectangular
1227 >                 * sides as well. */
1228                  if (dolower)
1229 <                        putrectsrc(shp, fp, buf, name, 0);
1229 >                        putrectsrc(shp, fp, lname, name, 0);
1230                  if (doupper)
1231 <                        putrectsrc(shp, fp, buf, name, 1);
1232 <                if (doupper && dolower && shp->h > MINDIM) {
1233 <                        strcat(strcpy(buf, name), "_glow");
632 <                        putsides(shp, fp, buf, name);
633 <                }
1231 >                        putrectsrc(shp, fp, lname, name, 1);
1232 >                if (dosides)
1233 >                        putsides(shp, fp, lname, name);
1234                  break;
1235          case DISK:
1236 <                strcat(strcpy(buf, name), "_light");
1236 >                /* Output at least one disk. If light is radiated from
1237 >                 * the sides of luminaire, output a cylinder as well. */
1238                  if (dolower)
1239 <                        putdisksrc(shp, fp, buf, name, 0);
1239 >                        putdisksrc(shp, fp, lname, name, 0);
1240                  if (doupper)
1241 <                        putdisksrc(shp, fp, buf, name, 1);
1242 <                if (doupper && dolower && shp->h > MINDIM) {
1243 <                        strcat(strcpy(buf, name), "_glow");
643 <                        putcyl(shp, fp, buf, name);
644 <                }
1241 >                        putdisksrc(shp, fp, lname, name, 1);
1242 >                if (dosides)
1243 >                        putcyl(shp, fp, lname, name);
1244                  break;
1245          case SPHERE:
1246 <                strcat(strcpy(buf, name), "_light");
1247 <                putspheresrc(shp, fp, buf, name);
1246 >                /* Output a sphere. */
1247 >                putspheresrc(shp, fp, lname, name);
1248                  break;
1249          }
1250          return(0);
1251   }
1252  
1253 <
1254 < makeshape(shp, width, length, height)           /* make source shape */
1255 < register SHAPE  *shp;
1256 < double  width, length, height;
1253 > /* makeshape -- decide what shape will be used
1254 > *
1255 > * makeshape decides what Radiance geometry will be used to represent
1256 > * the light source and stores information about it in shp.
1257 > */
1258 > int
1259 > makeshape(
1260 >        SRCINFO *shp,
1261 >        double  width,
1262 >        double  length,
1263 >        double  height
1264 > )
1265   {
1266 <        if (illumrad >= MINDIM/2.) {
1266 >        /* Categorize the shape */
1267 >        if (illumrad/meters2out >= MINDIM/2.) {
1268 >                /* If the -i command line option is used, and the
1269 >                 * object is not a point source, output an "illum"
1270 >                 * sphere */
1271 >                shp->isillum = 1;
1272                  shp->type = SPHERE;
1273 <                shp->w = shp->l = shp->h = 2.*illumrad;
1273 >                shp->w = shp->l = shp->h = 2.*illumrad / meters2out;
1274          } else if (width < MINDIM) {
1275 +                /* The width is either zero or negative. */
1276                  width = -width;
1277                  if (width < MINDIM) {
1278 +                        /* The width is zero. Use a tiny sphere to
1279 +                         * represent a point source. */
1280                          shp->type = SPHERE;
1281                          shp->w = shp->l = shp->h = MINDIM;
1282                  } else if (height < .5*width) {
1283 +                        /* The width is negative and the height is
1284 +                         * modest; output either a disk or a thin
1285 +                         * vertical cylinder. */
1286                          shp->type = DISK;
1287                          shp->w = shp->l = width;
1288                          if (height >= MINDIM)
# Line 672 | Line 1290 | double width, length, height;
1290                          else
1291                                  shp->h = .5*MINDIM;
1292                  } else {
1293 +                        /* The width is negative and the object is
1294 +                         * tall; output a sphere. */
1295                          shp->type = SPHERE;
1296                          shp->w = shp->l = shp->h = width;
1297                  }
1298          } else {
1299 +                /* The width is positive. Output a box, possibly very
1300 +                 * thin. */
1301                  shp->type = RECT;
1302                  shp->w = width;
1303                  if (length >= MINDIM)
# Line 687 | Line 1309 | double width, length, height;
1309                  else
1310                          shp->h = .5*MINDIM;
1311          }
1312 +
1313 +        /* Done choosing the shape; calculate its area in the x-y plane. */
1314          switch (shp->type) {
1315          case RECT:
1316                  shp->area = shp->w * shp->l;
# Line 699 | Line 1323 | double width, length, height;
1323          return(0);
1324   }
1325  
1326 + /* Rectangular or box-shaped light source.
1327 + *
1328 + * putrectsrc, putsides, putrect, and putpoint are used to output the
1329 + * Radiance description of a box.  The box is centered on the origin
1330 + * and has the dimensions given in the IES file.  The coordinates
1331 + * range from [-1/2*length, -1/2*width, -1/2*height] to [1/2*length,
1332 + * 1/2*width, 1/2*height].
1333 + *
1334 + * The location of the point is encoded in the low-order three bits of
1335 + * an integer. If the integer is p, then: bit 0 is (p & 1),
1336 + * representing length (x), bit 1 is (p & 2) representing width (y),
1337 + * and bit 2 is (p & 4), representing height (z).
1338 + *
1339 + * Looking down from above (towards -z), the vertices of the box or
1340 + * rectangle are numbered so:
1341 + *
1342 + *     2,6                                        3,7
1343 + *        +--------------------------------------+
1344 + *        |                                      |
1345 + *        |                                      |
1346 + *        |                                      |
1347 + *        |                                      |
1348 + *        +--------------------------------------+
1349 + *     0,4                                        1,5
1350 + *
1351 + * The higher number of each pair is above the x-y plane (positive z),
1352 + * the lower number is below the x-y plane (negative z.)
1353 + *
1354 + */
1355  
1356 < putrectsrc(shp, fp, mod, name, up)              /* rectangular source */
1357 < SHAPE   *shp;
1358 < FILE    *fp;
1359 < char    *mod, *name;
1360 < int     up;
1356 > /* putrecsrc - output a rectangle parallel to the x-y plane
1357 > *
1358 > * Putrecsrc calls out the vertices of a rectangle parallel to the x-y
1359 > * plane.  The order of the vertices is different for the upper and
1360 > * lower rectangles of a box, since a right-hand rule based on the
1361 > * order of the vertices is used to determine the surface normal of
1362 > * the rectangle, and the surface normal determines the direction the
1363 > * light radiated by the rectangle.
1364 > *
1365 > */
1366 > void
1367 > putrectsrc(
1368 >        SRCINFO *shp,
1369 >        FILE    *fp,
1370 >        char    *mod,
1371 >        char    *name,
1372 >        int     up
1373 > )
1374   {
1375          if (up)
1376                  putrect(shp, fp, mod, name, ".u", 4, 5, 7, 6);
# Line 712 | Line 1378 | int    up;
1378                  putrect(shp, fp, mod, name, ".d", 0, 2, 3, 1);
1379   }
1380  
1381 <
1382 < putsides(shp, fp, mod, name)                    /* put out sides of box */
1383 < register SHAPE  *shp;
1384 < FILE    *fp;
1385 < char    *mod, *name;
1381 > /* putsides - put out sides of box */
1382 > void
1383 > putsides(
1384 >        SRCINFO *shp,
1385 >        FILE    *fp,
1386 >        char    *mod,
1387 >        char    *name
1388 > )
1389   {
1390          putrect(shp, fp, mod, name, ".1", 0, 1, 5, 4);
1391          putrect(shp, fp, mod, name, ".2", 1, 3, 7, 5);
1392          putrect(shp, fp, mod, name, ".3", 3, 2, 6, 7);
1393          putrect(shp, fp, mod, name, ".4", 2, 0, 4, 6);
1394   }
726        
1395  
1396 < putrect(shp, fp, mod, name, suffix, a, b, c, d) /* put out a rectangle */
1397 < SHAPE   *shp;
1398 < FILE    *fp;
1399 < char    *mod, *name, *suffix;
1400 < int     a, b, c, d;
1396 > /* putrect - put out a rectangle
1397 > *
1398 > * putrect generates the "polygon" primitive which describes a
1399 > * rectangle.
1400 > */
1401 > void
1402 > putrect(
1403 >        SRCINFO *shp,
1404 >        FILE    *fp,
1405 >        char    *mod,
1406 >        char    *name,
1407 >        char    *suffix,
1408 >        int     a,
1409 >        int b,
1410 >        int c,
1411 >        int d
1412 > )
1413   {
1414          fprintf(fp, "\n%s polygon %s%s\n0\n0\n12\n", mod, name, suffix);
1415          putpoint(shp, fp, a);
# Line 738 | Line 1418 | int    a, b, c, d;
1418          putpoint(shp, fp, d);
1419   }
1420  
1421 <
1422 < putpoint(shp, fp, p)                            /* put out a point */
1423 < register SHAPE  *shp;
1424 < FILE    *fp;
1425 < int     p;
1421 > /* putpoint -- output a the coordinates of a vertex
1422 > *
1423 > * putpoint maps vertex numbers to coordinates and outputs the
1424 > * coordinates.
1425 > */
1426 > void
1427 > putpoint(
1428 >        SRCINFO *shp,
1429 >        FILE    *fp,
1430 >        int     p
1431 > )
1432   {
1433          static double   mult[2] = {-.5, .5};
1434  
# Line 752 | Line 1438 | int    p;
1438                          mult[p>>2]*shp->h*meters2out);
1439   }
1440  
1441 + /* End of routines to output a box-shaped light source */
1442  
1443 < putdisksrc(shp, fp, mod, name, up)              /* put out a disk source */
1444 < register SHAPE  *shp;
1445 < FILE    *fp;
1446 < char    *mod, *name;
1447 < int     up;
1443 > /* Routines to output a cylindrical or disk shaped light source
1444 > *
1445 > * As with other shapes, the light source is centered on the origin.
1446 > * The "ring" and "cylinder" primitives are used.
1447 > *
1448 > */
1449 > void
1450 > putdisksrc(             /* put out a disk source */
1451 >        SRCINFO *shp,
1452 >        FILE    *fp,
1453 >        char    *mod,
1454 >        char    *name,
1455 >        int     up
1456 > )
1457   {
1458          if (up) {
1459                  fprintf(fp, "\n%s ring %s.u\n", mod, name);
# Line 775 | Line 1471 | int    up;
1471   }
1472  
1473  
1474 < putcyl(shp, fp, mod, name)                      /* put out a cylinder */
1475 < register SHAPE  *shp;
1476 < FILE    *fp;
1477 < char    *mod, *name;
1474 > void
1475 > putcyl(                 /* put out a cylinder */
1476 >        SRCINFO *shp,
1477 >        FILE    *fp,
1478 >        char    *mod,
1479 >        char    *name
1480 > )
1481   {
1482          fprintf(fp, "\n%s cylinder %s.c\n", mod, name);
1483          fprintf(fp, "0\n0\n7\n");
# Line 787 | Line 1486 | char   *mod, *name;
1486          fprintf(fp, "\t%g\n", .5*shp->w*meters2out);
1487   }
1488  
1489 + /* end of of routines to output cylinders and disks */
1490  
1491 < putspheresrc(shp, fp, mod, name)                /* put out a sphere source */
1492 < SHAPE   *shp;
1493 < FILE    *fp;
1494 < char    *mod, *name;
1491 > void
1492 > putspheresrc(           /* put out a sphere source */
1493 >        SRCINFO *shp,
1494 >        FILE    *fp,
1495 >        char    *mod,
1496 >        char    *name
1497 > )
1498   {
1499          fprintf(fp, "\n%s sphere %s.s\n", mod, name);
1500          fprintf(fp, "0\n0\n4 0 0 0 %g\n", .5*shp->w*meters2out);
1501   }
1502  
1503 <
1504 < cvdata(in, out, ndim, npts, mult, lim)          /* convert data */
1505 < FILE    *in, *out;
1506 < int     ndim, npts[];
1507 < double  mult, lim[][2];
1503 > /* cvdata - convert LM-63 tilt and candela data to Radiance brightdata format
1504 > *
1505 > * The files created by this routine are intended for use with the Radiance
1506 > * "brightdata" material type.
1507 > *
1508 > * Two types of data are converted; one-dimensional tilt data, which
1509 > * is given in polar coordinates, and two-dimensional candela data,
1510 > * which is given in spherical co-ordinates.
1511 > *
1512 > * Return 0 for success, -1 for failure.
1513 > *
1514 > */
1515 > int
1516 > cvdata(
1517 >        FILE    *in,            /* Input file */
1518 >        FILE    *out,           /* Output file */
1519 >        int     ndim,           /* Number of dimensions; 1 for
1520 >                                 * tilt data, 2 for photometric data. */
1521 >        int     npts[],         /* Number of points in each dimension */
1522 >        double  mult,           /* Multiple each value by this
1523 >                                 * number. For tilt data, always
1524 >                                 * 1. For candela values, the
1525 >                                 * efficacy of white Radiance light.  */
1526 >        double  lim[][2]        /* The range of angles in each dimension. */
1527 > )
1528   {
1529 <        double  *pt[4];
1530 <        register int    i, j;
1529 >        double  *pt[4];         /* Four is the expected maximum of ndim. */
1530 >        int     i, j;
1531          double  val;
1532          int     total;
1533  
1534 +        /* Calculate and output the number of data values */
1535          total = 1; j = 0;
1536          for (i = 0; i < ndim; i++)
1537                  if (npts[i] > 1) {
# Line 815 | Line 1539 | double mult, lim[][2];
1539                          j++;
1540                  }
1541          fprintf(out, "%d\n", j);
1542 <                                        /* get coordinates */
1542 >
1543 >        /* Read in the angle values, and note the first and last in
1544 >         * each dimension, if there is a place to store them. In the
1545 >         * case of tilt data, there is only one list of angles. In the
1546 >         * case of candela values, vertical angles appear first, and
1547 >         * horizontal angles occur second. */
1548          for (i = 0; i < ndim; i++) {
1549 +                /* Allocate space for the angle values. */
1550                  pt[i] = (double *)malloc(npts[i]*sizeof(double));
1551                  for (j = 0; j < npts[i]; j++)
1552                          if (!scnflt(in, &pt[i][j]))
# Line 826 | Line 1556 | double mult, lim[][2];
1556                          lim[i][1] = pt[i][npts[i]-1];
1557                  }
1558          }
1559 <                                        /* write out in reverse */
1559 >
1560 >        /* Output the angles. If this is candela data, horizontal
1561 >         * angles output first. There are two cases: the first where
1562 >         * the angles are evenly spaced, the second where they are
1563 >         * not.
1564 >         *
1565 >         * When the angles are evenly spaced, three numbers are
1566 >         * output: the first angle, the last angle, and the number of
1567 >         * angles.  When the angles are not evenly spaced, instead
1568 >         * zero, zero, and the count of angles is given, followed by a
1569 >         * list of angles.  In this case, angles are output four to a line.
1570 >         */
1571          for (i = ndim-1; i >= 0; i--) {
1572                  if (npts[i] > 1) {
1573 +                        /* Determine if the angles are evenly spaces */
1574                          for (j = 1; j < npts[i]-1; j++)
1575                                  if (!FEQ(pt[i][j]-pt[i][j-1],
1576                                                  pt[i][j+1]-pt[i][j]))
1577                                          break;
1578 +                        /* If they are, output the first angle, the
1579 +                         * last angle, and a count */
1580                          if (j == npts[i]-1)
1581                                  fprintf(out, "%g %g %d\n", pt[i][0], pt[i][j],
1582                                                  npts[i]);
1583                          else {
1584 +                                /* otherwise, output 0, 0, and a
1585 +                                 * count, followed by the list of
1586 +                                 * angles, one to a line. */
1587                                  fprintf(out, "0 0 %d", npts[i]);
1588                                  for (j = 0; j < npts[i]; j++) {
1589                                          if (j%4 == 0)
# Line 846 | Line 1593 | double mult, lim[][2];
1593                                  putc('\n', out);
1594                          }
1595                  }
1596 <                free((char *)pt[i]);
1596 >                /* Free the storage containing the angle values. */
1597 >                free((void *)pt[i]);
1598          }
1599 +
1600 +        /* Finally, read in the data values (candela or multiplier values,
1601 +         * depending on the part of the file) and output them four to
1602 +         * a line. */
1603          for (i = 0; i < total; i++) {
1604                  if (i%4 == 0)
1605                          putc('\n', out);
# Line 859 | Line 1611 | double mult, lim[][2];
1611          return(0);
1612   }
1613  
1614 <
1614 > /* getword - get an LM-63 delimited word from fp
1615 > *
1616 > * Getword gets a word from an IES file delimited by either white
1617 > * space or a comma surrounded by white space. A pointer to the word
1618 > * is returned, which will persist only until getword is called again.
1619 > * At EOF, return NULL instead.
1620 > *
1621 > */
1622   char *
1623 < getword(fp)                     /* scan a word from fp */
1624 < register FILE   *fp;
1623 > getword(                        /* scan a word from fp */
1624 >        FILE    *fp
1625 > )
1626   {
1627 <        static char     word[MAXWORD];
1628 <        register char   *cp;
1629 <        register int    c;
1627 >        static char     wrd[RMAXWORD];
1628 >        char    *cp;
1629 >        int     c;
1630  
1631 +        /* Skip initial spaces */
1632          while (isspace(c=getc(fp)))
1633                  ;
1634 <        for (cp = word; c != EOF && cp < word+MAXWORD-1;
1634 >        /* Get characters to a delimiter or until wrd is full */
1635 >        for (cp = wrd; c != EOF && cp < wrd+RMAXWORD-1;
1636                          *cp++ = c, c = getc(fp))
1637                  if (isspace(c) || c == ',') {
1638 +                        /* If we find a delimiter */
1639 +                        /* Gobble up whitespace */
1640                          while (isspace(c))
1641                                  c = getc(fp);
1642 <                        if (c != EOF & c != ',')
1642 >                        /* If it's not a comma, put the first
1643 >                         * character of the next data item back */
1644 >                        if ((c != EOF) & (c != ','))
1645                                  ungetc(c, fp);
1646 +                        /* Close out the strimg */
1647                          *cp = '\0';
1648 <                        return(word);
1648 >                        /* return it */
1649 >                        return(wrd);
1650                  }
1651 +        /* If we ran out of space or are at the end of the file,
1652 +         * return either the word or NULL, as appropriate. */
1653          *cp = '\0';
1654 <        return(cp > word ? word : NULL);
1654 >        return(cp > wrd ? wrd : NULL);
1655   }
1656  
1657 <
1658 < cvtint(ip, word)                /* convert a word to an integer */
1659 < int     *ip;
1660 < char    *word;
1657 > /* cvtint - convert an IES word to an integer
1658 > *
1659 > * A pointer to the word is passed in wrd; ip is expected to point to
1660 > * an integer.  cvtint() will silently truncate a floating point value
1661 > * to an integer; "1", "1.0", and "1.5" will all return 1.
1662 > *
1663 > * cvtint() returns 0 if it fails, 1 if it succeeds.
1664 > */
1665 > int
1666 > cvtint(
1667 >        int     *ip,
1668 >        char    *wrd
1669 > )
1670   {
1671 <        if (word == NULL || !isint(word))
1671 >        if (wrd == NULL || !isint(wrd))
1672                  return(0);
1673 <        *ip = atoi(word);
1673 >        *ip = atoi(wrd);
1674          return(1);
1675   }
1676  
1677  
1678 < cvtflt(rp, word)                /* convert a word to a double */
1679 < double  *rp;
1680 < char    *word;
1678 > /* cvtflt - convert an IES word to a double precision floating-point number
1679 > *
1680 > * A pointer to the word is passed in wrd; rp is expected to point to
1681 > * a double.
1682 > *
1683 > * cvtflt returns 0 if it fails, 1 if it succeeds.
1684 > */
1685 > int
1686 > cvtflt(
1687 >        double  *rp,
1688 >        char    *wrd
1689 > )
1690   {
1691 <        if (word == NULL || !isflt(word))
1691 >        if (wrd == NULL || !isflt(wrd))
1692                  return(0);
1693 <        *rp = atof(word);
1693 >        *rp = atof(wrd);
1694          return(1);
1695   }
1696 +
1697 + /* cvgeometry - process materials and geometry format luminaire data
1698 + *
1699 + * The materials and geometry format (MGF) for describing luminaires
1700 + * was a part of Radiance that was first adopted and then retracted by
1701 + * the IES as part of LM-63.  It provides a way of describing
1702 + * luminaire geometry similar to the Radiance scene description
1703 + * format.
1704 + *
1705 + * cvgeometry() generates an mgf2rad command and then, if "-g" is given
1706 + * on the command line, an oconv command, both of which are then
1707 + * executed with the system() function.
1708 + *
1709 + * The generated commands are:
1710 + *   mgf2rad -e <multiplier> -g <size> <mgf_filename> \
1711 + *     | xform -s <scale_factor> \
1712 + *     >> <luminare_scene_description_file
1713 + * or:
1714 + *   mgf2rad -e <multiplier> -g <size> <mgf_filename> \
1715 + *     oconv - > <instance_filename>
1716 + */
1717 + int
1718 + cvgeometry(
1719 +        char    *inpname,
1720 +        SRCINFO *sinf,
1721 +        char    *outname,
1722 +        FILE    *outfp                  /* close output file upon return */
1723 + )
1724 + {
1725 +        char    buf[256];
1726 +        char    *cp;
1727 +
1728 +        if (inpname == NULL || !inpname[0]) {   /* no geometry file */
1729 +                fclose(outfp);
1730 +                return(0);
1731 +        }
1732 +        putc('\n', outfp);
1733 +        strcpy(buf, "mgf2rad ");                /* build mgf2rad command */
1734 +        cp = buf+8;
1735 +        if (!FEQ(sinf->mult, 1.0)) {
1736 +                /* if there's an output multiplier, include in the
1737 +                 * mgf2rad command */
1738 +                sprintf(cp, "-e %f ", sinf->mult);
1739 +                cp += strlen(cp);
1740 +        }
1741 +        /* Include the glow distance for the geometry */
1742 +        sprintf(cp, "-g %f %s ",
1743 +                sqrt(sinf->w*sinf->w + sinf->h*sinf->h + sinf->l*sinf->l),
1744 +                        inpname);
1745 +        cp += strlen(cp);
1746 +        if (instantiate) {              /* instantiate octree */
1747 +                /* If "-g" is given on the command line, include an
1748 +                 * "oconv" command in the pipe. */
1749 +                strcpy(cp, "| oconv - > ");
1750 +                cp += 12;
1751 +                fullnam(cp,outname,T_OCT);
1752 +                /* Only update if the input file is newer than the
1753 +                 * output file */
1754 +                if (fdate(inpname) > fdate(outname) &&
1755 +                                system(buf)) {          /* create octree */
1756 +                        fclose(outfp);
1757 +                        return(-1);
1758 +                }
1759 +                /* Reference the instance file in the scene description */
1760 +                fprintf(outfp, "void instance %s_inst\n", outname);
1761 +                /* If the geometry isn't in meters, scale it appropriately. */
1762 +                if (!FEQ(meters2out, 1.0))
1763 +                        fprintf(outfp, "3 %s -s %f\n",
1764 +                                        libname(buf,outname,T_OCT),
1765 +                                        meters2out);
1766 +                else
1767 +                        fprintf(outfp, "1 %s\n", libname(buf,outname,T_OCT));
1768 +                /* Close off the "instance" primitive. */
1769 +                fprintf(outfp, "0\n0\n");
1770 +                /* And the Radiance scene description. */
1771 +                fclose(outfp);
1772 +        } else {                        /* else append to luminaire file */
1773 +                if (!FEQ(meters2out, 1.0)) {    /* apply scalefactor */
1774 +                        sprintf(cp, "| xform -s %f ", meters2out);
1775 +                        cp += strlen(cp);
1776 +                }
1777 +                if (!out2stdout) {
1778 +                        fclose(outfp);
1779 +                        strcpy(cp, ">> ");      /* append works for DOS? */
1780 +                        cp += 3;
1781 +                        fullnam(cp,outname,T_RAD);
1782 +                }
1783 +                if (system(buf))
1784 +                        return(-1);
1785 +        }
1786 +        return(0);
1787 + }
1788 +
1789 + /* Set up emacs indentation */
1790 + /* Local Variables: */
1791 + /*   c-file-style: "bsd" */
1792 + /* End: */
1793 +
1794 + /* For vim, use ":set tabstop=8 shiftwidth=8" */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines