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

Comparing ray/src/util/eplus_adduvf.c (file contents):
Revision 2.2 by greg, Sun Feb 9 22:19:30 2014 UTC vs.
Revision 2.21 by greg, Mon Jan 20 17:53:40 2020 UTC

# Line 7 | Line 7 | static const char RCSid[] = "$Id$";
7   *      G.Ward for LBNL
8   */
9  
10 #include <stdio.h>
10   #include <stdlib.h>
11 < #include <string.h>
11 > #include <ctype.h>
12 > #include "platform.h"
13 > #include "rtio.h"
14 > #include "rtmath.h"
15 > #include "random.h"
16   #include "eplus_idf.h"
17   #include "triangulate.h"
18   #include "rtprocess.h"
19  
20   #ifndef NSAMPLES
21 < #define NSAMPLES        100000                  /* number of samples to use */
21 > #define NSAMPLES        80000                   /* default number of samples */
22   #endif
23  
24 + #define SURF_EPS        0.0005                  /* surface testing epsilon */
25 +
26   char            *progname;                      /* global argv[0] */
27  
28 < char            temp_octree[128];                       /* temporary octree */
28 > int             nsamps = NSAMPLES;              /* number of samples to use */
29  
30 + char            temp_octree[128];               /* temporary octree */
31 +
32   const char      UVF_PNAME[] =
33 <                        "ZoneProperty:UserViewFactor:bySurfaceName";
33 >                        "ZoneProperty:UserViewFactors:bySurfaceName";
34  
35 + const char      SUBSURF_PNAME[] =
36 +                        "FenestrationSurface:Detailed";
37 +
38   const char      ADD_HEADER[] =
39 <                        "!+++ User View Factors computed by Radiance +++!\n";
39 >                        "\n!+++ User View Factors computed by Radiance +++!\n\n";
40  
41   #define NAME_FLD        1                       /* name field always first? */
42  
43 + #define SS_BASE_FLD     4                       /* subsurface base surface */
44 + #define SS_VERT_FLD     9                       /* subsurface vertex count */
45 +
46   typedef struct {
47 <        const char      *pname;                 /* parameter type name */
47 >        const char      *pname;                 /* object type name */
48          short           zone_fld;               /* zone field index */
49          short           vert_fld;               /* vertex field index */
50   } SURF_PTYPE;           /* surface type we're interested in */
51  
52   const SURF_PTYPE        surf_type[] = {
53                  {"BuildingSurface:Detailed", 4, 10},
54 +                {"Floor:Detailed", 3, 9},
55 +                {"RoofCeiling:Detailed", 3, 9},
56 +                {"Wall:Detailed", 3, 9},
57                  {NULL}
58 <        };
58 >        };                              /* IDF surface types */
59  
60   typedef struct s_zone {
61          const char      *zname;                 /* zone name */
62          struct s_zone   *next;                  /* next zone in list */
63          int             nsurf;                  /* surface count */
64 <        IDF_PARAMETER   *pfirst;                /* first matching parameter */
65 <        IDF_PARAMETER   *plast;                 /* last matching parameter */
64 >        int             ntotal;                 /* surfaces+subsurfaces */
65 >        IDF_OBJECT      *pfirst;                /* first matching object */
66 >        IDF_OBJECT      *plast;                 /* last before subsurfaces */
67 >        float           *area_redu;             /* subsurface area per surf. */
68   } ZONE;                 /* a list of collected zone surfaces */
69  
70   ZONE            *zone_list = NULL;      /* our list of zones */
71  
72 + LUTAB           zonesurf_lut =          /* zone surface lookup table */
73 +                        LU_SINIT(NULL,NULL);
74 +
75   IDF_LOADED      *our_idf = NULL;        /* loaded/modified IDF */
76  
77 + typedef struct {
78 +        FVECT           norm;           /* surface normal */
79 +        double          area;           /* surface area */
80 +        int             nv;             /* number of vertices */
81 +        FVECT           vl[3];          /* vertex list (extends struct) */
82 + } SURFACE;              /* a polygonal surface */
83 +
84 + typedef struct {
85 +        FVECT           sdir[3];        /* UVW unit sampling vectors */
86 +        double          poff;           /* W-offset for plane of polygon */
87 +        double          area_left;      /* area left to sample */
88 +        int             samp_left;      /* remaining samples */
89 +        int             wd;             /* output file descriptor */
90 + } POLYSAMP;             /* structure for polygon sampling */
91 +
92   /* Create a new zone and push to top of our list */
93   static ZONE *
94 < new_zone(const char *zname, IDF_PARAMETER *param)
94 > new_zone(const char *zname, IDF_OBJECT *param)
95   {
96          ZONE    *znew = (ZONE *)malloc(sizeof(ZONE));
97  
# Line 64 | Line 100 | new_zone(const char *zname, IDF_PARAMETER *param)
100          znew->zname = zname;                    /* assumes static */
101          znew->next = zone_list;
102          znew->pfirst = znew->plast = param;
103 <        znew->nsurf = 1;
103 >        znew->ntotal = znew->nsurf = 1;
104 >        znew->area_redu = NULL;
105          return(zone_list = znew);
106   }
107  
108   /* Add the detailed surface (polygon) to the named zone */
109   static ZONE *
110 < add2zone(IDF_PARAMETER *param, const char *zname)
110 > add2zone(IDF_OBJECT *param, const char *zname)
111   {
112 <        ZONE    *zptr;
112 >        IDF_FIELD       *nfp = idf_getfield(param, NAME_FLD);
113 >        ZONE            *zptr;
114 >        LUENT           *lep;
115  
116 +        if (nfp == NULL) {
117 +                fputs(progname, stderr);
118 +                fputs(": surface missing name field!\n", stderr);
119 +                return(NULL);
120 +        }
121          for (zptr = zone_list; zptr != NULL; zptr = zptr->next)
122                  if (!strcmp(zptr->zname, zname))
123                          break;
124 <        if (zptr == NULL)
125 <                return(new_zone(zname, param));
126 <                                                /* keep surfaces together */
127 <        if (!idf_movparam(our_idf, param, zptr->plast))
124 >        if (zptr == NULL) {
125 >                zptr = new_zone(zname, param);
126 >        } else {                                /* keep surfaces together */
127 >                if (!idf_movobject(our_idf, param, zptr->plast))
128 >                        return(NULL);
129 >                zptr->plast = param;
130 >                zptr->nsurf++;
131 >                zptr->ntotal++;
132 >        }
133 >                                                /* add to lookup table */
134 >        lep = lu_find(&zonesurf_lut, nfp->val);
135 >        if (lep == NULL)
136                  return(NULL);
137 <        zptr->plast = param;
138 <        zptr->nsurf++;
137 >        if (lep->data != NULL) {
138 >                fputs(progname, stderr);
139 >                fputs(": duplicate surface name '", stderr);
140 >                fputs(nfp->val, stderr);
141 >                fputs("'\n", stderr);
142 >                return(NULL);
143 >        }
144 >        lep->key = nfp->val;
145 >        lep->data = (char *)zptr;
146          return(zptr);
147   }
148  
149 < /* Determine if a parameter is a surface in the indicated zone */
150 < static int
151 < in_zone(IDF_PARAMETER *param, const char *zname)
149 > /* Add a subsurface by finding its base surface and the corresponding zone */
150 > static ZONE *
151 > add_subsurf(IDF_OBJECT *param)
152   {
153 <        int             i = 0;
154 <        IDF_FIELD       *fptr;
155 <                                                /* check for surface type */
156 <        while (strcmp(surf_type[i].pname, param->pname))
157 <                if (surf_type[++i].pname == NULL)
158 <                        return(0);
159 <                                                /* get zone field */
160 <        fptr = idf_getfield(param, surf_type[i].zone_fld);
161 <        if (fptr == NULL)
162 <                return(0);
163 <                                                /* check for match */
164 <        if (strcmp(fptr->arg, zname))
165 <                return(0);
166 <                                                /* return field for #verts */
167 <        return(surf_type[i].vert_fld);
153 >        IDF_FIELD       *bfp = idf_getfield(param, SS_BASE_FLD);
154 >        ZONE            *zptr;
155 >        LUENT           *lep;
156 >
157 >        if (bfp == NULL) {
158 >                fputs(progname, stderr);
159 >                fputs(": missing base field name in subsurface!\n", stderr);
160 >                return(NULL);
161 >        }
162 >        lep = lu_find(&zonesurf_lut, bfp->val); /* find base zone */
163 >        if (lep == NULL || lep->data == NULL) {
164 >                fputs(progname, stderr);
165 >                fputs(": cannot find referenced base surface '", stderr);
166 >                fputs(bfp->val, stderr);
167 >                fputs("'\n", stderr);
168 >                return(NULL);
169 >        }
170 >        zptr = (ZONE *)lep->data;               /* add this subsurface */
171 >        if (!idf_movobject(our_idf, param, zptr->plast))
172 >                return(NULL);
173 >        zptr->ntotal++;
174 >        return(zptr);
175   }
176  
177 + /* Return field for vertices in the given object */
178 + static IDF_FIELD *
179 + get_vlist(IDF_OBJECT *param, const char *zname)
180 + {
181 + #define itm_len         (sizeof(IDF_FIELD)+6)
182 +        static char             fld_buf[4*itm_len];
183 +        static char             *next_fbp = fld_buf;
184 +        int                     i;
185 +        IDF_FIELD               *res;
186 +                                                /* check if subsurface */
187 +        if (!strcmp(param->pname, SUBSURF_PNAME)) {
188 +                if (zname != NULL) {
189 +                        LUENT   *lep = lu_find(&zonesurf_lut,
190 +                                        idf_getfield(param,SS_BASE_FLD)->val);
191 +                        if (strcmp((*(ZONE *)lep->data).zname, zname))
192 +                                return(NULL);
193 +                }
194 +                res = idf_getfield(param, SS_VERT_FLD);
195 +        } else {
196 +                i = 0;                          /* check for surface type */
197 +                while (strcmp(surf_type[i].pname, param->pname))
198 +                        if (surf_type[++i].pname == NULL)
199 +                                return(NULL);
200 +
201 +                if (zname != NULL) {            /* matches specified zone? */
202 +                        IDF_FIELD       *fptr = idf_getfield(param, surf_type[i].zone_fld);
203 +                        if (fptr == NULL || strcmp(fptr->val, zname))
204 +                                return(NULL);
205 +                }
206 +                res = idf_getfield(param, surf_type[i].vert_fld);
207 +        }
208 +        if (!res->val[0] || tolower(res->val[0]) == 'a') {  /* autocalculate */
209 +                IDF_FIELD       *fptr;
210 +                if (next_fbp >= fld_buf+sizeof(fld_buf))
211 +                        next_fbp = fld_buf;
212 +                i = 0;                          /* count vertices */
213 +                for (fptr = res->next; fptr != NULL; fptr = fptr->next)
214 +                        ++i;
215 +                if (i % 3)
216 +                        return(NULL);
217 +                fptr = res->next;
218 +                res = (IDF_FIELD *)next_fbp; next_fbp += itm_len;
219 +                res->next = fptr;
220 +                res->rem = "";
221 +                sprintf(res->val, "%d", i/3);
222 +        }
223 +        return(res);
224 + #undef itm_len
225 + }
226 +
227 + /* Get/allocate surface polygon */
228 + static SURFACE *
229 + get_surface(IDF_FIELD *fptr)
230 + {
231 +        SURFACE *surf;
232 +        int     nv;
233 +        FVECT   e1, e2, vc;
234 +        int     i, j;
235 +                                        /* get number of vertices */
236 +        if (fptr == NULL || (nv = atoi(fptr->val)) < 3) {
237 +                fputs(progname, stderr);
238 +                fputs(": bad vertex count for surface!\n", stderr);
239 +                return(NULL);
240 +        }
241 +        surf = (SURFACE *)malloc(sizeof(SURFACE)+sizeof(FVECT)*(nv-3));
242 +        if (surf == NULL)
243 +                return(NULL);
244 +        surf->nv = nv;
245 +        for (i = nv; i--; )             /* reverse vertex order/orientation */
246 +                for (j = 0; j < 3; j++) {
247 +                        fptr = fptr->next;
248 +                        if (fptr == NULL) {
249 +                                fputs(progname, stderr);
250 +                                fputs(": missing vertex in get_surface()\n", stderr);
251 +                                free(surf);
252 +                                return(NULL);
253 +                        }
254 +                        if ((surf->vl[i][j] = atof(fptr->val)) == 0 &&
255 +                                                        !isflt(fptr->val)) {
256 +                                fputs(progname, stderr);
257 +                                fputs(": bad vertex in get_surface()\n", stderr);
258 +                                free(surf);
259 +                                return(NULL);
260 +                        }
261 +                }
262 +                                        /* compute area and normal */
263 +        surf->norm[0] = surf->norm[1] = surf->norm[2] = 0;
264 +        VSUB(e1, surf->vl[1], surf->vl[0]);
265 +        for (i = 2; i < nv; i++) {
266 +                VSUB(e2, surf->vl[i], surf->vl[0]);
267 +                fcross(vc, e1, e2);
268 +                surf->norm[0] += vc[0];
269 +                surf->norm[1] += vc[1];
270 +                surf->norm[2] += vc[2];
271 +                VCOPY(e1, e2);
272 +        }
273 +        surf->area = .5 * normalize(surf->norm);
274 +        if (surf->area == 0) {
275 +                fputs(progname, stderr);
276 +                fputs(": degenerate polygon in get_surface()\n", stderr);
277 +                free(surf);
278 +                return(NULL);
279 +        }
280 +        return(surf);
281 + }
282 +
283   /* Convert surface to Radiance with modifier based on unique name */
284   static int
285 < rad_surface(const char *zname, IDF_PARAMETER *param, FILE *ofp)
285 > rad_surface(IDF_OBJECT *param, FILE *ofp)
286   {
287 <        const char      *sname = idf_getfield(param, NAME_FLD)->arg;
288 <        IDF_FIELD       *fptr = idf_getfield(param, in_zone(param, zname));
289 <        int             nvert, i;
287 >        const char      *sname = idf_getfield(param,NAME_FLD)->val;
288 >        IDF_FIELD       *fptr = get_vlist(param, NULL);
289 >        const char      **fargs;
290 >        int             nvert, i, j;
291  
292 <        if (fptr == NULL || (nvert = atoi(fptr->arg)) < 3) {
292 >        if (fptr == NULL || (nvert = atoi(fptr->val)) < 3) {
293                  fprintf(stderr, "%s: bad surface '%s'\n", progname, sname);
294                  return(0);
295          }
296 +        fargs = (const char **)malloc(sizeof(const char *)*3*nvert);
297 +        if (fargs == NULL)
298 +                return(0);
299          fprintf(ofp, "\nvoid glow '%s'\n0\n0\n4 1 1 1 0\n", sname);
300          fprintf(ofp, "\n'%s' polygon 's_%s'\n0\n0\n%d\n", sname, sname, 3*nvert);
301 <        while (nvert--) {
302 <                for (i = 3; i--; ) {
301 >        for (j = nvert; j--; ) {                /* get arguments in reverse */
302 >                for (i = 0; i < 3; i++) {
303                          fptr = fptr->next;
304 <                        if (fptr == NULL) {
304 >                        if (fptr == NULL || !isflt(fptr->val)) {
305                                  fprintf(stderr,
306 <                                "%s: missing vertex fields in surface '%s'\n",
307 <                                                progname, sname);
306 >                                        "%s: missing/bad vertex for %s '%s'\n",
307 >                                                progname, param->pname, sname);
308                                  return(0);
309                          }
310 +                        fargs[3*j + i] = fptr->val;
311 +                }
312 +        }
313 +        for (j = 0; j < nvert; j++) {           /* output reversed verts */
314 +                for (i = 0; i < 3; i++) {
315                          fputc('\t', ofp);
316 <                        fputs(fptr->arg, ofp);
316 >                        fputs(fargs[3*j + i], ofp);
317                  }
318                  fputc('\n', ofp);
319          }
320 +        free(fargs);
321          return(!ferror(ofp));
322   }
323  
324 < /* Strat rcontrib process */
324 > /* Convert subsurface to Radiance with modifier based on unique name */
325 > static double
326 > rad_subsurface(IDF_OBJECT *param, FILE *ofp)
327 > {
328 >        const char      *sname = idf_getfield(param,NAME_FLD)->val;
329 >        SURFACE         *surf = get_surface(get_vlist(param, NULL));
330 >        double          area;
331 >        int             i;
332 >
333 >        if (surf == NULL) {
334 >                fprintf(stderr, "%s: bad subsurface '%s'\n", progname, sname);
335 >                return(-1.);
336 >        }
337 >        fprintf(ofp, "\nvoid glow '%s'\n0\n0\n4 1 1 1 0\n", sname);
338 >        fprintf(ofp, "\n'%s' polygon 'ss_%s'\n0\n0\n%d\n",
339 >                                                sname, sname, 3*surf->nv);
340 >        for (i = 0; i < surf->nv; i++) {        /* offset vertices */
341 >                FVECT   vert;
342 >                VSUM(vert, surf->vl[i], surf->norm, 2.*SURF_EPS);
343 >                fprintf(ofp, "\t%.12f %.12f %.12f\n", vert[0], vert[1], vert[2]);
344 >        }
345 >        area = surf->area;
346 >        free(surf);
347 >        if (ferror(ofp))
348 >                return(-1.);
349 >        return(area);
350 > }
351 >
352 > /* Start rcontrib process */
353   static int
354   start_rcontrib(SUBPROC *pd, ZONE *zp)
355   {
356 < #define BASE_AC         3
356 > #define BASE_AC         6
357          static char     *base_av[BASE_AC] = {
358 <                                "rcontrib", "-ff", "-h"
358 >                                "rcontrib", "-V+", "-fff", "-h", "-x", "1"
359                          };
360          char            cbuf[300];
361          char            **av;
362          FILE            *ofp;
363 <        IDF_PARAMETER   *pptr;
364 <        int             i, n;
363 >        IDF_OBJECT      *pptr;
364 >        IDF_FIELD       *fptr;
365 >        int             i, j, n;
366                                                  /* start oconv command */
367 <        sprintf(cbuf, "oconv - > '%s'", temp_octree);
367 >        sprintf(cbuf, "oconv - > \"%s\"", temp_octree);
368          if ((ofp = popen(cbuf, "w")) == NULL) {
369                  fputs(progname, stderr);
370                  fputs(": cannot open oconv process\n", stderr);
371                  return(0);
372          }
373                                                  /* allocate argument list */
374 <        av = (char **)malloc(sizeof(char *)*(BASE_AC+4+2*zp->nsurf));
374 >        av = (char **)malloc(sizeof(char *)*(BASE_AC+4+2*(zp->ntotal)));
375          if (av == NULL)
376                  return(0);
377          for (i = 0; i < BASE_AC; i++)
378                  av[i] = base_av[i];
379 <        sprintf(cbuf, "%d", NSAMPLES);
379 >        sprintf(cbuf, "%d", nsamps);
380          av[i++] = "-c";
381 <        av[i++] = cbuf;                         /* add modifier arguments */
382 <        for (n = zp->nsurf, pptr = zp->pfirst; n--; pptr = pptr->dnext) {
383 <                IDF_FIELD       *fptr = idf_getfield(pptr, NAME_FLD);
384 <                if (fptr == NULL) {
381 >        av[i++] = cbuf;                         /* add modifiers & surfaces */
382 >        for (n = 0, pptr = zp->pfirst; n < zp->nsurf; n++, pptr = pptr->dnext) {
383 >                fptr = idf_getfield(pptr,NAME_FLD);
384 >                if (fptr == NULL || !fptr->val[0]) {
385                          fputs(progname, stderr);
386 <                        fputs(": missing name for surface parameter\n", stderr);
386 >                        fputs(": missing name for surface object\n", stderr);
387                          return(0);
388                  }
389 +                if (!rad_surface(pptr, ofp))    /* add surface to octree */
390 +                        return(0);
391                  av[i++] = "-m";
392 <                av[i++] = fptr->arg;
393 <                if (!rad_surface(zp->zname, pptr, ofp))
392 >                av[i++] = fptr->val;
393 >        }
394 >                                                /* now subsurfaces */
395 >        if (zp->ntotal > zp->nsurf) {
396 >                if (zp->area_redu != NULL)
397 >                        memset(zp->area_redu, 0, sizeof(float)*zp->ntotal);
398 >                else if ((zp->area_redu = (float *)calloc(zp->ntotal,
399 >                                                sizeof(float))) == NULL)
400                          return(0);
401          }
402 +        for ( ; n < zp->ntotal; n++, pptr = pptr->dnext) {
403 +                double          ssarea;
404 +                const char      *bname;
405 +                IDF_OBJECT      *pptr1;
406 +                fptr = idf_getfield(pptr,NAME_FLD);
407 +                if (fptr == NULL || !fptr->val[0]) {
408 +                        fputs(progname, stderr);
409 +                        fputs(": missing name for subsurface object\n", stderr);
410 +                        return(0);
411 +                }
412 +                                                /* add subsurface to octree */
413 +                if ((ssarea = rad_subsurface(pptr, ofp)) < 0)
414 +                        return(0);
415 +                                                /* mark area for subtraction */
416 +                bname = idf_getfield(pptr,SS_BASE_FLD)->val;
417 +                for (j = 0, pptr1 = zp->pfirst;
418 +                                j < zp->nsurf; j++, pptr1 = pptr1->dnext)
419 +                        if (!strcmp(idf_getfield(pptr1,NAME_FLD)->val, bname)) {
420 +                                zp->area_redu[j] += ssarea;
421 +                                break;
422 +                        }
423 +                av[i++] = "-m";
424 +                av[i++] = fptr->val;
425 +        }
426          if (pclose(ofp) != 0) {                 /* finish oconv */
427                  fputs(progname, stderr);
428                  fputs(": error running oconv process\n", stderr);
# Line 187 | Line 430 | start_rcontrib(SUBPROC *pd, ZONE *zp)
430          }
431          av[i++] = temp_octree;                  /* add final octree argument */
432          av[i] = NULL;
433 <        if (!open_process(pd, av)) {            /* start process */
433 >        if (open_process(pd, av) <= 0) {        /* start process */
434                  fputs(progname, stderr);
435                  fputs(": cannot start rcontrib process\n", stderr);
436                  return(0);
# Line 197 | Line 440 | start_rcontrib(SUBPROC *pd, ZONE *zp)
440   #undef BASE_AC
441   }
442  
443 + /* Initialize polygon sampling */
444 + static Vert2_list *
445 + init_poly(POLYSAMP *ps, IDF_FIELD *f0)
446 + {
447 +        SURFACE         *surf;
448 +        Vert2_list      *vl2;
449 +        int             i;
450 +                                        /* get 3-D polygon vertices */
451 +        if ((surf = get_surface(f0)) == NULL)
452 +                return(NULL);
453 +        vl2 = polyAlloc(surf->nv);
454 +        if (vl2 == NULL)
455 +                return(NULL);
456 +                                        /* create X & Y axes */
457 +        VCOPY(ps->sdir[2], surf->norm);
458 +        VSUB(ps->sdir[0], surf->vl[1], surf->vl[0]);
459 +        if (normalize(ps->sdir[0]) == 0)
460 +                return(NULL);
461 +        fcross(ps->sdir[1], ps->sdir[2], ps->sdir[0]);
462 +                                        /* compute plane offset */
463 +        ps->poff = DOT(surf->vl[0], ps->sdir[2]);
464 +                                        /* assign 2-D vertices */
465 +        for (i = 0; i < surf->nv; i++) {
466 +                vl2->v[i].mX = DOT(surf->vl[i], ps->sdir[0]);
467 +                vl2->v[i].mY = DOT(surf->vl[i], ps->sdir[1]);
468 +        }
469 +        ps->area_left = surf->area;
470 +        free(surf);                     /* it's ready! */
471 +        vl2->p = (void *)ps;
472 +        return(vl2);
473 + }
474 +
475 + /* Generate samples on 2-D triangle */
476 + static int
477 + sample_triangle(const Vert2_list *vl2, int a, int b, int c)
478 + {
479 +        POLYSAMP        *ps = (POLYSAMP *)vl2->p;
480 +        float           *samp;
481 +        FVECT           orig;
482 +        FVECT           ab, ac;
483 +        double          area;
484 +        int             i, j, ns;
485 +                                        /* compute sampling axes */
486 +        for (i = 3; i--; ) {
487 +                orig[i] = vl2->v[a].mX*ps->sdir[0][i] +
488 +                                vl2->v[a].mY*ps->sdir[1][i] +
489 +                                (ps->poff+SURF_EPS)*ps->sdir[2][i];
490 +                ab[i] = (vl2->v[b].mX - vl2->v[a].mX)*ps->sdir[0][i] +
491 +                                (vl2->v[b].mY - vl2->v[a].mY)*ps->sdir[1][i];
492 +                ac[i] = (vl2->v[c].mX - vl2->v[a].mX)*ps->sdir[0][i] +
493 +                                (vl2->v[c].mY - vl2->v[a].mY)*ps->sdir[1][i];
494 +        }
495 +                                        /* compute number of samples to take */
496 +        area = .5*(vl2->v[a].mX*vl2->v[b].mY - vl2->v[b].mX*vl2->v[a].mY +
497 +                        vl2->v[b].mX*vl2->v[c].mY - vl2->v[c].mX*vl2->v[b].mY +
498 +                        vl2->v[c].mX*vl2->v[a].mY - vl2->v[a].mX*vl2->v[c].mY);
499 +        if (area < .0) {
500 +                fputs(progname, stderr);
501 +                fputs(": negative triangle area in sample_triangle()\n", stderr);
502 +                return(0);
503 +        }
504 +        if (area >= ps->area_left) {
505 +                ns = ps->samp_left;
506 +                ps->area_left = 0;
507 +        } else {
508 +                ns = (ps->samp_left*area/ps->area_left + .5);
509 +                ps->samp_left -= ns;
510 +                ps->area_left -= area;
511 +        }
512 +        if (ns <= 0)                    /* XXX should be error? */
513 +                return(1);
514 +                                        /* buffer sample rays */
515 +        samp = (float *)malloc(sizeof(float)*6*ns);
516 +        if (samp == NULL)
517 +                return(0);
518 +        for (i = ns; i--; ) {           /* stratified Monte Carlo sampling */
519 +                double  sv[4];
520 +                FVECT   dv;
521 +                multisamp(sv, 4, (i+frandom())/(double)ns);
522 +                sv[0] *= sv[1] = sqrt(sv[1]);
523 +                sv[1] = 1. - sv[1];
524 +                for (j = 3; j--; )
525 +                        samp[i*6 + j] = orig[j] + sv[0]*ab[j] + sv[1]*ac[j];
526 +                sv[2] = sqrt(sv[2]);
527 +                sv[3] *= 2.*PI;
528 +                dv[0] = tcos(sv[3]) * sv[2];
529 +                dv[1] = tsin(sv[3]) * sv[2];
530 +                dv[2] = sqrt(1. - sv[2]*sv[2]);
531 +                for (j = 3; j--; )
532 +                        samp[i*6 + 3 + j] = dv[0]*ps->sdir[0][j] +
533 +                                                dv[1]*ps->sdir[1][j] +
534 +                                                dv[2]*ps->sdir[2][j] ;
535 +        }
536 +                                        /* send to our process */
537 +        writebuf(ps->wd, (char *)samp, sizeof(float)*6*ns);
538 +        free(samp);                     /* that's it! */
539 +        return(1);
540 + }
541 +
542 + /* Sample the given surface */
543 + static double
544 + sample_surface(IDF_OBJECT *param, int wd)
545 + {
546 +        POLYSAMP        psamp;
547 +        double          area;
548 +        int             nv;
549 +        Vert2_list      *vlist2;
550 +                                        /* set up our polygon sampler */
551 +        if ((vlist2 = init_poly(&psamp, get_vlist(param, NULL))) == NULL) {
552 +                fprintf(stderr, "%s: bad polygon %s '%s'\n",
553 +                                progname, param->pname,
554 +                                idf_getfield(param,NAME_FLD)->val);
555 +                return(-1.);
556 +        }
557 +        psamp.samp_left = nsamps;       /* assign samples & destination */
558 +        psamp.wd = wd;
559 +                                        /* hack for subsurface sampling */
560 +        psamp.poff += 2.*SURF_EPS * !strcmp(param->pname, SUBSURF_PNAME);
561 +
562 +        area = psamp.area_left;         /* remember starting surface area */
563 +                                        /* sample each subtriangle */
564 +        if (!polyTriangulate(vlist2, &sample_triangle))
565 +                return(-1.);
566 +        polyFree(vlist2);               /* clean up and return */
567 +        return(area);
568 + }
569 +
570   /* Compute User View Factors using open rcontrib process */
571   static int
572 < compute_uvfs(SUBPROC *pd, ZONE *sp)
572 > compute_uvfs(SUBPROC *pd, ZONE *zp)
573   {
574 <        
574 >        IDF_OBJECT      *pptr, *pout, *pptr1;
575 >        float           *uvfa;
576 >        char            uvfbuf[24];
577 >        int             n, m;
578 >                                                /* create output object */
579 >        pout = idf_newobject(our_idf, UVF_PNAME,
580 >                        "    ! computed by Radiance\n        ", our_idf->plast);
581 >        if (pout == NULL) {
582 >                fputs(progname, stderr);
583 >                fputs(": cannot create new IDF object\n", stderr);
584 >                return(0);
585 >        }
586 >        if (!idf_addfield(pout, zp->zname,
587 >                        "    !- Zone Name\n        ")) {
588 >                fputs(progname, stderr);
589 >                fputs(": cannot add zone name field\n", stderr);
590 >                return(0);
591 >        }
592 >                                                /* allocate read buffer */
593 >        uvfa = (float *)malloc(sizeof(float)*3*zp->ntotal);
594 >        if (uvfa == NULL)
595 >                return(0);
596 >                                                /* UVFs from each surface */
597 >        for (n = 0, pptr = zp->pfirst; n < zp->ntotal; n++, pptr = pptr->dnext) {
598 >                double  vfsum = 0;
599 >                double  adj_factor;
600 >                                                /* send samples to rcontrib */
601 >                if ((adj_factor = sample_surface(pptr, pd->w)) < 0)
602 >                        return(0);
603 >                if (zp->area_redu == NULL)
604 >                        adj_factor = 1.;
605 >                else                            /* comp. for subsurface area */
606 >                        adj_factor /= adj_factor - zp->area_redu[n];
607 >                                                /* read results */
608 >                if (readbuf(pd->r, (char *)uvfa, sizeof(float)*3*zp->ntotal) !=
609 >                                sizeof(float)*3*zp->ntotal) {
610 >                        fputs(progname, stderr);
611 >                        fputs(": read error from rcontrib process\n", stderr);
612 >                        return(0);
613 >                }
614 >                                                /* append UVF fields */
615 >                for (m = 0, pptr1 = zp->pfirst;
616 >                                m < zp->ntotal; m++, pptr1 = pptr1->dnext) {
617 >                        const double    uvf = uvfa[3*m + 1] * adj_factor;
618 >                        vfsum += uvf;
619 >                        if (pptr1 == pptr && uvf > .001)
620 >                                fprintf(stderr,
621 >                "%s: warning - non-zero self-VF (%.1f%%) for surface '%s'\n",
622 >                                                progname, 100.*uvf,
623 >                                                idf_getfield(pptr,NAME_FLD)->val);
624 >                        sprintf(uvfbuf, "%.4f", uvf);
625 >                        if (!idf_addfield(pout,
626 >                                        idf_getfield(pptr,NAME_FLD)->val, NULL) ||
627 >                                !idf_addfield(pout,
628 >                                        idf_getfield(pptr1,NAME_FLD)->val, NULL) ||
629 >                                !idf_addfield(pout, uvfbuf,
630 >                                                (n+m < 2*zp->ntotal-2) ?
631 >                                                "\n        " : "\n\n")) {
632 >                                fputs(progname, stderr);
633 >                                fputs(": error adding UVF fields\n", stderr);
634 >                                return(0);
635 >                        }
636 >                }
637 >                if (vfsum < 0.95)
638 >                        fprintf(stderr,
639 >                "%s: warning - missing %.1f%% of energy from surface '%s'\n",
640 >                                        progname, 100.*(1.-vfsum),
641 >                                        idf_getfield(pptr,NAME_FLD)->val);
642 >        }
643 >        free(uvfa);                             /* clean up and return */
644 >        return(1);
645   }
646  
647   /* Compute zone User View Factors */
# Line 210 | Line 650 | compute_zones(void)
650   {
651          ZONE    *zptr;
652                                                  /* temporary octree name */
653 <        if (temp_filename(temp_octree, sizeof(temp_octree), TEMPLATE) == NULL) {
214 <                fputs(progname, stderr);
215 <                fputs(": cannot create temporary octree\n", stderr);
216 <                return(0);
217 <        }
653 >        mktemp(strcpy(temp_octree, TEMPLATE));
654                                                  /* compute each zone */
655          for (zptr = zone_list; zptr != NULL; zptr = zptr->next) {
656                  SUBPROC rcproc;
# Line 240 | Line 676 | main(int argc, char *argv[])
676   {
677          int             incl_comments = 1;
678          char            *origIDF, *revIDF;
679 <        IDF_PARAMETER   *pptr;
679 >        IDF_OBJECT      *pptr;
680          int             i;
681  
682 <        progname = argv[0];
683 <        if (argc > 2 && !strcmp(argv[1], "-c")) {
684 <                incl_comments = -1;             /* output header only */
685 <                ++argv; --argc;
686 <        }
687 <        if ((argc < 2) | (argc > 3)) {
688 <                fputs("Usage: ", stderr);
689 <                fputs(progname, stderr);
690 <                fputs(" [-c] Model.idf [Revised.idf]\n", stderr);
691 <                return(1);
692 <        }
693 <        origIDF = argv[1];
694 <        revIDF = (argc == 2) ? argv[1] : argv[2];
682 >        progname = *argv++; argc--;             /* get options if any */
683 >        while (argc > 1 && argv[0][0] == '-')
684 >                switch (argv[0][1]) {
685 >                case 'c':                       /* elide comments */
686 >                        incl_comments = -1;             /* header only */
687 >                        argv++; argc--;
688 >                        continue;
689 >                case 's':                       /* samples */
690 >                        nsamps = 1000*atoi(*++argv);
691 >                        argv++; argc -= 2;
692 >                        continue;
693 >                default:
694 >                        fputs(progname, stderr);
695 >                        fputs(": unknown option '", stderr);
696 >                        fputs(argv[0], stderr);
697 >                        fputs("'\n", stderr);
698 >                        goto userr;
699 >                }
700 >        if ((argc < 1) | (argc > 2))
701 >                goto userr;
702 >        origIDF = argv[0];
703 >        revIDF = (argc == 1) ? argv[0] : argv[1];
704                                                  /* load Input Data File */
705          our_idf = idf_load(origIDF);
706          if (our_idf == NULL) {
# Line 265 | Line 710 | main(int argc, char *argv[])
710                  fputs("'\n", stderr);
711                  return(1);
712          }
713 +                                                /* check version (warning) */
714 +        if ((pptr = idf_getobject(our_idf, "Version")) != NULL &&
715 +                        pptr->flist != NULL && pptr->flist->val[0] != '9') {
716 +                fputs(progname, stderr);
717 +                fputs(": warning - written for IDF version 9.x, not ",
718 +                                stderr);
719 +                fputs(pptr->flist->val, stderr);
720 +                fputc('\n', stderr);
721 +        }
722                                                  /* remove existing UVFs */
723 <        if ((pptr = idf_getparam(our_idf, UVF_PNAME)) != NULL) {
724 <                IDF_PARAMETER   *pnext;
723 >        if ((pptr = idf_getobject(our_idf, UVF_PNAME)) != NULL) {
724 >                IDF_OBJECT      *pnext;
725                  fputs(progname, stderr);
726                  fputs(": removing previous User View Factors\n", stderr);
727                  do {
728                          pnext = pptr->pnext;
729 <                        idf_delparam(our_idf, pptr);
730 <                } while (pnext != NULL);
729 >                        idf_delobject(our_idf, pptr);
730 >                } while ((pptr = pnext) != NULL);
731          }
732                                                  /* add to header */
733          if (our_idf->hrem == NULL ||
# Line 282 | Line 736 | main(int argc, char *argv[])
736                  idf_add2hdr(our_idf, ADD_HEADER);
737                                                  /* gather zone surfaces */
738          for (i = 0; surf_type[i].pname != NULL; i++)
739 <                for (pptr = idf_getparam(our_idf, surf_type[i].pname);
739 >                for (pptr = idf_getobject(our_idf, surf_type[i].pname);
740                                  pptr != NULL; pptr = pptr->pnext) {
741                          IDF_FIELD       *fptr = idf_getfield(pptr,
742                                                          surf_type[i].zone_fld);
# Line 291 | Line 745 | main(int argc, char *argv[])
745                                  fputs(": warning - missing zone field\n", stderr);
746                                  continue;
747                          }
748 <                        if (add2zone(pptr, fptr->arg) == NULL)
748 >                        if (add2zone(pptr, fptr->val) == NULL)
749                                  return(1);
750                  }
751 +                                                /* add subsurfaces */
752 +        for (pptr = idf_getobject(our_idf, SUBSURF_PNAME);
753 +                        pptr != NULL; pptr = pptr->pnext)
754 +                if (add_subsurf(pptr) == NULL)
755 +                        return(1);
756                                                  /* run rcontrib on each zone */
757          if (!compute_zones())
758                  return(1);
# Line 306 | Line 765 | main(int argc, char *argv[])
765                  return(1);
766          }
767          return(0);                              /* finito! */
768 + userr:
769 +        fputs("Usage: ", stderr);
770 +        fputs(progname, stderr);
771 +        fputs(" [-c][-s Ksamps] Model.idf [Revised.idf]\n", stderr);
772 +        return(1);
773   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines