00001 #include <esg/energy/PhotonMap.h>
00002
00003 using namespace esg;
00004
00005 #define swap(ph,a,b) { Photon *ph2=ph[a]; ph[a]=ph[b]; ph[b]=ph2; }
00006
00007 void PhotonMap::_build(const vector<Photon>& photons)
00008 {
00009 _storedPhotons = photons.size();
00010
00011 #ifdef WIN32
00012 _map = (Photon*) malloc((_storedPhotons+1) * sizeof(Photon));
00013 #else
00014 _map = new Photon [_storedPhotons+1];
00015 #endif
00016
00017 if (!_map) {
00018 _storedPhotons = 0;
00019 fprintf(stderr,"PhotonMap::_build(): Out of memory initializing photon map\n");
00020 return;
00021 }
00022
00023 _bboxMin[0] = _bboxMin[1] = _bboxMin[2] = 1e8f;
00024 _bboxMax[0] = _bboxMax[1] = _bboxMax[2] = -1e8f;
00025
00026 for (int i = 0; i < photons.size(); i++) {
00027 _map[i] = photons[i];
00028 for (register unsigned j = 0; j < 3; j++) {
00029 if (photons[i]._position[j] < _bboxMin[j])
00030 _bboxMin[j] = photons[i]._position[j];
00031 if (photons[i]._position[j] > _bboxMax[j])
00032 _bboxMax[j] = photons[i]._position[j];
00033 }
00034 }
00035
00036
00037
00038
00039
00040
00041
00042 if (_storedPhotons <= 1) return;
00043
00044
00045 Photon **pa1 = (Photon**) malloc(sizeof(Photon*)*(_storedPhotons+1));
00046 Photon **pa2 = (Photon**) malloc(sizeof(Photon*)*(_storedPhotons+1));
00047
00048 for (register unsigned i = 0; i <= _storedPhotons; i++) pa2[i] = &_map[i];
00049
00050 _balance_segment(pa1, pa2, 1, 1, _storedPhotons);
00051 free(pa2);
00052
00053
00054 unsigned d, j=1, foo=1;
00055 Photon foo_photon = _map[j];
00056
00057 for (register unsigned i = 1; i <= _storedPhotons; i++) {
00058 d = pa1[j] - _map;
00059 pa1[j] = NULL;
00060 if (d != foo)
00061 _map[j] = _map[d];
00062 else {
00063 _map[j] = foo_photon;
00064 if (i < _storedPhotons) {
00065 for (; foo <= _storedPhotons; foo++)
00066 if (pa1[foo] != NULL) break;
00067 foo_photon = _map[foo];
00068 j = foo;
00069 }
00070 continue;
00071 }
00072 j = d;
00073 }
00074 free(pa1);
00075 }
00076
00077
00078
00079
00080
00081
00082
00083 void PhotonMap::_median_split(Photon **p, int start,
00084 int end, int median, int axis)
00085 {
00086 int left = start;
00087 int right = end;
00088
00089 while (right > left) {
00090 float v = p[right]->_position[axis];
00091 int i = left - 1;
00092 int j = right;
00093 for (;;) {
00094 while (p[++i]->_position[axis] < v);
00095 while (p[--j]->_position[axis] > v && j>left);
00096 if (i >= j) break;
00097 swap(p, i, j);
00098 }
00099
00100 swap(p, i, right);
00101 if (i >= median) right = i - 1;
00102 if (i <= median) left = i + 1;
00103 }
00104 }
00105
00106
00107
00108
00109 void PhotonMap::_balance_segment(Photon **pbal, Photon **porg,
00110 int index, int start, int end )
00111 {
00112
00113
00114
00115
00116 int median = 1;
00117 while ((4*median) <= (end-start+1))
00118 median += median;
00119
00120 if ((3*median) <= (end-start+1)) {
00121 median += median;
00122 median += start-1;
00123 } else
00124 median = end-median+1;
00125
00126
00127
00128
00129
00130 int axis=2;
00131 if ((_bboxMax[0] - _bboxMin[0]) > (_bboxMax[1] - _bboxMin[1]) &&
00132 (_bboxMax[0] - _bboxMin[0]) > (_bboxMax[2] - _bboxMin[2]))
00133 axis=0;
00134 else if ((_bboxMax[1] - _bboxMin[1]) > (_bboxMax[2] - _bboxMin[2]))
00135 axis=1;
00136
00137
00138
00139
00140
00141 _median_split(porg, start, end, median, axis);
00142
00143 pbal[index] = porg[median];
00144 pbal[index]->_plane = axis;
00145
00146
00147
00148
00149
00150 if (median > start) {
00151
00152 if (start < median-1) {
00153 float tmp = _bboxMax[axis];
00154 _bboxMax[axis] = pbal[index]->_position[axis];
00155 _balance_segment(pbal, porg, 2*index, start, median-1);
00156 _bboxMax[axis] = tmp;
00157 } else {
00158 pbal[2*index] = porg[start];
00159 }
00160 }
00161
00162 if (median < end) {
00163
00164 if (median+1 < end) {
00165 float tmp = _bboxMin[axis];
00166 _bboxMin[axis] = pbal[index]->_position[axis];
00167 _balance_segment(pbal, porg, 2*index+1, median+1, end);
00168 _bboxMin[axis] = tmp;
00169 } else {
00170 pbal[2*index+1] = porg[end];
00171 }
00172 }
00173 }
00174
00175 void PhotonMap::_locate_photons(NearestPhotons * const np,
00176 unsigned index) const
00177 {
00178 const Photon* p = &(np->photons[index]);
00179 float dist1;
00180 unsigned i2;
00181
00182 if (index < np->halfStoredPhotons) {
00183 dist1 = np->pos[p->_plane] - p->_position[p->_plane];
00184 i2 = 2 * index;
00185
00186 if (dist1 > 0.) {
00187 _locate_photons(np, i2+1);
00188 if (dist1*dist1 < np->dist2[0]) _locate_photons(np, i2);
00189 } else {
00190 _locate_photons(np, i2);
00191 if (dist1*dist1 < np->dist2[0]) _locate_photons(np, i2+1);
00192 }
00193 }
00194
00195
00196 dist1 = p->_position[0] - np->pos[0];
00197 float dist2 = dist1*dist1;
00198 dist1 = p->_position[1] - np->pos[1];
00199 dist2 += dist1*dist1;
00200 dist1 = p->_position[2] - np->pos[2];
00201 dist2 += dist1*dist1;
00202
00203 if (dist2 < np->dist2[0]) {
00204
00205
00206 if (np->found < np->max) {
00207
00208 np->found++;
00209 np->dist2[np->found] = dist2;
00210 np->index[np->found] = p;
00211 } else {
00212 int j, parent;
00213
00214 if (!np->gotHeap) {
00215
00216 float dst2;
00217 const Photon *phot;
00218 int half_found = np->found>>1;
00219 for (int k = half_found; k >= 1; k--) {
00220 parent=k;
00221 phot = np->index[k];
00222 dst2 = np->dist2[k];
00223 while (parent <= half_found) {
00224 j = parent+parent;
00225 if (j<np->found && np->dist2[j]<np->dist2[j+1]) j++;
00226 if (dst2 >= np->dist2[j]) break;
00227 np->dist2[parent] = np->dist2[j];
00228 np->index[parent] = np->index[j];
00229 parent=j;
00230 }
00231 np->dist2[parent] = dst2;
00232 np->index[parent] = phot;
00233 }
00234 np->gotHeap = true;
00235 }
00236
00237
00238
00239
00240 parent=1;
00241 j = 2;
00242 while (j <= np->found) {
00243 if (j < np->found && np->dist2[j] < np->dist2[j+1] ) j++;
00244 if (dist2 > np->dist2[j]) break;
00245 np->dist2[parent] = np->dist2[j];
00246 np->index[parent] = np->index[j];
00247 parent = j;
00248 j += j;
00249 }
00250 np->index[parent] = p;
00251 np->dist2[parent] = dist2;
00252 np->dist2[0] = np->dist2[1];
00253 }
00254 }
00255 }
00256
00257
00258
00259
00260
00261
00262
00263 PhotonMap::PhotonMap()
00264 : _map(NULL), _storedPhotons(0)
00265 {
00266 _bboxMin[0] = _bboxMin[1] = _bboxMin[2] = 1e8f;
00267 _bboxMax[0] = _bboxMax[1] = _bboxMax[2] = -1e8f;
00268 }
00269
00270 PhotonMap::PhotonMap(const vector<Photon>& photons)
00271 : _map(NULL), _storedPhotons(0)
00272 {
00273 _build(photons);
00274 }
00275
00276 PhotonMap::~PhotonMap()
00277 {
00278 if (_map) delete [] _map;
00279 }
00280
00281 void PhotonMap::set(const vector<Photon>& photons)
00282 {
00283 if (_map) delete [] _map;
00284 _build(photons);
00285 }
00286
00287 unsigned PhotonMap::numPhotons() const
00288 {
00289 return _storedPhotons;
00290 }
00291
00292 vector<Photon*>* PhotonMap::getNeighbourhood(const Vector3& spoint,
00293 const Vector3* snormal,
00294 float maxdist,
00295 unsigned nphotons) const
00296 {
00297 if (_storedPhotons == 0) return NULL;
00298 NearestPhotons* np = new NearestPhotons(nphotons, spoint, maxdist,
00299 _map, _storedPhotons/2 - 1);
00300 _locate_photons(np, 1);
00301
00302 if (np->found < 8) {
00303 delete np;
00304 return NULL;
00305 }
00306
00307 vector<Photon*> * ret = new vector<Photon*>();
00308 for (int i = 0; i < np->numPhotons(); i++) {
00309 if (snormal) {
00310 if (snormal->dot((*np)(i).getDirection()) > 0.) {
00311 ret->push_back(&(*np)(i));
00312 }
00313 } else {
00314 ret->push_back(&(*np)(i));
00315 }
00316 }
00317 delete np;
00318 return ret;
00319 }
00320
00321 bool PhotonMap::getIrradiance(const Vector3& spoint,
00322 const Vector3* snormal,
00323 float maxdist,
00324 unsigned nphotons,
00325 Vector3& irrad) const
00326 {
00327 irrad.set(0.0, 0.0, 0.0);
00328 if (_storedPhotons == 0) return false;
00329 NearestPhotons* np = new NearestPhotons(nphotons, spoint, maxdist,
00330 _map, _storedPhotons/2 - 1);
00331 _locate_photons(np, 1);
00332
00333 if (np->found < 8) {
00334 delete np;
00335 return false;
00336 }
00337
00338 for (int i = 0; i < np->numPhotons(); i++) {
00339 if (snormal) {
00340 if (snormal->dot((*np)(i).getDirection()) > 0.)
00341 irrad.add((*np)(i)._power);
00342 } else {
00343 irrad.add((*np)(i)._power);
00344 }
00345 }
00346 irrad.scale(1. / (M_PI * maxdist * maxdist));
00347 delete np;
00348 return true;
00349 }