• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

kstars

  • sources
  • kde-4.12
  • kdeedu
  • kstars
  • kstars
  • htmesh
SpatialIndex.cpp
Go to the documentation of this file.
1 //# Filename: SpatialIndex.cpp
2 //#
3 //# The SpatialIndex class is defined here.
4 //#
5 //# Author: Peter Z. Kunszt based on A. Szalay's code
6 //#
7 //# Date: October 15, 1998
8 //#
9 //# Copyright (C) 2000 Peter Z. Kunszt, Alex S. Szalay, Aniruddha R. Thakar
10 //# The Johns Hopkins University
11 //#
12 //# Modification History:
13 //#
14 //# Oct 18, 2001 : Dennis C. Dinge -- Replaced ValVec with std::vector
15 //# Jul 25, 2002 : Gyorgy Fekete -- Added pointById()
16 //#
17 
18 #include "SpatialIndex.h"
19 #include "SpatialException.h"
20 
21 #ifdef _WIN32
22 #include <malloc.h>
23 #else
24 #ifdef __APPLE__
25 #include <sys/malloc.h>
26 #else
27 #include <cstdlib>
28 #endif
29 #endif
30 
31 #include <cstdio>
32 #include <cmath>
33 // ===========================================================================
34 //
35 // Macro definitions for readability
36 //
37 // ===========================================================================
38 
39 #define N(x) nodes_[(x)]
40 #define V(x) vertices_[nodes_[index].v_[(x)]]
41 #define IV(x) nodes_[index].v_[(x)]
42 #define W(x) vertices_[nodes_[index].w_[(x)]]
43 #define IW(x) nodes_[index].w_[(x)]
44 #define ICHILD(x) nodes_[index].childID_[(x)]
45 
46 #define IV_(x) nodes_[index_].v_[(x)]
47 #define IW_(x) nodes_[index_].w_[(x)]
48 #define ICHILD_(x) nodes_[index_].childID_[(x)]
49 #define IOFFSET 9
50 
51 
52 // ===========================================================================
53 //
54 // Member functions for class SpatialIndex
55 //
56 // ===========================================================================
57 
59 //
60 SpatialIndex::SpatialIndex(size_t maxlevel, size_t buildlevel) : maxlevel_(maxlevel),
61  buildlevel_( (buildlevel == 0 || buildlevel > maxlevel) ? maxlevel : buildlevel)
62 {
63  size_t nodes,vertices;
64 
65  vMax(&nodes,&vertices);
66  layers_.resize(buildlevel_+1); // allocate enough space already
67  nodes_.resize(nodes+1); // allocate space for all nodes
68  vertices_.resize(vertices+1); // allocate space for all vertices
69 
70  N(0).index_ = 0; // initialize invalid node
71 
72  // initialize first layer
73  layers_[0].level_ = 0;
74  layers_[0].nVert_ = 6;
75  layers_[0].nNode_ = 8;
76  layers_[0].nEdge_ = 12;
77  layers_[0].firstIndex_ = 1;
78  layers_[0].firstVertex_ = 0;
79 
80  // set the first 6 vertices
81  float64 v[6][3] = {
82  {0.0L, 0.0L, 1.0L}, // 0
83  {1.0L, 0.0L, 0.0L}, // 1
84  {0.0L, 1.0L, 0.0L}, // 2
85  {-1.0L, 0.0L, 0.0L}, // 3
86  {0.0L, -1.0L, 0.0L}, // 4
87  {0.0L, 0.0L, -1.0L} // 5
88  };
89 
90  for(int i = 0; i < 6; i++)
91  vertices_[i].set( v[i][0], v[i][1], v[i][2]);
92 
93  // create the first 8 nodes - index 1 through 8
94  index_ = 1;
95  newNode(1,5,2,8,0); // S0
96  newNode(2,5,3,9,0); // S1
97  newNode(3,5,4,10,0); // S2
98  newNode(4,5,1,11,0); // S3
99  newNode(1,0,4,12,0); // N0
100  newNode(4,0,3,13,0); // N1
101  newNode(3,0,2,14,0); // N2
102  newNode(2,0,1,15,0); // N3
103 
104  // loop through buildlevel steps, and build the nodes for each layer
105 
106  size_t pl=0;
107  size_t level = buildlevel_;
108  while(level-- > 0) {
109  SpatialEdge edge(*this, pl);
110  edge.makeMidPoints();
111  makeNewLayer(pl);
112  ++pl;
113  }
114 
115  sortIndex();
116 }
117 
119 // nodeVertex: return the vectors of the vertices, based on the ID
120 //
121 void
122 SpatialIndex::nodeVertex(const uint64 id,
123  SpatialVector & v0,
124  SpatialVector & v1,
125  SpatialVector & v2) const {
126 
127  if(buildlevel_ == maxlevel_) {
128  uint32 idx = (uint32)id - leaves_ + IOFFSET; // -jbb: Fix segfault. See "idx =" below.
129  v0 = vertices_[nodes_[idx].v_[0]];
130  v1 = vertices_[nodes_[idx].v_[1]];
131  v2 = vertices_[nodes_[idx].v_[2]];
132  return;
133  }
134 
135  // buildlevel < maxlevel
136  // get the id of the stored leaf that we are in
137  // and get the vertices of the node we want
138  uint64 sid = id >> ((maxlevel_ - buildlevel_)*2);
139  uint32 idx = (uint32)(sid - storedleaves_ + IOFFSET);
140 
141  v0 = vertices_[nodes_[idx].v_[0]];
142  v1 = vertices_[nodes_[idx].v_[1]];
143  v2 = vertices_[nodes_[idx].v_[2]];
144 
145  // loop therough additional levels,
146  // pick the correct triangle accordingly, storing the
147  // vertices in v1,v2,v3
148  for(uint32 i = buildlevel_ + 1; i <= maxlevel_; i++) {
149  uint64 j = ( id >> ((maxlevel_ - i)*2) ) & 3;
150  SpatialVector w0 = v1 + v2; w0.normalize();
151  SpatialVector w1 = v0 + v2; w1.normalize();
152  SpatialVector w2 = v1 + v0; w2.normalize();
153 
154  switch(j) {
155  case 0:
156  v1 = w2;
157  v2 = w1;
158  break;
159  case 1:
160  v0 = v1;
161  v1 = w0;
162  v2 = w2;
163  break;
164  case 2:
165  v0 = v2;
166  v1 = w1;
167  v2 = w0;
168  break;
169  case 3:
170  v0 = w0;
171  v1 = w1;
172  v2 = w2;
173  break;
174  }
175  }
176 }
177 
179 // makeNewLayer: generate a new layer and the nodes in it
180 //
181 void
182 SpatialIndex::makeNewLayer(size_t oldlayer)
183 {
184  uint64 index, id;
185  size_t newlayer = oldlayer + 1;
186  layers_[newlayer].level_ = layers_[oldlayer].level_+1;
187  layers_[newlayer].nVert_ = layers_[oldlayer].nVert_ +
188  layers_[oldlayer].nEdge_;
189  layers_[newlayer].nNode_ = 4 * layers_[oldlayer].nNode_;
190  layers_[newlayer].nEdge_ = layers_[newlayer].nNode_ +
191  layers_[newlayer].nVert_ - 2;
192  layers_[newlayer].firstIndex_ = index_;
193  layers_[newlayer].firstVertex_ = layers_[oldlayer].firstVertex_ +
194  layers_[oldlayer].nVert_;
195 
196  uint64 ioffset = layers_[oldlayer].firstIndex_ ;
197 
198  for(index = ioffset;
199  index < ioffset + layers_[oldlayer].nNode_; index++){
200  id = N(index).id_ << 2;
201  ICHILD(0) = newNode(IV(0),IW(2),IW(1),id++,index);
202  ICHILD(1) = newNode(IV(1),IW(0),IW(2),id++,index);
203  ICHILD(2) = newNode(IV(2),IW(1),IW(0),id++,index);
204  ICHILD(3) = newNode(IW(0),IW(1),IW(2),id,index);
205  }
206 }
207 
209 // newNode: make a new node
210 //
211 uint64
212 SpatialIndex::newNode(size_t v1, size_t v2,size_t v3,uint64 id,uint64 parent)
213 {
214  IV_(0) = v1; // vertex indices
215  IV_(1) = v2;
216  IV_(2) = v3;
217 
218  IW_(0) = 0; // middle point indices
219  IW_(1) = 0;
220  IW_(2) = 0;
221 
222  ICHILD_(0) = 0; // child indices
223  ICHILD_(1) = 0; // index 0 is invalid node.
224  ICHILD_(2) = 0;
225  ICHILD_(3) = 0;
226 
227  N(index_).id_ = id; // set the id
228  N(index_).index_ = index_; // set the index
229  N(index_).parent_ = parent; // set the parent
230 
231  return index_++;
232 }
233 
235 // vMax: compute the maximum number of vertices for the
236 // polyhedron after buildlevel of subdivisions and
237 // the total number of nodes that we store
238 // also, calculate the number of leaf nodes that we eventually have.
239 //
240 void
241 SpatialIndex::vMax(size_t *nodes, size_t *vertices) {
242  uint64 nv = 6; // initial values
243  uint64 ne = 12;
244  uint64 nf = 8;
245  int32 i = buildlevel_;
246  *nodes = (size_t)nf;
247 
248  while(i-->0){
249  nv += ne;
250  nf *= 4;
251  ne = nf + nv -2;
252  *nodes += (size_t)nf;
253  }
254  *vertices = (size_t)nv;
255  storedleaves_ = nf;
256 
257  // calculate number of leaves
258  i = maxlevel_ - buildlevel_;
259  while(i-- > 0)
260  nf *= 4;
261  leaves_ = nf;
262 }
263 
265 // sortIndex: sort the index so that the first node is the invalid node
266 // (index 0), the next 8 nodes are the root nodes
267 // and then we put all the leaf nodes in the following block
268 // in ascending id-order.
269 // All the rest of the nodes is at the end.
270 void
271 SpatialIndex::sortIndex() {
272  std::vector<QuadNode> oldnodes(nodes_); // create a copy of the node list
273  size_t index;
274  size_t nonleaf;
275  size_t leaf;
276 
277 #define ON(x) oldnodes[(x)]
278 
279  // now refill the nodes_ list according to our sorting.
280  for( index=IOFFSET, leaf=IOFFSET, nonleaf=nodes_.size()-1;
281  index < nodes_.size(); index++) {
282 
283  if( ON(index).childID_[0] == 0 ) { // childnode
284  // set leaf into list
285  N(leaf) = ON(index);
286  // set parent's pointer to this leaf
287  for (size_t i = 0; i < 4; i++) {
288  if(N(N(leaf).parent_).childID_[i] == index) {
289  N(N(leaf).parent_).childID_[i] = leaf;
290  break;
291  }
292  }
293  leaf++;
294  } else {
295  // set nonleaf into list from the end
296  // set parent of the children already to this
297  // index, they come later in the list.
298  N(nonleaf) = ON(index);
299  ON(N(nonleaf).childID_[0]).parent_ = nonleaf;
300  ON(N(nonleaf).childID_[1]).parent_ = nonleaf;
301  ON(N(nonleaf).childID_[2]).parent_ = nonleaf;
302  ON(N(nonleaf).childID_[3]).parent_ = nonleaf;
303  // set parent's pointer to this leaf
304  for (size_t i = 0; i < 4; i++) {
305  if(N(N(nonleaf).parent_).childID_[i] == index) {
306  N(N(nonleaf).parent_).childID_[i] = nonleaf;
307  break;
308  }
309  }
310  nonleaf--;
311  }
312  }
313 }
315 // Translate ascii leaf name to a uint32
316 //
317 // The following encoding is used:
318 //
319 // The string leaf name has the always the same structure, it begins with
320 // an N or S, indicating north or south cap and then numbers 0-3 follow
321 // indicating which child to descend into. So for a depth-5-index we have
322 // strings like
323 // N012023 S000222 N102302 etc
324 //
325 // Each of the numbers correspond to 2 bits of code (00 01 10 11) in the
326 // uint32. The first two bits are 10 for S and 11 for N. For example
327 //
328 // N 0 1 2 0 2 3
329 // 11000110001011 = 12683 (dec)
330 //
331 // The leading bits are always 0.
332 //
333 // --- WARNING: This works only up to 15 levels.
334 // (we probably never need more than 7)
335 //
336 
337 uint64
338 SpatialIndex::idByName(const char *name) {
339 
340  uint64 out=0, i;
341  uint32 size = 0;
342 
343  if(name == 0) // null pointer-name
344  throw SpatialFailure("SpatialIndex:idByName:no name given");
345  if(name[0] != 'N' && name[0] != 'S') // invalid name
346  throw SpatialFailure("SpatialIndex:idByName:invalid name",name);
347 
348  size = strlen(name); // determine string length
349  // at least size-2 required, don't exceed max
350  if(size < 2)
351  throw SpatialFailure("SpatialIndex:idByName:invalid name - too short ",name);
352  if(size > HTMNAMEMAX)
353  throw SpatialFailure("SpatialIndex:idByName:invalid name - too long ",name);
354 
355  for(i = size-1; i > 0; i--) {// set bits starting from the end
356  if(name[i] > '3' || name[i] < '0') // invalid name
357  throw SpatialFailure("SpatialIndex:idByName:invalid name digit ",name);
358  out += (uint64(name[i]-'0') << 2*(size - i -1));
359  }
360 
361  i = 2; // set first pair of bits, first bit always set
362  if(name[0]=='N') i++; // for north set second bit too
363  out += (i << (2*size - 2) );
364 
365  /************************
366  // This code may be used later for hashing !
367  if(size==2)out -= 8;
368  else {
369  size -= 2;
370  uint32 offset = 0, level4 = 8;
371  for(i = size; i > 0; i--) { // calculate 4 ^ (level-1), level = size-2
372  offset += level4;
373  level4 *= 4;
374  }
375  out -= level4 - offset;
376  }
377  **************************/
378  return out;
379 }
380 
381 
383 // Translate uint32 to an ascii leaf name
384 //
385 // The encoding described above may be decoded again using the following
386 // procedure:
387 //
388 // * Traverse the uint32 from left to right.
389 // * Find the first 'true' bit.
390 // * The first pair gives N (11) or S (10).
391 // * The subsequent bit-pairs give the numbers 0-3.
392 //
393 
394 char *
395 SpatialIndex::nameById(uint64 id, char * name){
396 
397  uint32 size=0, i;
398 #ifdef _WIN32
399  uint64 IDHIGHBIT = 1;
400  uint64 IDHIGHBIT2= 1;
401  IDHIGHBIT = IDHIGHBIT << 63;
402  IDHIGHBIT2 = IDHIGHBIT2 << 62;
403 #endif
404 
405  /*************
406  // This code might be useful for hashing later !!
407 
408  // calculate the level (i.e. 8*4^level) and add it to the id:
409  uint32 level=0, level4=8, offset=8;
410  while(id >= offset) {
411  if(++level > 13) { ok = false; offset = 0; break; }// level too deep
412  level4 *= 4;
413  offset += level4;
414  }
415  id += 2 * level4 - offset;
416  **************/
417 
418  // determine index of first set bit
419  for(i = 0; i < IDSIZE; i+=2) {
420  if ( (id << i) & IDHIGHBIT ) break;
421  if ( (id << i) & IDHIGHBIT2 ) // invalid id
422  throw SpatialFailure("SpatialIndex:nameById: invalid ID");
423  }
424  if(id == 0)
425  throw SpatialFailure("SpatialIndex:nameById: invalid ID");
426 
427  size=(IDSIZE-i) >> 1;
428  // allocate characters
429  if(!name)
430  name = new char[size+1];
431 
432  // fill characters starting with the last one
433  for(i = 0; i < size-1; i++)
434  name[size-i-1] = '0' + char( (id >> i*2) & 3);
435 
436  // put in first character
437  if( (id >> (size*2-2)) & 1 ) {
438  name[0] = 'N';
439  } else {
440  name[0] = 'S';
441  }
442  name[size] = 0; // end string
443 
444  return name;
445 }
447 // Find a vector for the leaf node given by its ID
448 //
449 void
450 SpatialIndex::pointById(SpatialVector &vec, uint64 ID) const {
451 
452  // uint64 index;
453  float64 center_x, center_y, center_z, sum;
454  char name[HTMNAMEMAX];
455 
456  SpatialVector v0, v1, v2; //
457 
458  this->nodeVertex(ID, v0, v1, v2);
459 
460  nameById(ID, name);
461 /*
462  I started to go this way until I discovered nameByID...
463  Some docs would be nice for this
464 
465  switch(name[1]){
466  case '0':
467  index = name[0] == 'S' ? 1 : 5;
468  break;
469  case '1':
470  index = name[0] == 'S' ? 2 : 6;
471  break;
472  case '2':
473  index = name[0] == 'S' ? 3 : 7;
474  break;
475  case '3':
476  index = name[0] == 'S' ? 4 : 8;
477  break;
478  }
479 */
480 // cerr << "---------- Point by id: " << name << endl;
481 // v0.show(); v1.show(); v2.show();
482  center_x = v0.x_ + v1.x_ + v2.x_;
483  center_y = v0.y_ + v1.y_ + v2.y_;
484  center_z = v0.z_ + v1.z_ + v2.z_;
485  sum = center_x * center_x + center_y * center_y + center_z * center_z;
486  sum = sqrt(sum);
487  center_x /= sum;
488  center_y /= sum;
489  center_z /= sum;
490  vec.x_ = center_x;
491  vec.y_ = center_y;
492  vec.z_ = center_z; // I don't want it nomralized or radec to be set,
493 // cerr << " - - - - " << endl;
494 // vec.show();
495 // cerr << "---------- Point by id Retuning" << endl;
496 }
498 // Find a leaf node where a vector points to
499 //
500 
501 uint64
502 SpatialIndex::idByPoint(const SpatialVector & v) const {
503  uint64 index;
504 
505  // start with the 8 root triangles, find the one which v points to
506  for(index=1; index <=8; index++) {
507  if( (V(0) ^ V(1)) * v < -gEpsilon) continue;
508  if( (V(1) ^ V(2)) * v < -gEpsilon) continue;
509  if( (V(2) ^ V(0)) * v < -gEpsilon) continue;
510  break;
511  }
512  // loop through matching child until leaves are reached
513  while(ICHILD(0)!=0) {
514  uint64 oldindex = index;
515  for(size_t i = 0; i < 4; i++) {
516  index = nodes_[oldindex].childID_[i];
517  if( (V(0) ^ V(1)) * v < -gEpsilon) continue;
518  if( (V(1) ^ V(2)) * v < -gEpsilon) continue;
519  if( (V(2) ^ V(0)) * v < -gEpsilon) continue;
520  break;
521  }
522  }
523  // return if we have reached maxlevel
524  if(maxlevel_ == buildlevel_)return N(index).id_;
525 
526  // from now on, continue to build name dynamically.
527  // until maxlevel_ levels depth, continue to append the
528  // correct index, build the index on the fly.
529  char name[HTMNAMEMAX];
530  nameById(N(index).id_,name);
531  size_t len = strlen(name);
532  SpatialVector v0 = V(0);
533  SpatialVector v1 = V(1);
534  SpatialVector v2 = V(2);
535 
536  size_t level = maxlevel_ - buildlevel_;
537  while(level--) {
538 
539  SpatialVector w0 = v1 + v2; w0.normalize();
540  SpatialVector w1 = v0 + v2; w1.normalize();
541  SpatialVector w2 = v1 + v0; w2.normalize();
542 
543  if(isInside(v, v0, w2, w1)) {
544  name[len++] = '0';
545  v1 = w2; v2 = w1;
546  continue;
547  } else if(isInside(v, v1, w0, w2)) {
548  name[len++] = '1';
549  v0 = v1; v1 = w0; v2 = w2;
550  continue;
551  } else if(isInside(v, v2, w1, w0)) {
552  name[len++] = '2';
553  v0 = v2; v1 = w1; v2 = w0;
554  continue;
555  } else if(isInside(v, w0, w1, w2)) {
556  name[len++] = '3';
557  v0 = w0; v1 = w1; v2 = w2;
558  continue;
559  }
560  }
561  name[len] = '\0';
562  return idByName(name);
563 }
564 
566 // Test whether a vector is inside a triangle. Input triangle has
567 // to be sorted in a counter-clockwise direction.
568 //
569 bool
570 SpatialIndex::isInside(const SpatialVector & v, const SpatialVector & v0,
571  const SpatialVector & v1, const SpatialVector & v2) const
572 {
573  if( (v0 ^ v1) * v < -gEpsilon) return false;
574  if( (v1 ^ v2) * v < -gEpsilon) return false;
575  if( (v2 ^ v0) * v < -gEpsilon) return false;
576  return true;
577 }
IW_
#define IW_(x)
Definition: SpatialIndex.cpp:47
SpatialFailure
SpatialException thrown on operational failure.
Definition: SpatialException.h:102
int32
int int32
Definition: SpatialGeneral.h:55
ICHILD
#define ICHILD(x)
Definition: SpatialIndex.cpp:44
SpatialEdge::makeMidPoints
void makeMidPoints()
Definition: SpatialEdge.cpp:63
gEpsilon
const float64 gEpsilon
Definition: SpatialGeneral.h:88
SpatialIndex::idByName
static uint64 idByName(const char *)
NodeName conversion to integer ID.
Definition: SpatialIndex.cpp:338
SpatialIndex::nameById
static char * nameById(uint64 ID, char *name=0)
int32 conversion to a string (name of database).
Definition: SpatialIndex.cpp:395
SpatialIndex::pointById
void pointById(SpatialVector &vector, uint64 ID) const
find the vector to the centroid of a triangle represented by the ID
Definition: SpatialIndex.cpp:450
SpatialVector
The SpatialVector is a 3D vector usually living on the surface of the sphere.
Definition: SpatialVector.h:32
IDHIGHBIT2
#define IDHIGHBIT2
Definition: SpatialGeneral.h:127
SpatialIndex.h
IW
#define IW(x)
Definition: SpatialIndex.cpp:43
SpatialIndex::SpatialIndex
SpatialIndex(size_t maxlevel, size_t buildlevel=5)
Constructor.
Definition: SpatialIndex.cpp:60
IV_
#define IV_(x)
Definition: SpatialIndex.cpp:46
IOFFSET
#define IOFFSET
Definition: SpatialIndex.cpp:49
SpatialIndex::idByPoint
uint64 idByPoint(const SpatialVector &vector) const
find a node by giving a vector.
Definition: SpatialIndex.cpp:502
SpatialIndex::nodeVertex
void nodeVertex(const uint64 id, SpatialVector &v1, SpatialVector &v2, SpatialVector &v3) const
return the actual vertex vectors
Definition: SpatialIndex.cpp:122
SpatialEdge
Definition: SpatialEdge.h:43
V
#define V(x)
Definition: SpatialIndex.cpp:40
N
#define N(x)
Definition: SpatialIndex.cpp:39
ICHILD_
#define ICHILD_(x)
Definition: SpatialIndex.cpp:48
uint64
unsigned long long uint64
Definition: SpatialGeneral.h:69
IDHIGHBIT
#define IDHIGHBIT
Definition: SpatialGeneral.h:126
IDSIZE
#define IDSIZE
Definition: SpatialGeneral.h:77
ON
#define ON(x)
IV
#define IV(x)
Definition: SpatialIndex.cpp:41
SpatialException.h
float64
double float64
Definition: SpatialGeneral.h:58
HTMNAMEMAX
#define HTMNAMEMAX
Definition: SpatialGeneral.h:78
uint32
unsigned int uint32
Definition: SpatialGeneral.h:56
SpatialVector::normalize
void normalize()
Normalize vector length to 1.
Definition: SpatialVector.cpp:110
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:36:21 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kstars

Skip menu "kstars"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal