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