1 | #ifndef __SPHEREPACK_H__
|
---|
2 | #define __SPHEREPACK_H__
|
---|
3 |
|
---|
4 | #include <list>
|
---|
5 | #include <assert.h>
|
---|
6 |
|
---|
7 | #include "mars_lookup.h"
|
---|
8 | #include "mars_linalg.h"
|
---|
9 | #include "mars_util.h"
|
---|
10 | #include "mars_calc.h"
|
---|
11 | #include "mars_ptr.h"
|
---|
12 |
|
---|
13 | namespace geoworld
|
---|
14 | {
|
---|
15 | template <typename T>
|
---|
16 | class RandomSpherePack;
|
---|
17 |
|
---|
18 | template <typename T>
|
---|
19 | class RandomSpherePack
|
---|
20 | {
|
---|
21 | public:
|
---|
22 | class Sphere;
|
---|
23 | typedef typename mars::TreeTag3D< T >::VECTOR VECTOR;
|
---|
24 | typedef typename mars::TreeTag3D< T >::SCALAR SCALAR;
|
---|
25 | typedef std::list <VECTOR> PointList;
|
---|
26 | typedef std::list< mars::ptr< Sphere > > SphereList;
|
---|
27 | typedef typename SphereList::iterator SphereListIterator;
|
---|
28 | typedef typename SphereList::const_iterator SphereListConstIterator;
|
---|
29 |
|
---|
30 | struct IteratorTraits
|
---|
31 | {
|
---|
32 | typedef RandomSpherePack SpherePack;
|
---|
33 | using SphereType = Sphere;
|
---|
34 | typedef typename SphereList::iterator SphereListIterator;
|
---|
35 | };
|
---|
36 | struct ConstIteratorTraits
|
---|
37 | {
|
---|
38 | typedef const RandomSpherePack SpherePack;
|
---|
39 | using SphereType = const Sphere;
|
---|
40 | typedef typename SphereList::const_iterator SphereListIterator;
|
---|
41 | };
|
---|
42 |
|
---|
43 | class Sphere
|
---|
44 | {
|
---|
45 | private:
|
---|
46 | SphereList _subnodes;
|
---|
47 |
|
---|
48 | public:
|
---|
49 | const RandomSpherePack< T > * owner;
|
---|
50 |
|
---|
51 | VECTOR p;
|
---|
52 | SCALAR r;
|
---|
53 |
|
---|
54 | inline Sphere (const RandomSpherePack< T > * pOwner)
|
---|
55 | : owner(pOwner), r(0) {}
|
---|
56 |
|
---|
57 | inline Sphere (const Sphere & copy)
|
---|
58 | : owner(copy.owner), p(copy.p), r(copy.r), _subnodes(copy._subnodes) {}
|
---|
59 |
|
---|
60 | inline Sphere (const RandomSpherePack< T > * pOwner, const VECTOR & p, const T & r)
|
---|
61 | : owner(pOwner), p(p), r(r) {}
|
---|
62 |
|
---|
63 | template< typename Tag >
|
---|
64 | inline operator mars::RadialRegion< Tag > () const { return mars::RadialRegion< Tag > (p, r); }
|
---|
65 |
|
---|
66 | inline operator mars::CylindricalRegion< T > () const { return mars::CylindricalRegion< T > (p, r); }
|
---|
67 |
|
---|
68 | inline static float computeCull (const float azimuth, const float zenith)
|
---|
69 | {
|
---|
70 | using namespace mars;
|
---|
71 |
|
---|
72 | static const float PIxPI = SQ(static_cast<float> (PI));
|
---|
73 | // Calculates dot product of the displacement vector with the cull plane normal
|
---|
74 | // Spherical analog of Pythagoras: cos(c) = cos(a)cos(b)
|
---|
75 | return (PIxPI - SQ(acos(cos(azimuth)*cos(zenith)))) / PIxPI;
|
---|
76 | }
|
---|
77 |
|
---|
78 | inline SphereListConstIterator begin() const { return _subnodes.begin(); }
|
---|
79 | inline SphereListConstIterator end() const { return _subnodes.end(); }
|
---|
80 | inline SphereListIterator begin() { return _subnodes.begin(); }
|
---|
81 | inline SphereListIterator end() { return _subnodes.end(); }
|
---|
82 |
|
---|
83 | inline bool operator == (const Sphere & b) const
|
---|
84 | {
|
---|
85 | return p == b.p && r == b.r && owner == b.owner;
|
---|
86 | }
|
---|
87 |
|
---|
88 | inline size_t count() { return _subnodes.size(); }
|
---|
89 |
|
---|
90 | // Connect an existing sphere to this sphere as a child
|
---|
91 | void attach (const mars::ptr< Sphere > & pSphere)
|
---|
92 | {
|
---|
93 | assert (mars::MAG(pSphere->p) > 1);
|
---|
94 | _subnodes.push_back(pSphere);
|
---|
95 | }
|
---|
96 | Sphere * attachCulled( const mars::RangeX<float> &rads, const mars::RangeX<float> &rrng, const mars::SphericalCoords<T> &spc0 )
|
---|
97 | {
|
---|
98 | using namespace mars;
|
---|
99 |
|
---|
100 | const T r = static_cast <T> (rads.next());
|
---|
101 | SphericalCoords <T> spc1(
|
---|
102 | r,
|
---|
103 | rrng.next(),
|
---|
104 | rrng.next()
|
---|
105 | );
|
---|
106 |
|
---|
107 | // The closer a child is to the intersection of the two spheres (parent and current) the smaller it will be
|
---|
108 | if (rrng.delta >= owner->_minimum)
|
---|
109 | spc1.r = static_cast< T > (static_cast< float > (spc1.r) * computeCull(spc1.azimuth, spc1.zenith));
|
---|
110 |
|
---|
111 | // Ignore any and all children that are too small, just discard the information
|
---|
112 | if (spc1.r >= owner->_minimum)
|
---|
113 | {
|
---|
114 | // Apply new randomly generated angles to the angles between the two spheres and the corresponding radius
|
---|
115 | return & attach(
|
---|
116 | spc1.zenith + spc0.zenith,
|
---|
117 | spc1.azimuth + spc0.azimuth,
|
---|
118 | spc1.r / 2,
|
---|
119 | spc1.r
|
---|
120 | );
|
---|
121 | } else
|
---|
122 | return NULL;
|
---|
123 | }
|
---|
124 | // Create and connect a new sphere with the specified radius at the specified spherical coordinates relative to this sphere
|
---|
125 | Sphere & attach (const float zenith, const float azimuth, const T dr, const T rr)
|
---|
126 | {
|
---|
127 | using namespace mars;
|
---|
128 |
|
---|
129 | // Sphere is attached at the radius of the parent sphere plus the specified amount and at the spherical angles specified
|
---|
130 | _subnodes.push_back(mars::ptr< Sphere > (new Sphere(owner, SphericalCoords<T>(r + dr, zenith, azimuth) + p, rr)));
|
---|
131 | assert (mars::MAG(_subnodes.back()->p) > 1);
|
---|
132 | return *_subnodes.back();
|
---|
133 | }
|
---|
134 | template< typename PTR, typename R, typename G >
|
---|
135 | void store (mars::LookupTree< typename PTR::Type, R, G > & store, const PTR & pElem) const
|
---|
136 | {
|
---|
137 | store.add(pElem, *this);
|
---|
138 | for (typename SphereList::const_iterator it = _subnodes.begin(); it != _subnodes.end(); ++it)
|
---|
139 | (*it)->store(store, pElem);
|
---|
140 | }
|
---|
141 | };
|
---|
142 |
|
---|
143 | private:
|
---|
144 | SphereList _toptier;
|
---|
145 |
|
---|
146 | const float _divisor;
|
---|
147 | const mars::RangeX <float> _sizeflux;
|
---|
148 | const mars::RangeX <unsigned short> _kidflux;
|
---|
149 | const T _minimum, _maxtier;
|
---|
150 |
|
---|
151 | T _limit; // Non-const for subdivision
|
---|
152 |
|
---|
153 | inline float intersectAngle (const Sphere & sphere0, const Sphere & sphere) const
|
---|
154 | {
|
---|
155 | using namespace mars;
|
---|
156 |
|
---|
157 | assert(mars::MAG(sphere.p - sphere0.p) < sphere.r + sphere0.r);
|
---|
158 | return acos(
|
---|
159 | static_cast< float > (MAGSQ(sphere.p - sphere0.p) + SQ(sphere0.r) - SQ(sphere.r)) / static_cast< float > (2 * MAG(sphere.p - sphere0.p) * sphere0.r)
|
---|
160 | );
|
---|
161 | }
|
---|
162 |
|
---|
163 | inline T distance (const T r1, const T r2) const
|
---|
164 | {
|
---|
165 | if (r1 > r2)
|
---|
166 | return r1 + r2 / 2;
|
---|
167 | else
|
---|
168 | return r2 + r1 / 2;
|
---|
169 | }
|
---|
170 |
|
---|
171 | mars::ptr< Sphere > spawnBetween (const Sphere & sphere0, const Sphere & sphere1)
|
---|
172 | {
|
---|
173 | using namespace mars;
|
---|
174 | using namespace std;
|
---|
175 |
|
---|
176 | // The vector between the two precursor spheres
|
---|
177 | const vector3D< T > dp = sphere1.p - sphere0.p;
|
---|
178 |
|
---|
179 | // The scalar and the square of the distance between the two precursor spheres
|
---|
180 | const T dsq = MAGSQ(dp), d = sqrt(dsq);
|
---|
181 |
|
---|
182 | // New sphere radius must be large enough to sufficiently overlap both the parent and child spheres
|
---|
183 | // but yet not exceed the parent sphere's radius
|
---|
184 | const RangeX <T> rrng(
|
---|
185 | sphere0.r / 2 + (d - sphere0.r - sphere1.r) / 2,
|
---|
186 | std::max(sphere0.r, sphere1.r)
|
---|
187 | );
|
---|
188 | const T r = rrng.next();
|
---|
189 |
|
---|
190 | const T
|
---|
191 | // Scalar and square distances between the sphere centers of the parent sphere and the newly spliced sphere
|
---|
192 | br = distance(sphere0.r, r), brsq = SQ(br),
|
---|
193 |
|
---|
194 | // Distance between the sphere centers of the newly spliced sphere and the child sphere
|
---|
195 | ar = distance(r, sphere1.r),
|
---|
196 |
|
---|
197 | // Projection of the vector between the sphere centers of the parent sphere and the newly spliced sphere onto the vector between the parent sphere and the child sphere
|
---|
198 | ch = (brsq + dsq - SQ(ar)) / (2*d);
|
---|
199 |
|
---|
200 | assert (br + ar >= d);
|
---|
201 |
|
---|
202 | // Setup the rotation about the axis defined by the aforementioned vector
|
---|
203 | const mars::Quaternion< T >
|
---|
204 | q = mars::Quaternion< T >::rotation(RANDf(PI * 2), mars::U(dp));
|
---|
205 |
|
---|
206 | const vector3D< T >
|
---|
207 | // First-half: Make an arbitrarily perpendicular vector to the aforementioned axis
|
---|
208 | // Second-half: Use the law of cosines to determine the height of the triangle
|
---|
209 | // (this would be the "opposite" shared by two imaginary right-triangles that compose the triangle)
|
---|
210 | vb = mars::U(vector3D< T > (dp.y, -(dp.x + dp.z), dp.y)) * sqrt(brsq - SQ(ch)),
|
---|
211 |
|
---|
212 | // Apply the rotation
|
---|
213 | vbr = q & vb,
|
---|
214 |
|
---|
215 | // Form the baseline vector
|
---|
216 | vch = mars::U(dp) * ch,
|
---|
217 |
|
---|
218 | // Calculate the hypotenuse vector
|
---|
219 | // - hypotenuse: distance between sphere centers of parent sphere and newly spliced sphere
|
---|
220 | // - opposite: rotated vector
|
---|
221 | pp = vch + vbr;
|
---|
222 |
|
---|
223 | assert(SQ(MAG(pp) - br) < 0.0001);
|
---|
224 | assert(MAG(sphere1.p - (sphere0.p + pp)) < sphere1.r + r);
|
---|
225 | assert(d - (MAG(pp) + r + sphere1.r) < 0);
|
---|
226 |
|
---|
227 | return mars::ptr< Sphere > (new Sphere (*this, sphere0.p + pp, r));
|
---|
228 | }
|
---|
229 |
|
---|
230 | void spawn (const Sphere & sphere0, Sphere & sphere, const T nTier)
|
---|
231 | {
|
---|
232 | using namespace mars;
|
---|
233 |
|
---|
234 | static const float pi = static_cast <float> (PI);
|
---|
235 |
|
---|
236 | // Next number of breadth kids to generate for this sphere
|
---|
237 | const unsigned short amt = _kidflux.next();
|
---|
238 |
|
---|
239 | // Allowed radii for children
|
---|
240 | const RangeX <float> rads (
|
---|
241 | _sizeflux.minimum * static_cast <float> (sphere.r),
|
---|
242 | _sizeflux.maximum * static_cast <float> (sphere.r)
|
---|
243 | );
|
---|
244 |
|
---|
245 | // Spherical coordinate representation of vector between parent sphere and this current sphere
|
---|
246 | const SphericalCoords<T> spc0 (sphere0.p - sphere.p);
|
---|
247 | RangeX<float> rrng = naturalArcRange(sphere0, sphere, pi);
|
---|
248 |
|
---|
249 | for (unsigned int c = sphere.count(); c < amt; ++c)
|
---|
250 | {
|
---|
251 | Sphere * neww = sphere.attachCulled(rads, rrng, spc0);
|
---|
252 |
|
---|
253 | // Do not recurse if we are as deep as we are allowed to go
|
---|
254 | // or if the size of the sphere is small enough and doesn't need more descendants in this branch
|
---|
255 | if (neww != NULL && neww->r > _limit && nTier < _maxtier)
|
---|
256 | spawn (sphere, *neww, nTier + 1);
|
---|
257 | }
|
---|
258 | }
|
---|
259 |
|
---|
260 | void subdivide (const Sphere & sphere0, Sphere & sphere)
|
---|
261 | {
|
---|
262 | using namespace mars;
|
---|
263 | const T r = sphere.r;
|
---|
264 | const size_t len = sphere.count();
|
---|
265 | static const float pi = static_cast <float> (PI);
|
---|
266 |
|
---|
267 | // Do not sub-divide this sphere if it is already too small
|
---|
268 | if (sphere.r / _divisor >= _limit)
|
---|
269 | {
|
---|
270 | sphere.r /= _divisor;
|
---|
271 |
|
---|
272 | for (typename SphereList::iterator it = sphere.begin(); it != sphere.end(); ++it)
|
---|
273 | {
|
---|
274 | mars::ptr< Sphere > pSphTail = *it;
|
---|
275 | // First divide the current sphere and all successive spheres before adding any new spheres
|
---|
276 | subdivide(sphere, *pSphTail);
|
---|
277 |
|
---|
278 | // Splice-in a randomly-placed sphere between this current sphere and the iterator current sphere
|
---|
279 | mars::ptr< Sphere > pSphere1 = spawnBetween(sphere, *pSphTail);
|
---|
280 |
|
---|
281 | spawnImmediates(*pSphere1, sphere, *pSphTail);
|
---|
282 |
|
---|
283 | pSphere1->attach(pSphTail);
|
---|
284 | *it = pSphere1;
|
---|
285 |
|
---|
286 | // Generate allowed radii for additional children of the parent of the spliced sphere
|
---|
287 | // Must come after sphere.r /= 2 because it depends on the new radius
|
---|
288 | const RangeX <T> rads (
|
---|
289 | _sizeflux.minimum * static_cast <float> (pSphTail->r),
|
---|
290 | _sizeflux.maximum * static_cast <float> (pSphTail->r)
|
---|
291 | );
|
---|
292 |
|
---|
293 | // Spherical coordinate representation of vector between parent sphere and this current sphere
|
---|
294 | const SphericalCoords<T> spc0 (pSphTail->p - pSphere1->p);
|
---|
295 | RangeX<float> rrng = naturalArcRange(*pSphTail, *pSphere1, pi);
|
---|
296 |
|
---|
297 | // Add only as many new children as the original conditions permit for a new random quantity
|
---|
298 | for (size_t n = _kidflux.next(); n > len; --n)
|
---|
299 | {
|
---|
300 | pSphTail->attachCulled(rads, rrng, spc0);
|
---|
301 | }
|
---|
302 | }
|
---|
303 | }
|
---|
304 | }
|
---|
305 | void spawnImmediates( Sphere & sphere, Sphere & sphere0, Sphere & sphere1)
|
---|
306 | {
|
---|
307 | using namespace mars;
|
---|
308 | const short kfn = _kidflux.next();
|
---|
309 |
|
---|
310 | // Add new children if and only if the new random amount is within the bounds and accounts for the spliced one's descendant
|
---|
311 | if (kfn > _kidflux.minimum)
|
---|
312 | {
|
---|
313 | // Accounts for the spliced one's descendant
|
---|
314 | const unsigned short amt = kfn - 1;
|
---|
315 |
|
---|
316 | // Allowed radii for children
|
---|
317 | const RangeX <T> rads (
|
---|
318 | _sizeflux.minimum * static_cast <float> (sphere.r),
|
---|
319 | _sizeflux.maximum * static_cast <float> (sphere.r)
|
---|
320 | );
|
---|
321 |
|
---|
322 | const SphericalCoords<T> spc (sphere0.p - sphere.p);
|
---|
323 |
|
---|
324 | // Allowed range where neither the descendant nor ancestor intersect with this current sphere
|
---|
325 | const RangeX<float> rrng (
|
---|
326 | intersectAngle(sphere, sphere1),
|
---|
327 | PI - intersectAngle(sphere0, sphere),
|
---|
328 | 0.02f / 2.0f
|
---|
329 | );
|
---|
330 |
|
---|
331 | // Adds children to the spliced sphere
|
---|
332 | for (unsigned int c = 0; c < amt; ++c)
|
---|
333 | {
|
---|
334 | const T r = static_cast <T> (rads.next());
|
---|
335 | SphericalCoords <T> spc1(
|
---|
336 | r,
|
---|
337 | rrng.next() * 2.0f,
|
---|
338 | rrng.next() * 2.0f
|
---|
339 | );
|
---|
340 |
|
---|
341 | // Since the two allowed ranges are disjoint, we compensate for the non-linear issue
|
---|
342 | if (spc1.azimuth > rrng.maximum)
|
---|
343 | spc1.azimuth = rrng.maximum - spc1.azimuth;
|
---|
344 | if (spc1.zenith > rrng.maximum)
|
---|
345 | spc1.zenith = rrng.maximum - spc1.zenith;
|
---|
346 |
|
---|
347 | // The closer to the intersections the child is, the smaller it becomes
|
---|
348 | const float f = Sphere::computeCull(spc1.azimuth, spc1.zenith);
|
---|
349 |
|
---|
350 | spc1.r *= (f + (1.0f - f)) / 2.0f;
|
---|
351 |
|
---|
352 | // Attach the child
|
---|
353 | if (spc1.r >= _minimum)
|
---|
354 | {
|
---|
355 | sphere.attach(
|
---|
356 | spc.zenith + spc1.zenith,
|
---|
357 | spc.azimuth + spc1.azimuth,
|
---|
358 | spc1.r / 2,
|
---|
359 | spc1.r
|
---|
360 | );
|
---|
361 | }
|
---|
362 | }
|
---|
363 | }
|
---|
364 | }
|
---|
365 |
|
---|
366 | inline mars::RangeX<float> naturalArcRange( const Sphere & sphere0, Sphere & sphere, const float pi ) const
|
---|
367 | {
|
---|
368 | // Depending on radii of the two spheres (parent and current), determine the angle of the arc spanning the intersection of the two spheres
|
---|
369 | const float deg = (sphere0 == sphere ? 0 : intersectAngle(sphere0, sphere));
|
---|
370 |
|
---|
371 | // Allowed angular range dispositions for children
|
---|
372 | return mars::RangeX<float> (-pi + deg, +pi - deg, 0.02f);
|
---|
373 | }
|
---|
374 |
|
---|
375 | template <typename I>
|
---|
376 | struct StackInfo
|
---|
377 | {
|
---|
378 | I i, end;
|
---|
379 |
|
---|
380 | inline StackInfo(const I & begin, const I & end)
|
---|
381 | : i(begin), end(end) {}
|
---|
382 | };
|
---|
383 |
|
---|
384 | public:
|
---|
385 | template< typename TRAITS = ConstIteratorTraits >
|
---|
386 | class ConstIterator : public std::iterator< std::input_iterator_tag, Sphere >
|
---|
387 | {
|
---|
388 | protected:
|
---|
389 | typename TRAITS::SphereType * _spCurr;
|
---|
390 |
|
---|
391 | private:
|
---|
392 | typedef typename TRAITS::SphereListIterator SphereListIterator;
|
---|
393 |
|
---|
394 | typename TRAITS::SpherePack * const _pack;
|
---|
395 | SphereListIterator _it;
|
---|
396 | StackInfo< SphereListIterator > * _stCurr;
|
---|
397 | std::stack< StackInfo< SphereListIterator > > _stack;
|
---|
398 |
|
---|
399 | CR_CONTEXT;
|
---|
400 |
|
---|
401 | void process()
|
---|
402 | {
|
---|
403 | CR_START();
|
---|
404 |
|
---|
405 | _stack.push(StackInfo< SphereListIterator > (_pack->_toptier.begin(), _pack->_toptier.end()));
|
---|
406 | while (!_stack.empty())
|
---|
407 | {
|
---|
408 | _stCurr = & _stack.top();
|
---|
409 |
|
---|
410 | while (_stCurr->i != _stCurr->end)
|
---|
411 | {
|
---|
412 | _spCurr = & **_stCurr->i++;
|
---|
413 |
|
---|
414 | CR_RETURN_VOID;
|
---|
415 |
|
---|
416 | if (_spCurr->begin() != _spCurr->end())
|
---|
417 | {
|
---|
418 | _stack.push(StackInfo< SphereListIterator > (_spCurr->begin(), _spCurr->end()));
|
---|
419 | _stCurr = & _stack.top();
|
---|
420 | continue;
|
---|
421 | }
|
---|
422 | }
|
---|
423 |
|
---|
424 | _stack.pop();
|
---|
425 | }
|
---|
426 |
|
---|
427 | _spCurr = NULL;
|
---|
428 |
|
---|
429 | CR_END();
|
---|
430 | }
|
---|
431 |
|
---|
432 | public:
|
---|
433 | ConstIterator (typename TRAITS::SpherePack * const pack)
|
---|
434 | : _pack(pack)
|
---|
435 | {
|
---|
436 | CR_INIT();
|
---|
437 | process();
|
---|
438 | }
|
---|
439 | inline operator bool () { return _spCurr != NULL; }
|
---|
440 | inline ConstIterator & operator++()
|
---|
441 | {
|
---|
442 | process();
|
---|
443 | return *this;
|
---|
444 | }
|
---|
445 | inline ConstIterator operator++(int)
|
---|
446 | {
|
---|
447 | ConstIterator old = *this;
|
---|
448 | process();
|
---|
449 | return old;
|
---|
450 | }
|
---|
451 | inline const Sphere * operator -> () const { return &(*_spCurr); }
|
---|
452 | inline const Sphere & operator * () const { return *_spCurr; }
|
---|
453 | };
|
---|
454 |
|
---|
455 | class Iterator : public ConstIterator< IteratorTraits >
|
---|
456 | {
|
---|
457 | public:
|
---|
458 | Iterator (typename IteratorTraits::SpherePack * const pack)
|
---|
459 | : ConstIterator< IteratorTraits > (pack) {}
|
---|
460 |
|
---|
461 | inline Sphere * operator -> () { return &(*this->_spCurr); }
|
---|
462 | inline Sphere & operator * () { return *this->_spCurr; }
|
---|
463 | };
|
---|
464 |
|
---|
465 | typedef Iterator iterator;
|
---|
466 | typedef ConstIterator< ConstIteratorTraits > const_iterator;
|
---|
467 |
|
---|
468 | public:
|
---|
469 | inline RandomSpherePack (
|
---|
470 | const T limit, // Size below-which spheres are no-longer generated, essentially characterizes the degree of refined detail
|
---|
471 | const T minimum, // The minimum size of a sphere (usually just 1.0)
|
---|
472 | const T maxtier, // The maximum number depth-iterations (as opposed to breadth), this also affects the level of detail
|
---|
473 | const mars::RangeX<float> & sizeflux, // Flux of size of spheres at starting tier
|
---|
474 | const mars::RangeX<unsigned short> & kidflux // Flux of number of breadth-iterations (as opposed to depth),
|
---|
475 | )
|
---|
476 | : _sizeflux(sizeflux), _kidflux(kidflux), _limit(limit), _minimum(minimum), _maxtier(maxtier),
|
---|
477 | // Numeric stability will result if (iff?) divisor is not less than 2 because the gap between sub-divided spheres would be too great
|
---|
478 | _divisor(4.0f / 3.0f)
|
---|
479 | {}
|
---|
480 |
|
---|
481 | inline Sphere createEmptySphere () const
|
---|
482 | { return Sphere(this); }
|
---|
483 |
|
---|
484 | inline const Sphere & spawn (const VECTOR & pt, const T size)
|
---|
485 | {
|
---|
486 | assert (size >= _minimum);
|
---|
487 |
|
---|
488 | _toptier.push_back(
|
---|
489 | mars::ptr <Sphere> (
|
---|
490 | new Sphere(
|
---|
491 | this,
|
---|
492 | pt,
|
---|
493 | static_cast <T> (static_cast <float> (size / _sizeflux.minimum) * _sizeflux.next())
|
---|
494 | )
|
---|
495 | )
|
---|
496 | );
|
---|
497 |
|
---|
498 | return * _toptier.back();
|
---|
499 | }
|
---|
500 |
|
---|
501 | inline const Sphere & spawn (const float zenith, const float azimuth, const T size)
|
---|
502 | {
|
---|
503 | assert (size >= _minimum);
|
---|
504 |
|
---|
505 | const T r = static_cast <T> (static_cast <float> (size / _sizeflux.minimum) * _sizeflux.next());
|
---|
506 | const Sphere & neighbor = *_toptier.back();
|
---|
507 |
|
---|
508 | _toptier.push_back(
|
---|
509 | mars::ptr <Sphere> (
|
---|
510 | new Sphere(
|
---|
511 | this,
|
---|
512 | neighbor.p + mars::SphericalCoords< T > (distance (neighbor.r, r), zenith, azimuth),
|
---|
513 | r
|
---|
514 | )
|
---|
515 | )
|
---|
516 | );
|
---|
517 |
|
---|
518 | return * _toptier.back();
|
---|
519 | }
|
---|
520 |
|
---|
521 | inline void generateDescendants ()
|
---|
522 | {
|
---|
523 | for (typename SphereList::iterator it = _toptier.begin(); it != _toptier.end(); ++it)
|
---|
524 | spawn(**it, **it, 1);
|
---|
525 | }
|
---|
526 | inline void subdivide ()
|
---|
527 | {
|
---|
528 | if (_limit / _divisor >= _minimum)
|
---|
529 | _limit /= _divisor;
|
---|
530 | for (typename SphereList::iterator it = _toptier.begin(); it != _toptier.end(); ++it)
|
---|
531 | subdivide(**it, **it);
|
---|
532 |
|
---|
533 | typename SphereList::iterator itTail, itHead;
|
---|
534 |
|
---|
535 | itHead = _toptier.begin();
|
---|
536 | itTail = itHead++;
|
---|
537 |
|
---|
538 | while (itHead != _toptier.end())
|
---|
539 | {
|
---|
540 | mars::ptr< Sphere > pSphereA = spawnBetween(**itTail, **itHead);
|
---|
541 |
|
---|
542 | spawnImmediates(*pSphereA, **itTail, **itHead);
|
---|
543 | _toptier.insert (itHead, pSphereA);
|
---|
544 |
|
---|
545 | itTail = itHead++;
|
---|
546 | }
|
---|
547 | }
|
---|
548 | inline iterator iterate () { return iterator(this); }
|
---|
549 | inline const_iterator iterate () const { return const_iterator(this); }
|
---|
550 | inline unsigned int count () const
|
---|
551 | {
|
---|
552 | std::stack< StackInfo< SphereListConstIterator > > stack;
|
---|
553 | unsigned int c = 1;
|
---|
554 |
|
---|
555 | stack.push(StackInfo< SphereListConstIterator > (_toptier.begin(), _toptier.end()));
|
---|
556 |
|
---|
557 | while (!stack.empty())
|
---|
558 | {
|
---|
559 | StackInfo< SphereListConstIterator > & curr = stack.top();
|
---|
560 |
|
---|
561 | while (curr.i != curr.end)
|
---|
562 | {
|
---|
563 | const Sphere & sphere = **curr.i;
|
---|
564 |
|
---|
565 | ++c;
|
---|
566 | ++curr.i;
|
---|
567 | if (sphere.begin() != sphere.end())
|
---|
568 | {
|
---|
569 | stack.push(curr);
|
---|
570 | curr = StackInfo< SphereListConstIterator >(sphere.begin(), sphere.end());
|
---|
571 | continue;
|
---|
572 | }
|
---|
573 | }
|
---|
574 |
|
---|
575 | stack.pop();
|
---|
576 | }
|
---|
577 | return c;
|
---|
578 | }
|
---|
579 |
|
---|
580 | template< typename PTR, typename R, typename G >
|
---|
581 | void store (mars::LookupTree< typename PTR::Type, R, G > & store, const PTR & pElem) const
|
---|
582 | {
|
---|
583 | for (typename SphereList::const_iterator it = _toptier.begin(); it != _toptier.end(); ++it)
|
---|
584 | (*it)->store(store, pElem);
|
---|
585 | }
|
---|
586 |
|
---|
587 | // TODO: Find a purpose for this method, may not be necessary, was primordially conceived
|
---|
588 | template< typename E, typename R, typename G, typename QR >
|
---|
589 | float probability (mars::LookupTree< E, R, G > & store, const QR & search, E * = NULL) const
|
---|
590 | {
|
---|
591 | using namespace mars;
|
---|
592 | float f = 0.0f;
|
---|
593 |
|
---|
594 | for (typename mars::LookupTree< E, R, G >::EntityRadialIterator it = store.contents(search); it.hasMore(); ++it)
|
---|
595 | {
|
---|
596 | const R & region = it.region();
|
---|
597 | const float ff = GaussianFn<float>::f(MAGSQ(region.p - region.p), 1.0, SQ(region.r), 0, 1.0f, 0);
|
---|
598 |
|
---|
599 | if (ff > f)
|
---|
600 | f = ff;
|
---|
601 | }
|
---|
602 | return f;
|
---|
603 | }
|
---|
604 | };
|
---|
605 | }
|
---|
606 |
|
---|
607 | #endif
|
---|