PageRenderTime 34ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/kstars/htmesh/SpatialIndex.cpp

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