3
StelGeodesicGrid: a library for dividing the sphere into triangle zones
4
by subdividing the icosahedron
6
Author and Copyright: Johannes Gajdosik, 2006
8
This library requires a simple Vector library,
9
which may have different copyright and license,
10
for example Vec3d from VecMath.hpp.
12
In the moment I choose to distribute the library under the GPL,
13
later I may choose to additionally distribute it under a more
14
relaxed license like the LGPL. If you want to have the library
15
under another license, please ask me.
19
This library is free software; you can redistribute it and/or
20
modify it under the terms of the GNU General Public License
21
as published by the Free Software Foundation; either version 2
22
of the License, or (at your option) any later version.
24
This library is distributed in the hope that it will be useful,
25
but WITHOUT ANY WARRANTY; without even the implied warranty of
26
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
GNU General Public License for more details.
29
You should have received a copy of the GNU General Public License
30
along with this library; if not, write to the Free Software
31
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35
#include "StelGeodesicGrid.hpp"
41
static const double icosahedron_G = 0.5*(1.0+sqrt(5.0));
42
static const double icosahedron_b = 1.0/sqrt(1.0+icosahedron_G*icosahedron_G);
43
static const double icosahedron_a = icosahedron_b*icosahedron_G;
45
static const Vec3d icosahedron_corners[12] =
47
Vec3d( icosahedron_a, -icosahedron_b, 0.0),
48
Vec3d( icosahedron_a, icosahedron_b, 0.0),
49
Vec3d(-icosahedron_a, icosahedron_b, 0.0),
50
Vec3d(-icosahedron_a, -icosahedron_b, 0.0),
51
Vec3d( 0.0, icosahedron_a, -icosahedron_b),
52
Vec3d( 0.0, icosahedron_a, icosahedron_b),
53
Vec3d( 0.0, -icosahedron_a, icosahedron_b),
54
Vec3d( 0.0, -icosahedron_a, -icosahedron_b),
55
Vec3d(-icosahedron_b, 0.0, icosahedron_a),
56
Vec3d( icosahedron_b, 0.0, icosahedron_a),
57
Vec3d( icosahedron_b, 0.0, -icosahedron_a),
58
Vec3d(-icosahedron_b, 0.0, -icosahedron_a)
61
struct TopLevelTriangle
63
int corners[3]; // index der Ecken
67
static const TopLevelTriangle icosahedron_triangles[20] =
91
StelGeodesicGrid::StelGeodesicGrid(const int lev) : maxLevel(lev<0?0:lev), lastMaxSearchlevel(-1)
95
triangles = new Triangle*[maxLevel+1];
96
int nr_of_triangles = 20;
97
for (int i=0;i<maxLevel;i++)
99
triangles[i] = new Triangle[nr_of_triangles];
100
nr_of_triangles *= 4;
102
for (int i=0;i<20;i++)
104
const int *const corners = icosahedron_triangles[i].corners;
106
icosahedron_corners[corners[0]],
107
icosahedron_corners[corners[1]],
108
icosahedron_corners[corners[2]]);
115
cacheSearchResult = new GeodesicSearchResult(*this);
118
StelGeodesicGrid::~StelGeodesicGrid(void)
122
for (int i=maxLevel-1;i>=0;i--) delete[] triangles[i];
125
delete cacheSearchResult;
126
cacheSearchResult = NULL;
129
void StelGeodesicGrid::getTriangleCorners(int lev,int index,
136
const int *const corners = icosahedron_triangles[index].corners;
137
h0 = icosahedron_corners[corners[0]];
138
h1 = icosahedron_corners[corners[1]];
139
h2 = icosahedron_corners[corners[2]];
144
const int i = index>>2;
145
Triangle &t(triangles[lev][i]);
151
getTriangleCorners(lev,i,c0,c1,c2);
160
getTriangleCorners(lev,i,c0,c1,c2);
169
getTriangleCorners(lev,i,c0,c1,c2);
184
int StelGeodesicGrid::getPartnerTriangle(int lev, int index) const
189
return (index&1) ? index+1 : index-1;
200
return (lev==1) ? index+5 : (getPartnerTriangle(lev-1, index>>2)<<2)+1;
202
return (lev==1) ? index+3 : (getPartnerTriangle(lev-1, index>>2)<<2)+0;
204
return (lev==1) ? index-3 : (getPartnerTriangle(lev-1, index>>2)<<2)+1;
206
return (lev==1) ? index-5 : (getPartnerTriangle(lev-1, index>>2)<<2)+0;
213
void StelGeodesicGrid::initTriangle(int lev,int index,
218
Q_ASSERT((c0^c1)*c2 >= 0.0);
219
Triangle &t(triangles[lev][index]);
230
initTriangle(lev,index+0,c0,t.e2,t.e1);
231
initTriangle(lev,index+1,t.e2,c1,t.e0);
232
initTriangle(lev,index+2,t.e1,t.e0,c2);
233
initTriangle(lev,index+3,t.e0,t.e1,t.e2);
238
void StelGeodesicGrid::visitTriangles(int maxVisitLevel,
242
if (func && maxVisitLevel >= 0)
244
if (maxVisitLevel > maxLevel) maxVisitLevel = maxLevel;
245
for (int i=0;i<20;i++)
247
const int *const corners = icosahedron_triangles[i].corners;
249
icosahedron_corners[corners[0]],
250
icosahedron_corners[corners[1]],
251
icosahedron_corners[corners[2]],
252
maxVisitLevel,func,context);
257
void StelGeodesicGrid::visitTriangles(int lev,int index,
265
(*func)(lev,index,c0,c1,c2,context);
266
Triangle &t(triangles[lev][index]);
268
if (lev <= maxVisitLevel)
271
visitTriangles(lev,index+0,c0,t.e2,t.e1,maxVisitLevel,func,context);
272
visitTriangles(lev,index+1,t.e2,c1,t.e0,maxVisitLevel,func,context);
273
visitTriangles(lev,index+2,t.e1,t.e0,c2,maxVisitLevel,func,context);
274
visitTriangles(lev,index+3,t.e0,t.e1,t.e2,maxVisitLevel,func,context);
279
int StelGeodesicGrid::searchZone(const Vec3d &v,int searchLevel) const
281
for (int i=0;i<20;i++)
283
const int *const corners = icosahedron_triangles[i].corners;
284
const Vec3d &c0(icosahedron_corners[corners[0]]);
285
const Vec3d &c1(icosahedron_corners[corners[1]]);
286
const Vec3d &c2(icosahedron_corners[corners[2]]);
287
if (((c0^c1)*v >= 0.0) && ((c1^c2)*v >= 0.0) && ((c2^c0)*v >= 0.0))
289
// v lies inside this icosahedron triangle
290
for (int lev=0;lev<searchLevel;lev++)
292
Triangle &t(triangles[lev][i]);
294
if ((t.e1^t.e2)*v <= 0.0)
298
else if ((t.e2^t.e0)*v <= 0.0)
302
else if ((t.e0^t.e1)*v <= 0.0)
314
qWarning() << "ERROR StelGeodesicGrid::searchZone - not found";
316
// shut up the compiler
321
void StelGeodesicGrid::searchZones(const StelGeom::ConvexS& convex,
322
int **inside_list,int **border_list,
323
int maxSearchLevel) const
325
if (maxSearchLevel < 0) maxSearchLevel = 0;
326
else if (maxSearchLevel > maxLevel) maxSearchLevel = maxLevel;
327
#if defined __STRICT_ANSI__ || !defined __GNUC__
328
int *halfs_used = new int[convex.size()];
330
int halfs_used[convex.size()];
332
for (int h=0;h<(int)convex.size();h++) {halfs_used[h] = h;}
333
#if defined __STRICT_ANSI__ || !defined __GNUC__
334
bool *corner_inside[12];
335
for(int ci=0; ci < 12; ci++) corner_inside[ci]= new bool[convex.size()];
337
bool corner_inside[12][convex.size()];
339
for (size_t h=0;h<convex.size();h++)
341
const StelGeom::HalfSpace &half_space(convex[h]);
342
for (int i=0;i<12;i++)
344
corner_inside[i][h] = half_space.contains(icosahedron_corners[i]);
347
for (int i=0;i<20;i++)
350
convex,halfs_used,convex.size(),
351
corner_inside[icosahedron_triangles[i].corners[0]],
352
corner_inside[icosahedron_triangles[i].corners[1]],
353
corner_inside[icosahedron_triangles[i].corners[2]],
354
inside_list,border_list,maxSearchLevel);
356
#if defined __STRICT_ANSI__ || !defined __GNUC__
358
for(int ci=0; ci < 12; ci++) delete[] corner_inside[ci];
362
void StelGeodesicGrid::searchZones(int lev,int index,
363
const StelGeom::ConvexS& convex,
364
const int *indexOfUsedHalfSpaces,
365
const int halfSpacesUsed,
366
const bool *corner0_inside,
367
const bool *corner1_inside,
368
const bool *corner2_inside,
369
int **inside_list,int **border_list,
370
const int maxSearchLevel) const
372
#if defined __STRICT_ANSI__ || !defined __GNUC__
373
int *halfs_used = new int[halfSpacesUsed];
375
int halfs_used[halfSpacesUsed];
377
int halfs_used_count = 0;
378
for (int h=0;h<halfSpacesUsed;h++)
380
const int i = indexOfUsedHalfSpaces[h];
381
if (!corner0_inside[i] && !corner1_inside[i] && !corner2_inside[i])
383
// totally outside this HalfSpace
386
else if (corner0_inside[i] && corner1_inside[i] && corner2_inside[i])
388
// totally inside this HalfSpace
392
// on the border of this HalfSpace
393
halfs_used[halfs_used_count++] = i;
396
if (halfs_used_count == 0)
398
// this triangle(lev,index) lies inside all halfspaces
399
**inside_list = index;
405
**border_list = index;
406
if (lev < maxSearchLevel)
408
Triangle &t(triangles[lev][index]);
413
#if defined __STRICT_ANSI__ || !defined __GNUC__
414
bool *edge0_inside = new bool[convex.size()];
415
bool *edge1_inside = new bool[convex.size()];
416
bool *edge2_inside = new bool[convex.size()];
418
bool edge0_inside[convex.size()];
419
bool edge1_inside[convex.size()];
420
bool edge2_inside[convex.size()];
422
for (int h=0;h<halfs_used_count;h++)
424
const int i = halfs_used[h];
425
const StelGeom::HalfSpace &half_space(convex[i]);
426
edge0_inside[i] = half_space.contains(t.e0);
427
edge1_inside[i] = half_space.contains(t.e1);
428
edge2_inside[i] = half_space.contains(t.e2);
430
searchZones(lev,index+0,
431
convex,halfs_used,halfs_used_count,
432
corner0_inside,edge2_inside,edge1_inside,
433
inside_list,border_list,maxSearchLevel);
434
searchZones(lev,index+1,
435
convex,halfs_used,halfs_used_count,
436
edge2_inside,corner1_inside,edge0_inside,
437
inside_list,border_list,maxSearchLevel);
438
searchZones(lev,index+2,
439
convex,halfs_used,halfs_used_count,
440
edge1_inside,edge0_inside,corner2_inside,
441
inside_list,border_list,maxSearchLevel);
442
searchZones(lev,index+3,
443
convex,halfs_used,halfs_used_count,
444
edge0_inside,edge1_inside,edge2_inside,
445
inside_list,border_list,maxSearchLevel);
446
#if defined __STRICT_ANSI__ || !defined __GNUC__
447
delete[] edge0_inside;
448
delete[] edge1_inside;
449
delete[] edge2_inside;
453
#if defined __STRICT_ANSI__ || !defined __GNUC__
458
/*************************************************************************
459
Return a search result matching the given spatial region
460
*************************************************************************/
461
const GeodesicSearchResult* StelGeodesicGrid::search(const StelGeom::ConvexS& convex, int maxSearchLevel) const
463
// Try to use the cached version
464
if (maxSearchLevel==lastMaxSearchlevel && convex==lastSearchRegion)
466
return cacheSearchResult;
468
// Else recompute it and update cache parameters
469
lastMaxSearchlevel = maxSearchLevel;
470
lastSearchRegion = convex;
471
cacheSearchResult->search(convex, maxSearchLevel);
472
return cacheSearchResult;
476
/*************************************************************************
477
Return a search result matching the given spatial region
478
*************************************************************************/
479
const GeodesicSearchResult* StelGeodesicGrid::search(const Vec3d &e0,const Vec3d &e1,const Vec3d &e2,const Vec3d &e3,int maxSearchLevel) const
481
StelGeom::ConvexS c(e0, e1, e2, e3);
482
return search(c,maxSearchLevel);
486
GeodesicSearchResult::GeodesicSearchResult(const StelGeodesicGrid &grid)
488
zones(new int*[grid.getMaxLevel()+1]),
489
inside(new int*[grid.getMaxLevel()+1]),
490
border(new int*[grid.getMaxLevel()+1])
492
for (int i=0;i<=grid.getMaxLevel();i++)
494
zones[i] = new int[StelGeodesicGrid::nrOfZones(i)];
498
GeodesicSearchResult::~GeodesicSearchResult(void)
500
for (int i=grid.getMaxLevel();i>=0;i--)
509
void GeodesicSearchResult::search(const StelGeom::ConvexS& convex,
512
for (int i=grid.getMaxLevel();i>=0;i--)
514
inside[i] = zones[i];
515
border[i] = zones[i]+StelGeodesicGrid::nrOfZones(i);
517
grid.searchZones(convex,inside,border,maxSearchLevel);
520
void GeodesicSearchInsideIterator::reset(void)
523
maxCount = 1<<(maxLevel<<1); // 4^maxLevel
526
index = (*indexP) * maxCount;
527
count = (indexP < endP) ? 0 : maxCount;
530
int GeodesicSearchInsideIterator::next(void)
532
if (count < maxCount) return index+(count++);
536
index = (*indexP) * maxCount;
540
while (level < maxLevel)
544
indexP = r.zones[level];
545
endP = r.inside[level];
548
index = (*indexP) * maxCount;