00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <cmath>
00013 #include "astro.h"
00014 #include "octree.h"
00015
00016 using namespace std;
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 enum
00034 {
00035 XPos = 1,
00036 YPos = 2,
00037 ZPos = 4,
00038 };
00039
00040
00041
00042
00043
00044
00045
00046 static const unsigned int splitThreshold = 100;
00047
00048 static const float sqrt3 = 1.732050808f;
00049
00050
00051 DynamicStarOctree::DynamicStarOctree(const Point3f& _center, float _absMag) :
00052 stars(NULL), children(NULL), center(_center), absMag(_absMag)
00053 {
00054 }
00055
00056 DynamicStarOctree::~DynamicStarOctree()
00057 {
00058 if (children != NULL)
00059 {
00060 for (int i = 0; i < 8; i++)
00061 {
00062 delete children[i];
00063 }
00064 delete [] children;
00065 }
00066 }
00067
00068
00069 static int childIndex(const Star& star, const Point3f& center)
00070 {
00071 Point3f pos = star.getPosition();
00072
00073 int child = 0;
00074 child |= pos.x < center.x ? 0 : XPos;
00075 child |= pos.y < center.y ? 0 : YPos;
00076 child |= pos.z < center.z ? 0 : ZPos;
00077
00078 return child;
00079 }
00080
00081
00082 inline bool
00083 starOrbitStraddlesNodes(const Star& star, const Point3f& center)
00084 {
00085 float orbitalRadius = star.getOrbitalRadius();
00086 if (orbitalRadius == 0.0f)
00087 return false;
00088
00089 Point3f starPos = star.getPosition();
00090 return (abs(starPos.x - center.x) < orbitalRadius ||
00091 abs(starPos.y - center.y) < orbitalRadius ||
00092 abs(starPos.z - center.z) < orbitalRadius);
00093 }
00094
00095
00096 void DynamicStarOctree::insertStar(const Star& star, float scale)
00097 {
00098
00099
00100
00101
00102
00103 if (star.getAbsoluteMagnitude() <= absMag ||
00104 starOrbitStraddlesNodes(star, center))
00105 {
00106 addStar(star);
00107 }
00108 else
00109 {
00110
00111
00112
00113
00114
00115
00116 if (children == NULL)
00117 {
00118
00119 if (stars != NULL && stars->size() >= splitThreshold)
00120 split(scale * 0.5f);
00121 addStar(star);
00122 }
00123 else
00124 {
00125
00126
00127 children[childIndex(star, center)]->insertStar(star, scale * 0.5f);
00128 }
00129 }
00130 }
00131
00132
00133 void DynamicStarOctree::addStar(const Star& star)
00134 {
00135 if (stars == NULL)
00136 stars = new vector<const Star*>();
00137 stars->insert(stars->end(), &star);
00138 }
00139
00140
00141 void DynamicStarOctree::split(float scale)
00142 {
00143 children = new DynamicStarOctree*[8];
00144 for (int i = 0; i < 8; i++)
00145 {
00146 Point3f p(center);
00147 p.x += ((i & XPos) != 0) ? scale : -scale;
00148 p.y += ((i & YPos) != 0) ? scale : -scale;
00149 p.z += ((i & ZPos) != 0) ? scale : -scale;
00150 children[i] = new DynamicStarOctree(p, astro::lumToAbsMag(astro::absMagToLum(absMag) / 4.0f));
00151 }
00152 sortStarsIntoChildNodes();
00153 }
00154
00155
00156
00157
00158
00159 void DynamicStarOctree::sortStarsIntoChildNodes()
00160 {
00161 int nBrightStars = 0;
00162
00163 for (unsigned int i = 0; i < stars->size(); i++)
00164 {
00165 const Star* star = (*stars)[i];
00166
00167 if (star->getAbsoluteMagnitude() <= absMag ||
00168 starOrbitStraddlesNodes(*star, center))
00169 {
00170
00171
00172
00173 (*stars)[nBrightStars] = (*stars)[i];
00174 nBrightStars++;
00175 }
00176 else
00177 {
00178
00179 children[childIndex(*star, center)]->addStar(*star);
00180 }
00181 }
00182
00183 stars->resize(nBrightStars);
00184 }
00185
00186
00187 void DynamicStarOctree::rebuildAndSort(StarOctree*& node, Star*& sortedStars)
00188 {
00189 Star* firstStar = sortedStars;
00190
00191 if (stars != NULL)
00192 {
00193 for (vector<const Star*>::const_iterator iter = stars->begin();
00194 iter != stars->end(); iter++)
00195 {
00196 *sortedStars++ = **iter;
00197 }
00198 }
00199
00200 uint32 nStars = (uint32) (sortedStars - firstStar);
00201 node = new StarOctree(center, absMag, firstStar, nStars);
00202
00203 if (children != NULL)
00204 {
00205 node->children = new StarOctree*[8];
00206 for (int i = 0; i < 8; i++)
00207 children[i]->rebuildAndSort(node->children[i], sortedStars);
00208 }
00209 }
00210
00211
00212
00213 StarOctree::StarOctree(const Point3f& _center,
00214 float _absMag,
00215 Star* _firstStar,
00216 uint32 _nStars) :
00217 center(_center),
00218 absMag(_absMag),
00219 firstStar(_firstStar),
00220 nStars(_nStars),
00221 children(NULL)
00222 {
00223 }
00224
00225 StarOctree::~StarOctree()
00226 {
00227 if (children != NULL)
00228 {
00229 for (int i = 0; i < 8; i++)
00230 delete children[i];
00231 delete [] children;
00232 }
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 void StarOctree::findVisibleStars(StarHandler& starHandler,
00244 const Point3f& position,
00245 const Planef* frustumPlanes,
00246 float limitingMag,
00247 float scale) const
00248 {
00249
00250 {
00251
00252
00253 for (int i = 0; i < 5; i++)
00254 {
00255 const Planef* plane = frustumPlanes + i;
00256 float r = scale * (abs(plane->normal.x) +
00257 abs(plane->normal.y) +
00258 abs(plane->normal.z));
00259 if (plane->normal * Vec3f(center.x, center.y, center.z) - plane->d < -r)
00260 return;
00261 }
00262 }
00263
00264
00265
00266 float minDistance = (position - center).length() - scale * sqrt3;
00267
00268
00269 float dimmest = minDistance > 0 ? astro::appToAbsMag(limitingMag, minDistance) : 1000;
00270 for (unsigned int i = 0; i < nStars; i++)
00271 {
00272 Star& star = firstStar[i];
00273 if (star.getAbsoluteMagnitude() < dimmest)
00274 {
00275 float distance = position.distanceTo(star.getPosition());
00276 float appMag = astro::absToAppMag(star.getAbsoluteMagnitude(), distance);
00277 if (appMag < limitingMag)
00278 starHandler.process(star, distance, appMag);
00279 }
00280 }
00281
00282
00283
00284 if (minDistance <= 0 || astro::absToAppMag(absMag, minDistance) <= limitingMag)
00285 {
00286
00287 if (children != NULL)
00288 {
00289 for (int i = 0; i < 8; i++)
00290 {
00291 children[i]->findVisibleStars(starHandler,
00292 position,
00293 frustumPlanes,
00294 limitingMag,
00295 scale * 0.5f);
00296 }
00297 }
00298 }
00299 }
00300
00301
00302 void StarOctree::findCloseStars(StarHandler& starHandler,
00303 const Point3f& position,
00304 float radius,
00305 float scale) const
00306 {
00307
00308
00309 float nodeDistance = (position - center).length() - scale * sqrt3;
00310 if (nodeDistance > radius)
00311 return;
00312
00313
00314
00315
00316
00317
00318 float radiusSquared = radius * radius;
00319
00320
00321 for (unsigned int i = 0; i < nStars; i++)
00322 {
00323 Star& star = firstStar[i];
00324 if (position.distanceToSquared(star.getPosition()) < radiusSquared)
00325 {
00326 float distance = position.distanceTo(star.getPosition());
00327 float appMag = astro::absToAppMag(star.getAbsoluteMagnitude(),
00328 distance);
00329 starHandler.process(star, distance, appMag);
00330 }
00331 }
00332
00333
00334 if (children != NULL)
00335 {
00336 for (int i = 0; i < 8; i++)
00337 {
00338 children[i]->findCloseStars(starHandler,
00339 position,
00340 radius,
00341 scale * 0.5f);
00342 }
00343 }
00344 }
00345
00346
00347
00348 int StarOctree::countChildren() const
00349 {
00350 if (children == NULL)
00351 {
00352 return 0;
00353 }
00354 else
00355 {
00356 int nChildren = 0;
00357 for (int i = 0; i < 8; i++)
00358 nChildren += 1 + children[i]->countChildren();
00359
00360 return nChildren;
00361 }
00362 }
00363
00364 int StarOctree::countStars() const
00365 {
00366 int count = nStars;
00367
00368 if (children != NULL)
00369 {
00370 for (int i = 0; i < 8; i++)
00371 count += children[i]->countStars();
00372 }
00373
00374 return count;
00375 }