1 #ifndef PHOTONKDTREE
2 #define PHOTONKDTREE
3
4 #include "Photon.hxx"
5 #include "PhotonHeap.hxx"
6 #include <fcntl.h>
7 #include <sys/mman.h>
8
9 // A helper class to compare photon positions according to the given dimension
10 class PhotonCompare
11 {
12 // Dimension in which 'less' is tested
13 int dimension;
14
15 public:
16 PhotonCompare(int dimension)
17 : dimension(dimension)
18 {};
19
20 bool operator()(const Photon *less, const Photon *greater) const
21 {
22 // Special case: If the same point is hit twice , the addresses are compared
23 // (Otherwise there could be maldefined split locations!)
24 if (less->point[dimension] == greater->point[dimension])
25 return (less < greater);
26
27 return (less->point[dimension] < greater->point[dimension]);
28 };
29 };
30
31 // A helper class to compare photon positions against a given reference point, according to the distance
32 class PhotonDistanceCompare
33 {
34 Vec3f point;
35 public:
36 PhotonDistanceCompare(Vec3f point)
37 : point(point)
38 {};
39
40 bool operator()(const Photon *less, const Photon *greater) const
41 {
42 Vec3f lconn = less->point - point,
43 gconn = greater->point - point;
44 float ldist = Dot(lconn, lconn),
45 gdist = Dot(gconn, gconn);
46
47 // Special case: If the same point is hit twice , the addresses are compared
48 // (Otherwise there could be maldefined split locations!)
49 if (ldist == gdist)
50 return (less < greater);
51
52 return (ldist < gdist);
53 };
54 };
55
56 // The tree itself
57 class PhotonKDTree
58 {
59 public:
60 Photon *resident;
61 PhotonKDTree *less,
62 *more;
63 int count,
64 dimension;
65
66 PhotonKDTree()
67 : resident(NULL), less(NULL), more(NULL), count(0), dimension(0)
68 {};
69
70 PhotonKDTree(Photon *newone)
71 : resident(newone), less(NULL), more(NULL), count(1), dimension(0)
72 {};
73
74 PhotonKDTree(vector<Photon*> &list, int from = 0, int to = -1)
75 : resident(NULL), less(NULL), more(NULL), count(0), dimension(0)
76 {
77 // -1 makes the method detect the to automatically
78 if (to == -1)
79 to = list.size() - 1;
80
81 count = to - from + 1;
82
83 Vec3f minimum = Vec3f( Infinity),
84 maximum = Vec3f(-Infinity);
85
86 // Get the split dimension
87 for (int i = from; i <= to; ++i)
88 {
89 minimum = Min(minimum, list[i]->point);
90 maximum = Max(maximum, list[i]->point);
91 }
92
93 float distance = 0.0f,
94 newdistance;
95 for (int i = 0; i < 3; ++i)
96 {
97 newdistance = maximum[i] - minimum[i];
98 if (newdistance > distance)
99 {
100 distance = newdistance;
101 dimension = i;
102 }
103 }
104
105 // Sort the list partially (into two halfs)
106 int middle = (to + from) / 2;
107 nth_element(&list[from], &list[middle], &list[to], PhotonCompare(dimension));
108
109 // And split it recursively into two subtrees
110 resident = list[middle];
111
112 if (middle - 1 >= from)
113 less = new PhotonKDTree(list, from, middle - 1);
114
115 if (middle + 1 <= to)
116 more = new PhotonKDTree(list, middle + 1, to);
117 };
118
119 // Loads a KD tree from a file
120 PhotonKDTree(string filename)
121 : resident(NULL), less(NULL), more(NULL), count(0), dimension(0)
122 {
123 int fd = open(filename.c_str(), O_RDONLY, (mode_t)0600);
124 if (fd == -1)
125 {
126 cerr << "Could not open PhotonMap file [pass 1]!" << endl;
127 exit(0);
128 }
129
130 char photonword[10] = " ";
131 read(fd, photonword, 9);
132
133 if (strcmp(photonword, "PHOTONMAP"))
134 {
135 cerr << "Wrong file format!" << endl;
136 exit(0);
137 }
138
139 int count;
140 read(fd, &count, sizeof(int));
141 close(fd);
142
143 // Be aware of wild pointer arithmetics! ;-)
144 void *map;
145 int photonsize = 3 * sizeof(Vec3f);
146 int filesize = 9 // The word "PHOTONMAP"
147 + count * (3 * sizeof(int) + photonsize); // Node entries
148
149 fd = open(filename.c_str(), O_RDONLY, (mode_t)0600);
150 if (fd == -1)
151 {
152 cerr << "Could not open PhotonMap file [pass 2]!" << endl;
153 exit(0);
154 }
155
156 // Map the file into virtual memory
157 map = mmap(0, filesize, PROT_READ, MAP_SHARED, fd, 0);
158 if (map == MAP_FAILED)
159 {
160 close(fd);
161 cerr << "Could not mmap PhotonMap file!" << endl;
162 exit(0);
163 }
164
165 BuildTree(reinterpret_cast<char*>(map) + 9, photonsize);
166
167 // Unmap the file again
168 if (munmap(map, filesize) == -1)
169 cerr << "Could not munmap PhotonMap file!" << endl;
170
171 close(fd);
172
173 };
174
175 // Deserializer, building the corresponding tree
176 PhotonKDTree(char *pointer, int photonsize)
177 : resident(NULL), less(NULL), more(NULL), count(0), dimension(0)
178 {
179 BuildTree(pointer, photonsize);
180 };
181
182 virtual ~PhotonKDTree(){};
183
184 virtual void BuildTree(char *pointer, int photonsize)
185 {
186 int lcount;
187 memmove(&count, pointer , sizeof(int));
188 memmove(&dimension, pointer + sizeof(int), sizeof(int));
189 memmove(&lcount, pointer + 2 * sizeof(int), sizeof(int));
190
191 resident = new Photon(pointer + 3 * sizeof(int));
192
193 int offset = 3 * sizeof(int) + photonsize;
194
195 if (lcount > 0)
196 less = new PhotonKDTree(pointer + offset, photonsize);
197
198 if (count - lcount > 1)
199 more = new PhotonKDTree(pointer + offset * (1 + lcount), photonsize);
200 };
201
202 // Serializes this current part of the tree into a virtual memory range
203 virtual void Serialize(char *pointer, int photonsize)
204 {
205 int lcount = (less) ? less->count : 0;
206
207 memmove(pointer , &count, sizeof(int));
208 memmove(pointer + sizeof(int), &dimension, sizeof(int));
209 memmove(pointer + 2 * sizeof(int), &lcount, sizeof(int));
210
211 resident->Serialize(pointer + 3 * sizeof(int));
212
213 int offset = 3 * sizeof(int) + photonsize;
214
215 if (less)
216 less->Serialize(pointer + offset, photonsize);
217
218 if (more)
219 more->Serialize(pointer + offset * (1 + lcount), photonsize);
220 }
221
222 // Stores the KD tree to a file
223 virtual void Save(string filename)
224 {
225 // Be aware of wild pointer arithmetics! ;-)
226 cout << "INFO: The tree contains " << count << " photons that will now be stored..." << endl;
227
228 void *map;
229 int photonsize = 3 * sizeof(Vec3f);
230 int filesize = 9 // The word "PHOTONMAP"
231 + count * (3 * sizeof(int) + photonsize); // Node entries
232
233 int fd = open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
234 if (fd == -1)
235 {
236 cerr << "Could not open PhotonMap file!" << endl;
237 exit(0);
238 }
239
240 // Resize the file to required needs
241 int result = lseek(fd, filesize - 1, SEEK_SET);
242 if (result == -1)
243 {
244 close(fd);
245 cerr << "Could not resize PhotonMap file [seek]!" << endl;
246 exit(0);
247 }
248
249 result = write(fd, "", 1);
250 if (result != 1)
251 {
252 close(fd);
253 cerr << "Could not resize PhotonMap file [write]!" << endl;
254 exit(0);
255 }
256
257 // Map the file into virtual memory
258 map = mmap(0, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
259 if (map == MAP_FAILED)
260 {
261 close(fd);
262 cerr << "Could not mmap PhotonMap file!" << endl;
263 exit(0);
264 }
265
266 char photonword[10] = "PHOTONMAP";
267 memmove(map, photonword, 9);
268 Serialize(reinterpret_cast<char*>(map) + 9, photonsize);
269
270 // Unmap the file again
271 if (munmap(map, filesize) == -1)
272 cerr << "Could not munmap PhotonMap file!" << endl
273 << "The file may be corrupted..." << endl;
274
275 close(fd);
276 };
277
278 // Get the neighborhood (to calculate the radiance estimate)
279 virtual void GetNextPhotons(PhotonHeap &heap)
280 {
281 float distance = resident->point[dimension] - heap.reference[dimension];
282
283 if (less && distance >= 0)
284 {
285 less->GetNextPhotons(heap);
286
287 if (more && distance < heap.maxdist)
288 more->GetNextPhotons(heap);
289 }
290 else if (more && distance <= 0)
291 {
292 more->GetNextPhotons(heap);
293
294 if (less && -distance < heap.maxdist)
295 less->GetNextPhotons(heap);
296 }
297
298 // Insert the photon if it is close enough
299 DistantPhoton *dphoton = new DistantPhoton(resident, heap.reference);
300
301 if (dphoton->distance < heap.maxdist2)
302 heap.Insert(dphoton);
303 else
304 delete dphoton;
305 };
306
307 };
308
309 #endif
syntax highlighted by Code2HTML, v. 0.9.1