ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapdata.c
Revision: 2.22
Committed: Wed Apr 8 15:14:21 2020 UTC (4 years, 1 month ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.21: +37 -8 lines
Log Message:
Fixed est00pid bug in single photon lookups that returned junk when none found, added code to detect and handle (ignore).

File Contents

# User Rev Content
1 greg 2.11 #ifndef lint
2 rschregle 2.22 static const char RCSid[] = "$Id: pmapdata.c,v 2.21 2019/05/10 17:43:22 rschregle Exp $";
3 greg 2.11 #endif
4 rschregle 2.15
5 greg 2.1 /*
6 rschregle 2.15 =========================================================================
7     Photon map types and interface to nearest neighbour lookups in underlying
8     point cloud data structure.
9    
10     The default data structure is an in-core kd-tree (see pmapkdt.{h,c}).
11     This can be overriden with the PMAP_OOC compiletime switch, which enables
12     an out-of-core octree (see oococt.{h,c}).
13 greg 2.1
14     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
15     (c) Fraunhofer Institute for Solar Energy Systems,
16 rschregle 2.3 (c) Lucerne University of Applied Sciences and Arts,
17 rschregle 2.15 supported by the Swiss National Science Foundation (SNSF, #147053)
18     ==========================================================================
19 greg 2.1
20 rschregle 2.22 $Id: pmapdata.c,v 2.21 2019/05/10 17:43:22 rschregle Exp $
21 greg 2.1 */
22    
23    
24    
25 rschregle 2.18 #include "pmapdata.h"
26 greg 2.1 #include "pmaprand.h"
27     #include "pmapmat.h"
28     #include "otypes.h"
29     #include "source.h"
30     #include "rcontrib.h"
31 rschregle 2.7 #include "random.h"
32 greg 2.1
33    
34    
35     PhotonMap *photonMaps [NUM_PMAP_TYPES] = {
36     NULL, NULL, NULL, NULL, NULL, NULL
37     };
38    
39    
40    
41 rschregle 2.15 /* Include routines to handle underlying point cloud data structure */
42     #ifdef PMAP_OOC
43     #include "pmapooc.c"
44     #else
45     #include "pmapkdt.c"
46     #endif
47    
48 rschregle 2.19 /* Ambient include/exclude set (from ambient.c) */
49     #ifndef MAXASET
50     #define MAXASET 4095
51     #endif
52     extern OBJECT ambset [MAXASET+1];
53    
54 rschregle 2.21 /* Callback to print photon attributes acc. to user defined format */
55     int (*printPhoton)(RAY *r, Photon *p, PhotonMap *pm);
56    
57 rschregle 2.15
58    
59 greg 2.1 void initPhotonMap (PhotonMap *pmap, PhotonMapType t)
60     /* Init photon map 'n' stuff... */
61     {
62     if (!pmap)
63     return;
64    
65 rschregle 2.15 pmap -> numPhotons = 0;
66 greg 2.1 pmap -> biasCompHist = NULL;
67     pmap -> maxPos [0] = pmap -> maxPos [1] = pmap -> maxPos [2] = -FHUGE;
68     pmap -> minPos [0] = pmap -> minPos [1] = pmap -> minPos [2] = FHUGE;
69     pmap -> minGathered = pmap -> maxGathered = pmap -> totalGathered = 0;
70     pmap -> gatherTolerance = gatherTolerance;
71     pmap -> minError = pmap -> maxError = pmap -> rmsError = 0;
72     pmap -> numDensity = 0;
73     pmap -> distribRatio = 1;
74     pmap -> type = t;
75 rschregle 2.15 pmap -> squeue.node = NULL;
76     pmap -> squeue.len = 0;
77 greg 2.1
78     /* Init local RNG state */
79     pmap -> randState [0] = 10243;
80     pmap -> randState [1] = 39829;
81     pmap -> randState [2] = 9433;
82     pmapSeed(randSeed, pmap -> randState);
83    
84     /* Set up type-specific photon lookup callback */
85     pmap -> lookup = pmapLookup [t];
86    
87 rschregle 2.15 /* Mark primary photon ray as unused */
88     pmap -> lastPrimary.srcIdx = -1;
89     pmap -> numPrimary = 0;
90     pmap -> primaries = NULL;
91    
92     /* Init storage */
93     pmap -> heap = NULL;
94     pmap -> heapBuf = NULL;
95     pmap -> heapBufLen = 0;
96     #ifdef PMAP_OOC
97     OOC_Null(&pmap -> store);
98     #else
99     kdT_Null(&pmap -> store);
100     #endif
101 greg 2.1 }
102    
103    
104    
105 rschregle 2.15 void initPhotonHeap (PhotonMap *pmap)
106 greg 2.1 {
107 rschregle 2.15 int fdFlags;
108 greg 2.1
109 rschregle 2.15 if (!pmap)
110     error(INTERNAL, "undefined photon map in initPhotonHeap");
111 greg 2.1
112 rschregle 2.15 if (!pmap -> heap) {
113     /* Open heap file */
114 rschregle 2.18 mktemp(strcpy(pmap -> heapFname, PMAP_TMPFNAME));
115     if (!(pmap -> heap = fopen(pmap -> heapFname, "w+b")))
116 rschregle 2.15 error(SYSTEM, "failed opening heap file in initPhotonHeap");
117 rschregle 2.18
118 greg 2.16 #ifdef F_SETFL /* XXX is there an alternate needed for Windows? */
119 rschregle 2.15 fdFlags = fcntl(fileno(pmap -> heap), F_GETFL);
120     fcntl(fileno(pmap -> heap), F_SETFL, fdFlags | O_APPEND);
121 rschregle 2.18 #endif/* ftruncate(fileno(pmap -> heap), 0); */
122 greg 2.1 }
123 rschregle 2.15 }
124    
125    
126    
127     void flushPhotonHeap (PhotonMap *pmap)
128     {
129     int fd;
130     const unsigned long len = pmap -> heapBufLen * sizeof(Photon);
131    
132     if (!pmap)
133     error(INTERNAL, "undefined photon map in flushPhotonHeap");
134    
135 rschregle 2.18 if (!pmap -> heap || !pmap -> heapBuf) {
136     /* Silently ignore undefined heap
137     error(INTERNAL, "undefined heap in flushPhotonHeap"); */
138     return;
139     }
140 rschregle 2.15
141     /* Atomically seek and write block to heap */
142     /* !!! Unbuffered I/O via pwrite() avoids potential race conditions
143     * !!! and buffer corruption which can occur with lseek()/fseek()
144     * !!! followed by write()/fwrite(). */
145     fd = fileno(pmap -> heap);
146 greg 2.1
147 rschregle 2.15 #ifdef DEBUG_PMAP
148     sprintf(errmsg, "Proc %d: flushing %ld photons from pos %ld\n", getpid(),
149     pmap -> heapBufLen, lseek(fd, 0, SEEK_END) / sizeof(Photon));
150     eputs(errmsg);
151     #endif
152    
153     /*if (pwrite(fd, pmap -> heapBuf, len, lseek(fd, 0, SEEK_END)) != len) */
154     if (write(fd, pmap -> heapBuf, len) != len)
155     error(SYSTEM, "failed append to heap file in flushPhotonHeap");
156 greg 2.17
157 rschregle 2.18 #if NIX
158 rschregle 2.15 if (fsync(fd))
159     error(SYSTEM, "failed fsync in flushPhotonHeap");
160 greg 2.17 #endif
161 rschregle 2.18
162 rschregle 2.15 pmap -> heapBufLen = 0;
163     }
164 greg 2.1
165 rschregle 2.15
166    
167 rschregle 2.18 #ifdef DEBUG_PMAP
168 rschregle 2.15 static int checkPhotonHeap (FILE *file)
169     /* Check heap for nonsensical or duplicate photons */
170     {
171     Photon p, lastp;
172     int i, dup;
173    
174     rewind(file);
175     memset(&lastp, 0, sizeof(lastp));
176 greg 2.1
177 rschregle 2.15 while (fread(&p, sizeof(p), 1, file)) {
178     dup = 1;
179    
180     for (i = 0; i <= 2; i++) {
181     if (p.pos [i] < thescene.cuorg [i] ||
182     p.pos [i] > thescene.cuorg [i] + thescene.cusize) {
183    
184     sprintf(errmsg, "corrupt photon in heap at [%f, %f, %f]\n",
185     p.pos [0], p.pos [1], p.pos [2]);
186     error(WARNING, errmsg);
187     }
188    
189     dup &= p.pos [i] == lastp.pos [i];
190     }
191    
192     if (dup) {
193     sprintf(errmsg,
194     "consecutive duplicate photon in heap at [%f, %f, %f]\n",
195     p.pos [0], p.pos [1], p.pos [2]);
196     error(WARNING, errmsg);
197     }
198     }
199    
200     return 0;
201 greg 2.1 }
202 rschregle 2.15 #endif
203 greg 2.1
204    
205    
206 rschregle 2.15 int newPhoton (PhotonMap* pmap, const RAY* ray)
207 greg 2.1 {
208 rschregle 2.19 unsigned i;
209 rschregle 2.15 Photon photon;
210 greg 2.1 COLOR photonFlux;
211    
212     /* Account for distribution ratio */
213     if (!pmap || pmapRandom(pmap -> randState) > pmap -> distribRatio)
214 rschregle 2.15 return -1;
215 greg 2.1
216     /* Don't store on sources */
217     if (ray -> robj > -1 && islight(objptr(ray -> ro -> omod) -> otype))
218 rschregle 2.15 return -1;
219 greg 2.1
220 rschregle 2.20 /* Ignore photon if modifier in/outside exclude/include set */
221 rschregle 2.19 if (ambincl != -1 && ray -> ro &&
222     ambincl != inset(ambset, ray -> ro -> omod))
223     return -1;
224    
225     if (pmapNumROI && pmapROI) {
226     unsigned inROI = 0;
227    
228     /* Store photon if within a region of interest (for ze Ecksperts!) */
229 rschregle 2.18 for (i = 0; !inROI && i < pmapNumROI; i++)
230     inROI = (ray -> rop [0] >= pmapROI [i].min [0] &&
231     ray -> rop [0] <= pmapROI [i].max [0] &&
232     ray -> rop [1] >= pmapROI [i].min [1] &&
233     ray -> rop [1] <= pmapROI [i].max [1] &&
234     ray -> rop [2] >= pmapROI [i].min [2] &&
235     ray -> rop [2] <= pmapROI [i].max [2]);
236 rschregle 2.19 if (!inROI)
237     return -1;
238 rschregle 2.18 }
239 rschregle 2.20
240 rschregle 2.19 /* Adjust flux according to distribution ratio and ray weight */
241 rschregle 2.21 copycolor(photonFlux, ray -> rcol);
242     #if 0
243     /* Factored out ray -> rweight as deprecated (?) for pmap, and infact
244     erroneously attenuates volume photon flux based on extinction,
245     which is already factored in by photonParticipate() */
246 rschregle 2.19 scalecolor(photonFlux,
247     ray -> rweight / (pmap -> distribRatio ? pmap -> distribRatio
248     : 1));
249 rschregle 2.21 #else
250     scalecolor(photonFlux,
251     1.0 / (pmap -> distribRatio ? pmap -> distribRatio : 1));
252     #endif
253 rschregle 2.19 setPhotonFlux(&photon, photonFlux);
254 rschregle 2.20
255 rschregle 2.19 /* Set photon position and flags */
256     VCOPY(photon.pos, ray -> rop);
257     photon.flags = 0;
258     photon.caustic = PMAP_CAUSTICRAY(ray);
259    
260     /* Set contrib photon's primary ray and subprocess index (the latter
261     * to linearise the primary ray indices after photon distribution is
262     * complete). Also set primary ray's source index, thereby marking it
263     * as used. */
264     if (isContribPmap(pmap)) {
265     photon.primary = pmap -> numPrimary;
266     photon.proc = PMAP_GETRAYPROC(ray);
267     pmap -> lastPrimary.srcIdx = ray -> rsrc;
268     }
269     else photon.primary = 0;
270    
271     /* Set normal */
272     for (i = 0; i <= 2; i++)
273     photon.norm [i] = 127.0 * (isVolumePmap(pmap) ? ray -> rdir [i]
274     : ray -> ron [i]);
275 rschregle 2.15
276 rschregle 2.19 if (!pmap -> heapBuf) {
277     /* Lazily allocate heap buffa */
278 rschregle 2.18 #if NIX
279 rschregle 2.19 /* Randomise buffa size to temporally decorellate flushes in
280     * multiprocessing mode */
281     srandom(randSeed + getpid());
282     pmap -> heapBufSize = PMAP_HEAPBUFSIZE * (0.5 + frandom());
283     #else
284     /* Randomisation disabled for single processes on WIN; also useful
285     * for reproducability during debugging */
286     pmap -> heapBufSize = PMAP_HEAPBUFSIZE;
287 rschregle 2.15 #endif
288 rschregle 2.19 if (!(pmap -> heapBuf = calloc(pmap -> heapBufSize, sizeof(Photon))))
289     error(SYSTEM, "failed heap buffer allocation in newPhoton");
290     pmap -> heapBufLen = 0;
291     }
292 rschregle 2.15
293 rschregle 2.19 /* Photon initialised; now append to heap buffa */
294     memcpy(pmap -> heapBuf + pmap -> heapBufLen, &photon, sizeof(Photon));
295    
296     if (++pmap -> heapBufLen >= pmap -> heapBufSize)
297     /* Heap buffa full, flush to heap file */
298     flushPhotonHeap(pmap);
299 greg 2.1
300 rschregle 2.19 pmap -> numPhotons++;
301 rschregle 2.21
302     /* Print photon attributes */
303     if (printPhoton)
304     /* Non-const kludge */
305     printPhoton((RAY*)ray, &photon, pmap);
306 greg 2.1
307 rschregle 2.15 return 0;
308 greg 2.1 }
309    
310    
311    
312 rschregle 2.15 void buildPhotonMap (PhotonMap *pmap, double *photonFlux,
313     PhotonPrimaryIdx *primaryOfs, unsigned nproc)
314     {
315     unsigned long n, nCheck = 0;
316     unsigned i;
317     Photon *p;
318     COLOR flux;
319 rschregle 2.18 char nuHeapFname [sizeof(PMAP_TMPFNAME)];
320 rschregle 2.15 FILE *nuHeap;
321     /* Need double here to reduce summation errors */
322     double avgFlux [3] = {0, 0, 0}, CoG [3] = {0, 0, 0}, CoGdist = 0;
323     FVECT d;
324    
325     if (!pmap)
326     error(INTERNAL, "undefined photon map in buildPhotonMap");
327    
328     /* Get number of photons from heapfile size */
329 rschregle 2.18 if (fseek(pmap -> heap, 0, SEEK_END) < 0)
330     error(SYSTEM, "failed seek to end of photon heap in buildPhotonMap");
331 rschregle 2.15 pmap -> numPhotons = ftell(pmap -> heap) / sizeof(Photon);
332    
333     if (!pmap -> numPhotons)
334     error(INTERNAL, "empty photon map in buildPhotonMap");
335    
336     if (!pmap -> heap)
337     error(INTERNAL, "no heap in buildPhotonMap");
338    
339     #ifdef DEBUG_PMAP
340     eputs("Checking photon heap consistency...\n");
341     checkPhotonHeap(pmap -> heap);
342    
343     sprintf(errmsg, "Heap contains %ld photons\n", pmap -> numPhotons);
344     eputs(errmsg);
345     #endif
346 rschregle 2.18
347 rschregle 2.15 /* Allocate heap buffa */
348     if (!pmap -> heapBuf) {
349     pmap -> heapBufSize = PMAP_HEAPBUFSIZE;
350     pmap -> heapBuf = calloc(pmap -> heapBufSize, sizeof(Photon));
351     if (!pmap -> heapBuf)
352     error(SYSTEM, "failed to allocate postprocessed photon heap in"
353     "buildPhotonMap");
354 greg 2.1 }
355    
356 rschregle 2.15 /* We REALLY don't need yet another @%&*! heap just to hold the scaled
357     * photons, but can't think of a quicker fix... */
358 rschregle 2.18 mktemp(strcpy(nuHeapFname, PMAP_TMPFNAME));
359     if (!(nuHeap = fopen(nuHeapFname, "w+b")))
360 rschregle 2.15 error(SYSTEM, "failed to open postprocessed photon heap in "
361     "buildPhotonMap");
362    
363     rewind(pmap -> heap);
364    
365     #ifdef DEBUG_PMAP
366     eputs("Postprocessing photons...\n");
367     #endif
368 greg 2.1
369 rschregle 2.18 while (!feof(pmap -> heap)) {
370     #ifdef DEBUG_PMAP
371     printf("Reading %lu at %lu... ", pmap -> heapBufSize, ftell(pmap->heap));
372     #endif
373 rschregle 2.15 pmap -> heapBufLen = fread(pmap -> heapBuf, sizeof(Photon),
374 rschregle 2.18 pmap -> heapBufSize, pmap -> heap);
375     #ifdef DEBUG_PMAP
376     printf("Got %lu\n", pmap -> heapBufLen);
377     #endif
378    
379     if (ferror(pmap -> heap))
380     error(SYSTEM, "failed to read photon heap in buildPhotonMap");
381 rschregle 2.15
382 rschregle 2.18 for (n = pmap -> heapBufLen, p = pmap -> heapBuf; n; n--, p++) {
383     /* Update min and max pos and set photon flux */
384     for (i = 0; i <= 2; i++) {
385     if (p -> pos [i] < pmap -> minPos [i])
386     pmap -> minPos [i] = p -> pos [i];
387     else if (p -> pos [i] > pmap -> maxPos [i])
388     pmap -> maxPos [i] = p -> pos [i];
389    
390     /* Update centre of gravity with photon position */
391     CoG [i] += p -> pos [i];
392     }
393    
394     if (primaryOfs)
395     /* Linearise photon primary index from subprocess index using the
396     * per-subprocess offsets in primaryOfs */
397     p -> primary += primaryOfs [p -> proc];
398    
399     /* Scale photon's flux (hitherto normalised to 1 over RGB); in
400     * case of a contrib photon map, this is done per light source,
401     * and photonFlux is assumed to be an array */
402 rschregle 2.20 getPhotonFlux(p, flux);
403 rschregle 2.18
404     if (photonFlux) {
405     scalecolor(flux, photonFlux [isContribPmap(pmap) ?
406     photonSrcIdx(pmap, p) : 0]);
407     setPhotonFlux(p, flux);
408 greg 2.1 }
409 rschregle 2.18
410     /* Update average photon flux; need a double here */
411     addcolor(avgFlux, flux);
412     }
413 greg 2.1
414 rschregle 2.18 /* Write modified photons to new heap */
415     fwrite(pmap -> heapBuf, sizeof(Photon), pmap -> heapBufLen, nuHeap);
416 rschregle 2.15
417 rschregle 2.18 if (ferror(nuHeap))
418     error(SYSTEM, "failed postprocessing photon flux in "
419     "buildPhotonMap");
420 rschregle 2.15
421     nCheck += pmap -> heapBufLen;
422     }
423    
424     #ifdef DEBUG_PMAP
425     if (nCheck < pmap -> numPhotons)
426     error(INTERNAL, "truncated photon heap in buildPhotonMap");
427     #endif
428    
429     /* Finalise average photon flux */
430     scalecolor(avgFlux, 1.0 / pmap -> numPhotons);
431     copycolor(pmap -> photonFlux, avgFlux);
432    
433     /* Average photon positions to get centre of gravity */
434     for (i = 0; i < 3; i++)
435     pmap -> CoG [i] = CoG [i] /= pmap -> numPhotons;
436    
437     rewind(pmap -> heap);
438    
439     /* Compute average photon distance to centre of gravity */
440     while (!feof(pmap -> heap)) {
441     pmap -> heapBufLen = fread(pmap -> heapBuf, sizeof(Photon),
442 rschregle 2.18 pmap -> heapBufSize, pmap -> heap);
443 rschregle 2.15
444 rschregle 2.18 for (n = pmap -> heapBufLen, p = pmap -> heapBuf; n; n--, p++) {
445     VSUB(d, p -> pos, CoG);
446     CoGdist += DOT(d, d);
447     }
448 rschregle 2.15 }
449    
450     pmap -> CoGdist = CoGdist /= pmap -> numPhotons;
451    
452 rschregle 2.18 /* Swap heaps, discarding unscaled photons */
453 rschregle 2.15 fclose(pmap -> heap);
454 rschregle 2.18 unlink(pmap -> heapFname);
455 rschregle 2.15 pmap -> heap = nuHeap;
456 rschregle 2.18 strcpy(pmap -> heapFname, nuHeapFname);
457 rschregle 2.15
458     #ifdef PMAP_OOC
459     OOC_BuildPhotonMap(pmap, nproc);
460     #else
461     kdT_BuildPhotonMap(pmap);
462     #endif
463    
464     /* Trash heap and its buffa */
465     free(pmap -> heapBuf);
466     fclose(pmap -> heap);
467 rschregle 2.18 unlink(pmap -> heapFname);
468 rschregle 2.15 pmap -> heap = NULL;
469     pmap -> heapBuf = NULL;
470 greg 2.1 }
471    
472    
473    
474     /* Dynamic max photon search radius increase and reduction factors */
475     #define PMAP_MAXDIST_INC 4
476     #define PMAP_MAXDIST_DEC 0.9
477    
478     /* Num successful lookups before reducing in max search radius */
479     #define PMAP_MAXDIST_CNT 1000
480    
481     /* Threshold below which we assume increasing max radius won't help */
482     #define PMAP_SHORT_LOOKUP_THRESH 1
483    
484 rschregle 2.8 /* Coefficient for adaptive maximum search radius */
485     #define PMAP_MAXDIST_COEFF 100
486    
487 greg 2.1 void findPhotons (PhotonMap* pmap, const RAY* ray)
488     {
489     int redo = 0;
490    
491 rschregle 2.15 if (!pmap -> squeue.len) {
492 greg 2.1 /* Lazy init priority queue */
493 rschregle 2.15 #ifdef PMAP_OOC
494     OOC_InitFindPhotons(pmap);
495     #else
496     kdT_InitFindPhotons(pmap);
497     #endif
498 greg 2.1 pmap -> minGathered = pmap -> maxGather;
499     pmap -> maxGathered = pmap -> minGather;
500     pmap -> totalGathered = 0;
501     pmap -> numLookups = pmap -> numShortLookups = 0;
502     pmap -> shortLookupPct = 0;
503     pmap -> minError = FHUGE;
504     pmap -> maxError = -FHUGE;
505     pmap -> rmsError = 0;
506 rschregle 2.9 /* SQUARED max search radius limit is based on avg photon distance to
507 rschregle 2.8 * centre of gravity, unless fixed by user (maxDistFix > 0) */
508 rschregle 2.15 pmap -> maxDist0 = pmap -> maxDist2Limit =
509 rschregle 2.9 maxDistFix > 0 ? maxDistFix * maxDistFix
510 rschregle 2.15 : PMAP_MAXDIST_COEFF * pmap -> squeue.len *
511     pmap -> CoGdist / pmap -> numPhotons;
512 greg 2.1 }
513    
514     do {
515 rschregle 2.15 pmap -> squeue.tail = 0;
516     pmap -> maxDist2 = pmap -> maxDist0;
517 greg 2.1
518     /* Search position is ray -> rorg for volume photons, since we have no
519     intersection point. Normals are ignored -- these are incident
520 rschregle 2.22 directions). */
521     /* NOTE: status returned by XXX_FindPhotons() is currently ignored;
522     if no photons are found, an empty queue is returned under the
523     assumption all photons are too distant to contribute significant
524     flux. */
525 greg 2.1 if (isVolumePmap(pmap)) {
526 rschregle 2.15 #ifdef PMAP_OOC
527     OOC_FindPhotons(pmap, ray -> rorg, NULL);
528     #else
529     kdT_FindPhotons(pmap, ray -> rorg, NULL);
530     #endif
531 greg 2.1 }
532     else {
533 rschregle 2.15 #ifdef PMAP_OOC
534     OOC_FindPhotons(pmap, ray -> rop, ray -> ron);
535     #else
536     kdT_FindPhotons(pmap, ray -> rop, ray -> ron);
537     #endif
538 greg 2.1 }
539 rschregle 2.3
540 rschregle 2.15 #ifdef PMAP_LOOKUP_INFO
541     fprintf(stderr, "%d/%d %s photons found within radius %.3f "
542     "at (%.2f,%.2f,%.2f) on %s\n", pmap -> squeue.tail,
543     pmap -> squeue.len, pmapName [pmap -> type], sqrt(pmap -> maxDist2),
544     ray -> rop [0], ray -> rop [1], ray -> rop [2],
545     ray -> ro ? ray -> ro -> oname : "<null>");
546     #endif
547    
548     if (pmap -> squeue.tail < pmap -> squeue.len * pmap -> gatherTolerance) {
549 greg 2.1 /* Short lookup; too few photons found */
550 rschregle 2.15 if (pmap -> squeue.tail > PMAP_SHORT_LOOKUP_THRESH) {
551 greg 2.1 /* Ignore short lookups which return fewer than
552     * PMAP_SHORT_LOOKUP_THRESH photons under the assumption there
553     * really are no photons in the vicinity, and increasing the max
554     * search radius therefore won't help */
555 rschregle 2.8 #ifdef PMAP_LOOKUP_WARN
556 greg 2.1 sprintf(errmsg,
557     "%d/%d %s photons found at (%.2f,%.2f,%.2f) on %s",
558 rschregle 2.15 pmap -> squeue.tail, pmap -> squeue.len,
559     pmapName [pmap -> type],
560     ray -> rop [0], ray -> rop [1], ray -> rop [2],
561 greg 2.1 ray -> ro ? ray -> ro -> oname : "<null>");
562     error(WARNING, errmsg);
563 rschregle 2.8 #endif
564 rschregle 2.3
565 rschregle 2.8 /* Bail out after warning if maxDist is fixed */
566     if (maxDistFix > 0)
567     return;
568    
569 rschregle 2.15 if (pmap -> maxDist0 < pmap -> maxDist2Limit) {
570 greg 2.1 /* Increase max search radius if below limit & redo search */
571     pmap -> maxDist0 *= PMAP_MAXDIST_INC;
572 rschregle 2.8 #ifdef PMAP_LOOKUP_REDO
573 greg 2.1 redo = 1;
574 rschregle 2.8 #endif
575     #ifdef PMAP_LOOKUP_WARN
576 greg 2.1 sprintf(errmsg,
577     redo ? "restarting photon lookup with max radius %.1e"
578     : "max photon lookup radius adjusted to %.1e",
579 rschregle 2.15 pmap -> maxDist0);
580 greg 2.1 error(WARNING, errmsg);
581 rschregle 2.8 #endif
582 greg 2.1 }
583 rschregle 2.8 #ifdef PMAP_LOOKUP_REDO
584 greg 2.1 else {
585     sprintf(errmsg, "max photon lookup radius clamped to %.1e",
586 rschregle 2.15 pmap -> maxDist0);
587 greg 2.1 error(WARNING, errmsg);
588     }
589 rschregle 2.8 #endif
590 greg 2.1 }
591    
592     /* Reset successful lookup counter */
593     pmap -> numLookups = 0;
594 rschregle 2.3 }
595 greg 2.1 else {
596 rschregle 2.8 /* Bail out after warning if maxDist is fixed */
597     if (maxDistFix > 0)
598     return;
599    
600 greg 2.1 /* Increment successful lookup counter and reduce max search radius if
601     * wraparound */
602     pmap -> numLookups = (pmap -> numLookups + 1) % PMAP_MAXDIST_CNT;
603     if (!pmap -> numLookups)
604     pmap -> maxDist0 *= PMAP_MAXDIST_DEC;
605    
606     redo = 0;
607     }
608 rschregle 2.8
609 greg 2.1 } while (redo);
610     }
611    
612    
613    
614 rschregle 2.22 Photon *find1Photon (PhotonMap *pmap, const RAY* ray, Photon *photon)
615 rschregle 2.15 {
616 rschregle 2.22 /* Init (squared) search radius to avg photon dist to centre of gravity */
617     float maxDist2_0 = pmap -> CoGdist;
618     int found = 0;
619     #ifdef PMAP_LOOKUP_REDO
620     #define REDO 1
621     #else
622     #define REDO 0
623     #endif
624 greg 2.1
625 rschregle 2.22 do {
626     pmap -> maxDist2 = maxDist2_0;
627 rschregle 2.15 #ifdef PMAP_OOC
628 rschregle 2.22 found = OOC_Find1Photon(pmap, ray -> rop, ray -> ron, photon);
629 rschregle 2.15 #else
630 rschregle 2.22 found = kdT_Find1Photon(pmap, ray -> rop, ray -> ron, photon);
631     #endif
632     if (found < 0) {
633     /* Expand search radius to retry */
634     maxDist2_0 *= 2;
635     #ifdef PMAP_LOOKUP_WARN
636     sprintf(errmsg, "failed 1-NN photon lookup"
637     #ifdef PMAP_LOOKUP_REDO
638     ", retrying with search radius %.2f", maxDist2_0
639     #endif
640     );
641     error(WARNING, errmsg);
642     #endif
643     }
644     } while (REDO && found < 0);
645    
646     /* Return photon buffer containing valid photon, else NULL */
647     return found < 0 ? NULL : photon;
648 greg 2.1 }
649    
650    
651    
652 rschregle 2.15 void getPhoton (PhotonMap *pmap, PhotonIdx idx, Photon *photon)
653 greg 2.1 {
654 rschregle 2.15 #ifdef PMAP_OOC
655 rschregle 2.18 if (OOC_GetPhoton(pmap, idx, photon))
656 rschregle 2.15 #else
657     if (kdT_GetPhoton(pmap, idx, photon))
658     #endif
659     error(INTERNAL, "failed photon lookup");
660 greg 2.1 }
661    
662    
663    
664 rschregle 2.15 Photon *getNearestPhoton (const PhotonSearchQueue *squeue, PhotonIdx idx)
665     {
666     #ifdef PMAP_OOC
667     return OOC_GetNearestPhoton(squeue, idx);
668     #else
669     return kdT_GetNearestPhoton(squeue, idx);
670     #endif
671 greg 2.1 }
672    
673    
674    
675 rschregle 2.15 PhotonIdx firstPhoton (const PhotonMap *pmap)
676     {
677     #ifdef PMAP_OOC
678     return OOC_FirstPhoton(pmap);
679     #else
680     return kdT_FirstPhoton(pmap);
681     #endif
682 greg 2.1 }
683    
684    
685    
686     void deletePhotons (PhotonMap* pmap)
687     {
688 rschregle 2.15 #ifdef PMAP_OOC
689     OOC_Delete(&pmap -> store);
690     #else
691     kdT_Delete(&pmap -> store);
692     #endif
693    
694     free(pmap -> squeue.node);
695 greg 2.1 free(pmap -> biasCompHist);
696    
697 rschregle 2.15 pmap -> numPhotons = pmap -> minGather = pmap -> maxGather =
698     pmap -> squeue.len = pmap -> squeue.tail = 0;
699 greg 2.1 }