• 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
RangeConvex.cpp
Go to the documentation of this file.
1 //# Filename: RangeConvex.cpp # # The RangeConvex # classes are
2 //defined here. # # Author: Peter Z. Kunszt based on A. Szalay's code
3 //# # Date: October 23, 1998 # # Copyright (C) 2000 Peter Z. Kunszt,
4 //Alex S. Szalay, Aniruddha R. Thakar # The Johns Hopkins University #
5 //# Modification History: # # Oct 18, 2001 : Dennis C. Dinge --
6 //Replaced ValVec with std::vector
7 
8 
9 #include "SpatialGeneral.h"
10 #include "RangeConvex.h"
11 
12 
13 #define N(n) index_->nodes_[(n)]
14 #define NC(n,m) index_->nodes_[(n)].childID_[(m)] // the children n->m
15 #define NV(m) index_->nodes_[id].v_[(m)] // the vertices of n
16 #define V(m) index_->vertices_[(m)] // the vertex vector m
17 
18 #define SGN(x) ( (x)<0? -1: ( (x)>0? 1:0 ) ) // signum
19 
20 // ===========================================================================
21 //
22 // Member functions for class RangeConvex
23 //
24 // ===========================================================================
25 
26 RangeConvex::RangeConvex()
27 {}
28 
30 //
31 // Initialize convex from a triangle. The corners of these vectors
32 // form a triangle, so we just add three ZERO constraints to the convex
33 // where the direction is given by the cross product of the corners.
34 // Of course, the sign has to be determined (on which side of the triangle
35 // are we?) If the three points lie on one line, no constraints are added.
36 //
37 RangeConvex::RangeConvex(const SpatialVector * v1,
38  const SpatialVector * v2,
39  const SpatialVector * v3)
40 {
41  SpatialVector a1 = (*v2) ^ (*v3); // set directions of half-spheres
42  SpatialVector a2 = (*v3) ^ (*v1);
43  SpatialVector a3 = (*v1) ^ (*v2);
44  float64 s1 = a1 * (*v1); // we really need only the signs of these
45  float64 s2 = a2 * (*v2);
46  float64 s3 = a3 * (*v3);
47 
48  if(s1 * s2 * s3) { // this is nonzero if not on one line
49  if(s1 < 0.0L) a1 = (-1) * a1 ; // change sign if necessary
50  if(s2 < 0.0L) a2 = (-1) * a2 ;
51  if(s3 < 0.0L) a3 = (-1) * a3 ;
52  constraints_.push_back(SpatialConstraint(a1,0.0)); // we don't care about the
53  constraints_.push_back(SpatialConstraint(a2,0.0)); // order since all angles are
54  constraints_.push_back(SpatialConstraint(a3,0.0)); // 90 degrees.
55  }
56  sign_ = zERO;
57 }
58 
60 //
61 // Initialize convex from a rectangle. The vectors that form a rectangle
62 // may be in any order, the code finds the edges by itself.
63 // If one of the vectors lies within the triangle formed by the
64 // other three vectors, the previous constructor is used.
65 //
66 RangeConvex::RangeConvex(const SpatialVector * v1,
67  const SpatialVector * v2,
68  const SpatialVector * v3,
69  const SpatialVector * v4)
70 {
71  int i,j,k,l,m; // indices
72  // to simplify things, copy input into a 4-array
73  const SpatialVector *v[4] = {v1,v2,v3,v4};
74  SpatialVector d[6];
75  float64 s[6][2];
76  for (i = 0, k = 0; i < 4 ; i++)
77  for (j = i+1; j < 4; j++, k++) { // set directions of half-spheres
78  d[k] = (*v[i]) ^ (*v[j]); // two of these are diagonals.
79  d[k].normalize();
80  for (l = 0, m = 0; l < 4; l++)
81  if(l != i && l != j)s[k][m++] = d[k] * (*v[l]); // set the 'sign'
82  }
83 
84  // the sides are characterized by having both other corners
85  // to the same (inner) side. so it is easy to find the edges.
86  // again, the sign has to be taken care of -> direction of d
87  // the nice thing here is that if one of the corners is inside
88  // a triangles formed by the other three, only 3 constraints get
89  // added.
90  for(i = 0; i < 6; i++)
91  if(s[i][0] * s[i][1] > 0.0) // not >= because we don't want aligned corners
92  constraints_.push_back(SpatialConstraint((s[i][0] > 0.0 ?
93  d[i] : (-1 * d[i])), 0.0));
94 
95  // Special cases: 1
96  // if three of the corners are aligned, we end up with
97  // only two constraints. Find the third and append it.
98  // Indeed, there are 3 identical constraints among the d[],
99  // so the first that qualifies gets appended.
100  if(constraints_.size() == 2) {
101  for(i = 0; i < 6; i++)
102  if(s[i][0] == 0.0 || s[i][1] == 0.0) {
103  constraints_.push_back(SpatialConstraint( ((s[i][0]+s[i][1]) > 0.0 ?
104  d[i] : (-1 * d[i])), 0.0));
105  break;
106  }
107  }
108  // Special cases: 2
109  // if all four corners are aligned, no constraints have been appended.
110  sign_ = zERO;
111 }
112 
114 //
115 void RangeConvex::add(SpatialConstraint & c)
116 {
117  constraints_.push_back(c);
118  // order constraints: by ascending opening angle. Since we append
119  // always at the end, we only need one ordering sweep starting at
120  // the end
121  for ( size_t i = constraints_.size() - 1; i > 0; i-- ) {
122  if ( constraints_[i].s_ < constraints_[i-1].s_ ) {
123  SpatialConstraint tmp( constraints_[i] );
124  constraints_[i] = constraints_[i-1];
125  constraints_[i-1] = tmp;
126  }
127  }
128 
129  if(constraints_.size() == 1) { // first constraint
130  sign_ = c.sign_;
131  return;
132  }
133 
134  switch (sign_) {
135  case nEG:
136  if(c.sign_ == pOS) sign_ = mIXED;
137  break;
138  case pOS:
139  if(c.sign_ == nEG) sign_ = mIXED;
140  break;
141  case zERO:
142  sign_ = c.sign_;
143  break;
144  case mIXED:
145  break;
146  }
147 }
148 
149 
151 // simplify0: simplify zERO convexes. calculate corners of convex
152 // and the bounding circle.
153 //
154 // zERO convexes are made up of constraints which are all great
155 // circles. It can happen that some of the constraints are redundant.
156 // For example, if 3 of the great circles define a triangle as the convex
157 // which lies fully inside the half sphere of the fourth constraint,
158 // that fourth constraint is redundant and will be removed.
159 //
160 // The algorithm is the following:
161 //
162 // zero-constraints are half-spheres, defined by a single normalized
163 // vector v, pointing in the direction of that half-sphere.
164 //
165 // Two zero-constraints intersect at
166 //
167 // i = +- v x v
168 // 1,2 1 2
169 //
170 // the vector cross product of their two defining vectors.
171 //
172 // The two vectors i1,2 are tested against every other constraint in
173 // the convex if they lie within their half-spheres. Those
174 // intersections i which lie within every other constraint, are stored
175 // into corners_.
176 //
177 // Constraints that do not have a single corner on them, are dropped.
178 //
179 
180 void
181 RangeConvex::simplify0() {
182 
183  size_t i,j,k;
184  SpatialVector vi1, vi2;
185  std::vector<size_t> cornerConstr1, cornerConstr2, removeConstr;
186  std::vector<SpatialVector> corner;
187  if (constraints_.size() == 1) { // for one constraint, it is itself the BC
188  boundingCircle_ = constraints_[0];
189  return;
190  // For 2 constraints, take the bounding circle a 0-constraint...
191  // this is by no means optimal, but the code is optimized for at least
192  // 3 zERO constraints... so this is acceptable.
193  } else if(constraints_.size() == 2) {
194  // test for constraints being identical - rule 1 out
195  if(constraints_[0].a_ == constraints_[1].a_){
196  constraints_.erase(constraints_.end()-1);
197  boundingCircle_ = constraints_[0];
198  return;
199  }
200  // test for constraints being two disjoint half spheres - empty convex!
201  if(constraints_[0].a_ == (-1.0)*constraints_[1].a_){
202  constraints_.clear();
203  return;
204  }
205  boundingCircle_ = SpatialConstraint(constraints_[0].v() +
206  constraints_[1].v(),0);
207  return;
208  }
209 
210  // Go over all pairs of constraints
211  for(i = 0; i < constraints_.size() - 1; i++) {
212  bool ruledout = true;
213  for(j = i+1; j < constraints_.size(); j ++) {
214  // test for constraints being identical - rule i out
215  if(constraints_[i].a_ == constraints_[j].a_) break;
216  // test for constraints being two disjoint half spheres - empty convex!
217  if(constraints_[i].a_ == (-1.0)*constraints_[j].a_){
218  constraints_.clear();
219  return;
220  }
221  // vi1 and vi2 are their intersection points
222  vi1 = constraints_[i].a_ ^ constraints_[j].a_ ;
223  vi1.normalize();
224  vi2 = (-1.0) * vi1;
225  bool vi1ok = true, vi2ok = true;
226  // now test whether vi1 or vi2 or both are inside every other constraint.
227  // if yes, store them in the corner array.
228  for(k = 0; k < constraints_.size(); k++) {
229  if(k == i || k == j) continue;
230  if(vi1ok && vi1 * constraints_[k].a_ <= 0.0) vi1ok = false;
231  if(vi2ok && vi2 * constraints_[k].a_ <= 0.0) vi2ok = false;
232  if(!vi1ok && !vi2ok) break;
233  }
234  if(vi1ok) {
235  corner.push_back(vi1);
236  cornerConstr1.push_back(i);
237  cornerConstr2.push_back(j);
238  ruledout = false;
239  }
240  if(vi2ok) {
241  corner.push_back(vi2);
242  cornerConstr1.push_back(i);
243  cornerConstr2.push_back(j);
244  ruledout = false;
245  }
246  }
247  // is this constraint ruled out? i.e. none of its intersections
248  // with other constraints are corners... remove it from constraints_ list.
249  if(ruledout) removeConstr.push_back(i);
250  }
251 
252  // Now set the corners into their correct order, which is an
253  // anti-clockwise walk around the polygon.
254  //
255  // start at any corner. so take the first.
256 
257  corners_.clear();
258  corners_.push_back(corner[0]);
259 
260  // The trick is now to start off into the correct direction.
261  // this corner has two edges it can walk. we have to take the
262  // one where the convex lies on its left side.
263  i = cornerConstr1[0]; // the i'th constraint and j'th constraint
264  j = cornerConstr2[0]; // intersect at 0'th corner
265  size_t c1(0),c2(0),k1(0),k2(0);
266  // Now find the other corner where the i'th and j'th constraints intersect.
267  // Store the corner in vi1 and vi2, and the other constraint indices
268  // in c1,c2.
269  for( k = 1; k < cornerConstr1.size(); k ++) {
270  if(cornerConstr1[k] == i) {
271  vi1 = corner[k];
272  c1 = cornerConstr2[k];
273  k1 = k;
274  }
275  if(cornerConstr2[k] == i) {
276  vi1 = corner[k];
277  c1 = cornerConstr1[k];
278  k1 = k;
279  }
280  if(cornerConstr1[k] == j) {
281  vi2 = corner[k];
282  c2 = cornerConstr2[k];
283  k2 = k;
284  }
285  if(cornerConstr2[k] == j) {
286  vi2 = corner[k];
287  c2 = cornerConstr1[k];
288  k2 = k;
289  }
290  }
291  // Now test i'th constraint-edge ( corner 0 and corner k ) whether
292  // it is on the correct side (left)
293  //
294  // ( (corner(k) - corner(0)) x constraint(i) ) * corner(0)
295  //
296  // is >0 if yes, <0 if no...
297  //
298  size_t c,currentCorner;
299  if( ((vi1 - corner[0]) ^ constraints_[i].a_) * corner[0] > 0 ) {
300  corners_.push_back(vi1);
301  c = c1;
302  currentCorner = k1;
303  } else {
304  corners_.push_back(vi2);
305  c = c2;
306  currentCorner = k2;
307  }
308  // now append the corners that match the index c until we got corner 0 again
309  // currentCorner holds the current corners index
310  // c holds the index of the constraint that has just been intersected with
311  // So:
312  // x We are on a constraint now (i or j from before), the second corner
313  // is the one intersecting with constraint c.
314  // x Find other corner for constraint c.
315  // x Save that corner, and set c to the constraint that intersects with c
316  // at that corner. Set currentcorner to that corners index.
317  // x Loop until 0th corner reached.
318  while( currentCorner ) {
319  for (k = 0; k < cornerConstr1.size(); k++) {
320  if(k == currentCorner)continue;
321  if(cornerConstr1[k] == c) {
322  if( (currentCorner = k) == 0) break;
323  corners_.push_back(corner[k]);
324  c = cornerConstr2[k];
325  break;
326  }
327  if(cornerConstr2[k] == c) {
328  if( (currentCorner = k) == 0) break;
329  corners_.push_back(corner[k]);
330  c = cornerConstr1[k];
331  break;
332  }
333  }
334  }
335  // Remove all redundant constraints
336  for ( i = 0; i < removeConstr.size(); i++)
337  constraints_.erase(constraints_.end()-removeConstr[i]-1);
338 
339  // Now calculate the bounding circle for the convex.
340  // We take it as the bounding circle of the triangle with
341  // the widest opening angle. All triangles made out of 3 corners
342  // are considered.
343  boundingCircle_.d_ = 1.0;
344  if (constraints_.size() >=3 ) {
345  for(i = 0; i < corners_.size(); i++)
346  for(j = i+1; j < corners_.size(); j++)
347  for(k = j+1; k < corners_.size(); k++) {
348  SpatialVector v = ( corners_[j] - corners_[i] ) ^
349  ( corners_[k] - corners_[j] );
350  v.normalize();
351  // Set the correct opening angle: Since the plane cutting
352  // out the triangle also correctly cuts out the bounding cap
353  // of the triangle on the sphere, we can take any corner to
354  // calculate the opening angle
355  float64 d = v * corners_[i];
356  if(boundingCircle_.d_ > d) boundingCircle_ = SpatialConstraint(v,d);
357  }
358  }
359 }
360 
362 // simplify: We have the following decision tree for the
363 // simplification of convexes:
364 //
365 // Always test two constraints against each other. We have
366 //
367 // * If both constraints are pOS
368 // # If they intersect: keep both
369 // # If one lies in the other: drop the larger one
370 // # Else: disjunct. Empty convex, stop.
371 //
372 // * If both constraints are nEG
373 // # If they intersect or are disjunct: ok
374 // # Else: one lies in the other, drop smaller 'hole'
375 //
376 // * Mixed: one pOS, one nEG
377 // # No intersection, disjunct: pOS is redundant
378 // # Intersection: keep both
379 // # pOS within nEG: empty convex, stop.
380 // # nEG within pOS: keep both.
381 //
382 
383 void
384 RangeConvex::simplify() {
385 
386  if(sign_ == zERO) {
387  simplify0(); // treat zERO convexes separately
388  return;
389  }
390 
391  size_t i,j;
392  size_t clen;
393  bool redundancy = true;
394 
395  while(redundancy) {
396  redundancy = false;
397  clen = constraints_.size();
398 
399  for(i = 0; i < clen; i++) {
400  for(j = 0; j < i; j++) {
401  int test;
402 
403  // don't bother with two zero constraints
404  if( constraints_[i].sign_ == zERO && constraints_[j].sign_ == zERO)
405  continue;
406 
407  // both pos or zero
408  if( ( constraints_[i].sign_ == pOS || constraints_[i].sign_ == zERO ) &&
409  ( constraints_[j].sign_ == pOS || constraints_[j].sign_ == zERO ) ) {
410  if ( (test = testConstraints(i,j)) == 0 ) continue; // intersection
411  if ( test < 0 ) { // disjoint ! convex is empty
412  constraints_.clear();
413  return;
414  }
415  // one is redundant
416  if(test == 1) constraints_.erase(constraints_.end()-i-1);
417  else if(test==2) constraints_.erase(constraints_.end()-j-1);
418  else continue; // intersection
419  redundancy = true; // we did cut out a constraint -> do the loop again
420  break;
421  }
422 
423  // both neg or zero
424  if( ( constraints_[i].sign_ == nEG ) &&
425  ( constraints_[j].sign_ == nEG ) ) {
426  if ( (test = testConstraints(i,j)) <= 0 ) continue; // ok
427  // one is redundant
428  if(test == 1) constraints_.erase(constraints_.end()-1-j);
429  else if(test==2) constraints_.erase(constraints_.end()-1-i);
430  else continue; // intersection
431  redundancy = true; // we did cut out a constraint -> do the loop again
432  break;
433  }
434 
435  // one neg, one pos/zero
436  if( (test = testConstraints(i,j)) == 0) continue; // ok: intersect
437  if( test < 0 ) { // neg is redundant
438  if ( constraints_[i].sign_ == nEG ) constraints_.erase(constraints_.end()-1-i);
439  else constraints_.erase(constraints_.end()-1-j);
440  redundancy = true; // we did cut out a constraint -> do the loop again
441  break;
442  }
443  // if the negative constraint is inside the positive: continue
444  if ( (constraints_[i].sign_ == nEG && test == 2) ||
445  (constraints_[j].sign_ == nEG && test == 1) ) continue;
446  // positive constraint in negative: convex is empty!
447  constraints_.clear();
448  return;
449  }
450  if(redundancy) break;
451  }
452 
453  }
454 
455  // reset the sign of the convex
456  sign_ = constraints_[0].sign_;
457  for(i = 1; i < constraints_.size(); i++) {
458  switch (sign_) {
459  case nEG:
460  if(constraints_[i].sign_ == pOS) sign_ = mIXED;
461  break;
462  case pOS:
463  if(constraints_[i].sign_ == nEG) sign_ = mIXED;
464  break;
465  case zERO:
466  sign_ = constraints_[i].sign_;
467  break;
468  case mIXED:
469  break;
470  }
471  }
472 
473  if (constraints_.size() == 1) // for one constraint, it is itself the BC
474  boundingCircle_ = constraints_[0];
475  else if (sign_ == pOS)
476  boundingCircle_ = constraints_[0];
477 
478 }
479 
481 // testConstraints: Test for the relative position of two constraints.
482 // Returns 0 if they intersect
483 // Returns -1 if they are disjoint
484 // Returns 1 if j is in i
485 // Returns 2 if i is in j
486 //
487 int
488 RangeConvex::testConstraints(size_t i, size_t j) {
489 
490  float64 phi = (
491  (constraints_[i].sign_ == nEG ? (-1 * constraints_[i].a_):
492  constraints_[i].a_ )
493  *
494  (constraints_[j].sign_ == nEG ? (-1 * constraints_[j].a_):
495  constraints_[j].a_ )
496  );
497  phi = (phi <= -1.0L + gEpsilon ? gPi : acos(phi)) ; // correct for math lib -1.0
498  float64 a1 = (constraints_[i].sign_ == pOS ?
499  constraints_[i].s_ : gPi-constraints_[i].s_);
500  float64 a2 = (constraints_[j].sign_ == pOS ?
501  constraints_[j].s_ : gPi-constraints_[j].s_);
502 
503  if ( phi > a1 + a2 ) return -1;
504  if ( a1 > phi + a2 ) return 1;
505  if ( a2 > phi + a1 ) return 2;
506  return 0;
507 }
508 
510 // used by intersect.cpp application
511 //
512 void
513 RangeConvex::intersect(const SpatialIndex * idx, HtmRange * htmrange)
514 {
515  hr = htmrange;
516  index_ = idx;
517  addlevel_ = idx->maxlevel_ - idx->buildlevel_;
518 
519  simplify(); // don't work too hard...
520 
521  if(constraints_.empty())return; // nothing to intersect!!
522 
523  // Start with root nodes (index = 1-8) and intersect triangles
524  for(uint32 i = 1; i <= 8; i++){
525  testTrixel(i);
526  }
527 }
528 
530 //
531 inline void RangeConvex::saveTrixel(uint64 htmid)
532 {
533 
534  // Some application want a complete htmid20 range
535  //
536  int level, i, shifts;
537  uint64 lo, hi;
538 #ifdef _WIN32
539  uint64 IDHIGHBIT = 1;
540  uint64 IDHIGHBIT2= 1;
541  IDHIGHBIT = IDHIGHBIT << 63;
542  IDHIGHBIT2 = IDHIGHBIT2 << 62;
543 #endif
544 
545  for(i = 0; i < IDSIZE; i+=2) {
546  if ( (htmid << i) & IDHIGHBIT ) break;
547  }
548 
549  level = (IDSIZE-i) >> 1;
550  level -= 2;
551  if (level < olevel){
552  /* Size is the length of the string representing the name of the
553  trixel, the level is size - 2
554  */
555  shifts = (olevel - level) << 1;
556  lo = htmid << shifts;
557  hi = lo + ((uint64) 1 << shifts) -1;
558  } else {
559  lo = hi = htmid;
560  }
561  hr->mergeRange(lo, hi);
562 
563  return;
564 }
565 
567 // testTrixel: this is the main test of a triangle vs a Convex. It
568 // will properly mark up the flags for the triangular node[index], and
569 // all its children
570 SpatialMarkup
571 RangeConvex::testTrixel(uint64 id)
572 {
573  SpatialMarkup mark;
574  uint64 childID;
575  uint64 tid;
576 
577  // const struct SpatialIndex::QuadNode &indexNode = index_->nodes_[id];
578  const struct SpatialIndex::QuadNode *indexNode = &index_->nodes_[id];
579 
580  //
581  // do the face test on the triangle
582 
583  // was: mark = testNode(V(NV(0)),V(NV(1)),V(NV(2)));
584  // changed to by Gyorgy Fekete. Overall Speedup approx. 2%
585 
586  mark = testNode(id); // was:(indexNode or id);
587 
588 
589  switch(mark){
590  case fULL:
591  tid = N(id).id_;
592 
593  saveTrixel(tid); //was: plist_->push_back(tid);
594 
595  return mark;
596  case rEJECT:
597  tid = N(id).id_;
598  return mark;
599  default:
600  // if pARTIAL or dONTKNOW, then continue, test children,
601  // but do not reach beyond the leaf nodes.
602  // If Convex is fully contained within one (sWALLOWED),
603  // we can stop looking further in another child
604 
605  // #define NC(n,m) index_->nodes_[(n)].childID_[(m)] // the children n->m
606  // childID = index_->nodes_[id].childID_[0];
607 
608  // Test how many of the four children are rejected?
609  //
610  // [ed:algo]
611  //
612  break;
613  }
614 
615  // NEW NEW algorithm Disabled when enablenew is 0
616  //
617  {
618  childID = indexNode->childID_[0];
619  if ( childID != 0){
621  tid = N(id).id_;
622  childID = indexNode->childID_[0]; testTrixel(childID);
623  childID = indexNode->childID_[1]; testTrixel(childID);
624  childID = indexNode->childID_[2]; testTrixel(childID);
625  childID = indexNode->childID_[3]; testTrixel(childID);
626  } else {
627  if (addlevel_){
628  testPartial(addlevel_, N(id).id_, V(NV(0)), V(NV(1)), V(NV(2)), 0);
629  } else {
630  saveTrixel(N(id).id_); // was: plist_->push_back(N(id).id_);
631  }
632  }
633  }
634 
635 
636 
637  /* NEW NEW NEW
638  If rejected, then we return [done]
639  If full, then we list the id (propagate to children) [done]
640 
641  If partial, then we look ahead to see how many children are rejected.
642  But ah, next iteration could benefit from having computed this already.
643 
644  If two chidlren are rejected, then we stop
645  If one or 0 nodes are rejected, then we
646  */
647  return mark;
648 }
649 
650 
652 // testPartial: test a triangle's subtriangle whether they are partial.
653 // if level is nonzero, recurse.
654 //
655 void
656 RangeConvex::testPartial(size_t level, uint64 id,
657  const SpatialVector & v0,
658  const SpatialVector & v1,
659  const SpatialVector & v2, int PPrev)
660 {
661  uint64 ids[4], id0;
662  SpatialMarkup m[4];
663  int P, F;// count number of partials and fulls
664 
665  SpatialVector w0 = v1 + v2; w0.normalize();
666  SpatialVector w1 = v0 + v2; w1.normalize();
667  SpatialVector w2 = v1 + v0; w2.normalize();
668 
669  ids[0] = id0 = id << 2;
670  ids[1] = id0 + 1;
671  ids[2] = id0 + 2;
672  ids[3] = id0 + 3;
673 
674  m[0] = testNode(v0, w2, w1);
675  m[1] = testNode(v1, w0, w2);
676  m[2] = testNode(v2, w1, w0);
677  m[3] = testNode(w0, w1, w2);
678 
679  F = (m[0] == fULL) + (m[1] == fULL) + (m[2] == fULL) + (m[3] == fULL);
680  P = (m[0] == pARTIAL) + (m[1] == pARTIAL) + (m[2] == pARTIAL) + (m[3] == pARTIAL);
681 
682  //
683  // Several interesting cases for saving this (the parent) trixel.
684  // Case P==4, all four children are partials, so pretend parent is full, we save and return
685  // Case P==3, and F==1, most of the parent is in, so pretend that parent is full again
686  // Case P==2 or 3, but the previous testPartial had three partials, so parent was in an arc
687  // as opposed to previous partials being fewer, so parent was in a tiny corner...
688 
689 
690  if ((level-- <= 0) || ((P == 4) || (F >= 2) || (P == 3 && F == 1) || (P > 1 && PPrev == 3))){
691  saveTrixel(id);
692  return;
693  } else {
694  // look at each child, see if some need saving;
695  for(int i=0; i<4; i++){
696  if (m[i] == fULL){
697  saveTrixel(ids[i]);
698  }
699  }
700  // look at the four kids again, for partials
701 
702  if (m[0] == pARTIAL) testPartial(level, ids[0], v0, w2, w1, P);
703  if (m[1] == pARTIAL) testPartial(level, ids[1], v1, w0, w2, P);
704  if (m[2] == pARTIAL) testPartial(level, ids[2], v2, w1, w0, P);
705  if (m[3] == pARTIAL) testPartial(level, ids[3], w0, w1, w2, P);
706  }
707 }
708 
710 // testNode: tests the QuadNodes for intersections.
711 //
712 SpatialMarkup
713 RangeConvex::testNode(uint64 id)
714 //uint64 id)
715 // const struct SpatialIndex::QuadNode *indexNode)
716 {
717  const SpatialVector *v0, *v1, *v2;
718  // const struct SpatialIndex::QuadNode &indexNode = index_->nodes_[id];
719  const struct SpatialIndex::QuadNode *indexNode = &index_->nodes_[id];
720  int m;
721  m = indexNode->v_[0];
722  v0 = &index_->vertices_[m]; // the vertex vector m
723 
724  m = indexNode->v_[1];
725  v1 = &index_->vertices_[m];
726 
727  m = indexNode->v_[2];
728  v2 = &index_->vertices_[m];
729 
730  // Start with testing the vertices for the QuadNode with this convex.
731  int vsum = testVertex(v0) + testVertex(v1) + testVertex(v2);
732 
733  SpatialMarkup mark =
734  testTriangle( *v0, *v1, *v2, vsum);
735 
736  // since we cannot play games using the on-the-fly triangles,
737  // substitute dontknow with partial.
738  if (mark == dONTKNOW)
739  mark = pARTIAL;
740 
741  return mark;
742 }
743 SpatialMarkup
744 RangeConvex::testNode(const SpatialVector & v0,
745  const SpatialVector & v1,
746  const SpatialVector & v2) {
747  // Start with testing the vertices for the QuadNode with this convex.
748 
749  int vsum = testVertex(v0) + testVertex(v1) + testVertex(v2);
750 
751  SpatialMarkup mark =
752  testTriangle( v0, v1, v2, vsum);
753 
754  // since we cannot play games using the on-the-fly triangles,
755  // substitute dontknow with partial.
756  if (mark == dONTKNOW)
757  mark = pARTIAL;
758 
759  return mark;
760 }
761 
763 // testTriangle: tests a triangle given by 3 vertices if
764 // it intersects the convex.
765 //
766 SpatialMarkup
767 RangeConvex::testTriangle(const SpatialVector & v0,
768  const SpatialVector & v1,
769  const SpatialVector & v2,
770  int vsum) {
771 
772  if(vsum == 1 || vsum == 2) return pARTIAL;
773 
774  // If vsum = 3 then we have all vertices inside the convex.
775  // Now use the following decision tree:
776  //
777  // * If the sign of the convex is pOS or zERO : mark as fULL intersection.
778  //
779  // * Else, test for holes inside the triangle. A 'hole' is a nEG constraint
780  // that has its center inside the triangle. If there is such a hole,
781  // return pARTIAL intersection.
782  //
783  // * Else (no holes, sign nEG or mIXED) test for intersection of nEG
784  // constraints with the edges of the triangle. If there are such,
785  // return pARTIAL intersection.
786  //
787  // * Else return fULL intersection.
788 
789  if(vsum == 3) {
790  if(sign_ == pOS || sign_ == zERO) return fULL;
791  if ( testHole(v0,v1,v2) ) return pARTIAL;
792  if ( testEdge(v0,v1,v2) ) return pARTIAL;
793  return fULL;
794  }
795 
796  // If we have reached that far, we have vsum=0. There is no definite
797  // decision making possible here with our methods, the markup may result
798  // in dONTKNOW. The decision tree is the following:
799  //
800  // * Test with bounding circle of the triangle.
801  //
802  // # If the sign of the convex zERO test with the precalculated
803  // bounding circle of the convex. If it does not intersect with the
804  // triangle's bounding circle, rEJECT.
805  //
806  // # If the sign of the convex is nonZERO: if the bounding circle
807  // lies outside of one of the constraints, rEJECT.
808  //
809  // * Else: there was an intersection with the bounding circle.
810  //
811  // # For zERO convexes, test whether the convex intersects the edges.
812  // If none of the edges of the convex intersects with the edges of
813  // the triangle, we have a rEJECT. Else, pARTIAL.
814  //
815  // # If sign of convex is pOS, or miXED and the smallest constraint does
816  // not intersect the edges and has its center inside the triangle,
817  // return sWALLOW. If no intersection of edges and center outside
818  // triangle, return rEJECT.
819  //
820  // # So the smallest constraint DOES intersect with the edges. If
821  // there is another pOS constraint which does not intersect with
822  // the edges, and has its center outside the triangle, return
823  // rEJECT. If its center is inside the triangle return sWALLOW.
824  // Else, return pARTIAL for pOS and dONTKNOW for mIXED signs.
825  //
826  // * If we are here, return dONTKNOW. There is an intersection with
827  // the bounding circle, none of the vertices is inside the convex and
828  // we have very strange possibilities left for pOS and mIXED signs. For
829  // nEG, i.e. all constraints negative, we also have some complicated
830  // things left for which we cannot test further.
831 
832  if ( !testBoundingCircle(v0,v1,v2) ) return rEJECT;
833 
834  if ( sign_ == pOS || sign_ == mIXED || (sign_ == zERO && constraints_.size() <= 2)) {
835  // Does the smallest constraint intersect with the edges?
836  if ( testEdgeConstraint(v0,v1,v2,0) ) {
837  // Is there another positive constraint that does NOT intersect with
838  // the edges?
839  size_t cIndex;
840  if ( (cIndex = testOtherPosNone(v0,v1,v2)) ) {
841  // Does that constraint lie inside or outside of the triangle?
842  if ( testConstraintInside(v0,v1,v2, cIndex) )
843  return pARTIAL;
844  // Does the triangle lie completely within that constr?
845  else if( constraints_[cIndex].contains(v0) )
846  return pARTIAL;
847  else return rEJECT;
848 
849  } else {
850  if(sign_ == pOS || sign_ == zERO) return pARTIAL;
851  else return dONTKNOW;
852  }
853  } else {
854  if (sign_ == pOS || sign_ == zERO) {
855  // Does the smallest lie inside or outside the triangle?
856  if( testConstraintInside(v0,v1,v2, 0) )
857  return pARTIAL;
858  else return rEJECT;
859  } else return dONTKNOW;
860  }
861  } else if (sign_ == zERO) {
862  if ( corners_.size() > 0 && testEdge0(v0,v1,v2) )
863  return pARTIAL;
864  else return rEJECT;
865  }
866  return pARTIAL;
867 }
868 
870 // testVertex: same as above, but for any spatialvector, no markup speedup
871 //
872 int
873 RangeConvex::testVertex(const SpatialVector & v)
874 {
875  for ( size_t i = 0; i < constraints_.size(); i++)
876  if ( (constraints_[i].a_ * v ) < constraints_[i].d_ )
877  return 0;
878 
879  return 1;
880 }
881 int
882 RangeConvex::testVertex(const SpatialVector *v)
883 {
884  for ( size_t i = 0; i < constraints_.size(); i++)
885  if ( (constraints_[i].a_ * *v ) < constraints_[i].d_ )
886  return 0;
887 
888  return 1;
889 }
890 
892 // testHole: test for holes. If there is a negative constraint whose center
893 // is inside the triangle, we speak of a hole. Returns true if
894 // found one.
895 //
896 bool
897 RangeConvex::testHole(const SpatialVector & v0,
898  const SpatialVector & v1,
899  const SpatialVector & v2) {
900 
901  bool test = false;
902 
903  for(size_t i = 0; i < constraints_.size(); i++) {
904  if ( constraints_[i].sign_ == nEG ) { // test only 'holes'
905 
906  // If (a ^ b * c) < 0, vectors abc point clockwise.
907  // -> center c not inside triangle, since vertices a,b are ordered
908  // counter-clockwise. The comparison here is the other way
909  // round because c points into the opposite direction as the hole
910 
911  if ( ( ( v0 ^ v1 ) *
912  constraints_[i].a_) > 0.0L ) continue;
913  if ( ( ( v1 ^ v2 ) *
914  constraints_[i].a_) > 0.0L ) continue;
915  if ( ( ( v2 ^ v0 ) *
916  constraints_[i].a_) > 0.0L ) continue;
917  test = true;
918  break;
919  }
920  }
921  return test;
922 }
923 
925 // testEdge0: test if the edges intersect with the zERO convex.
926 // The edges are given by the vertex vectors e[0-2]
927 // All constraints are great circles, so test if their intersect
928 // with the edges is inside or outside the convex.
929 // If any edge intersection is inside the convex, return true.
930 // If all edge intersections are outside, check whether one of
931 // the corners is inside the triangle. If yes, all of them must be
932 // inside -> return true.
933 //
934 bool
935 RangeConvex::testEdge0(const SpatialVector & v0,
936  const SpatialVector & v1,
937  const SpatialVector & v2) {
938  // We have constructed the corners_ array in a certain direction.
939  // now we can run around the convex, check each side against the 3
940  // triangle edges. If any of the sides has its intersection INSIDE
941  // the side, return true. At the end test if a corner lies inside
942  // (because if we get there, none of the edges intersect, but it
943  // can be that the convex is fully inside the triangle. so to test
944  // one single edge is enough)
945 
946  struct edgeStruct {
947  SpatialVector e; // The half-sphere this edge delimits
948  float64 l; // length of edge
949  const SpatialVector *e1; // first end
950  const SpatialVector *e2; // second end
951  } edge[3];
952 
953  // fill the edge structure for each side of this triangle
954  edge[0].e = v0 ^ v1; edge[0].e1 = &v0; edge[0].e2 = &v1;
955  edge[1].e = v1 ^ v2; edge[1].e1 = &v1; edge[1].e2 = &v2;
956  edge[2].e = v2 ^ v0; edge[2].e1 = &v2; edge[2].e2 = &v0;
957  edge[0].l = acos(v0 * v1);
958  edge[1].l = acos(v1 * v2);
959  edge[2].l = acos(v2 * v0);
960 
961  for(size_t i = 0; i < corners_.size(); i++) {
962  size_t j = 0;
963  if(i < corners_.size() - 1) j = i+1;
964  SpatialVector a1;
965  float64 l1,l2; // lengths of the arcs from intersection to edge corners
966  float64 cedgelen = acos(corners_[i] * corners_[j]); // length of edge of convex
967 
968  // calculate the intersection - all 3 edges
969  for (size_t iedge = 0; iedge < 3; iedge++) {
970  a1 = ( edge[iedge].e ) ^ ( corners_[i] ^ corners_[j] );
971  a1.normalize();
972  // if the intersection a1 is inside the edge of the convex,
973  // its distance to the corners is smaller than the edgelength.
974  // this test has to be done for both the edge of the convex and
975  // the edge of the triangle.
976  for(size_t k = 0; k < 2; k++) {
977  l1 = acos(corners_[i] * a1);
978  l2 = acos(corners_[j] * a1);
979  if( l1 - cedgelen <= gEpsilon && l2 - cedgelen <= gEpsilon ) {
980  l1 = acos( *(edge[iedge].e1) * a1 );
981  l2 = acos( *(edge[iedge].e2) * a1 );
982  if( l1 - edge[iedge].l <= gEpsilon &&
983  l2 - edge[iedge].l <= gEpsilon )
984  return true;
985  }
986  a1 *= -1.0; // do the same for the other intersection
987  }
988  }
989  }
990  return testVectorInside(v0,v1,v2,corners_[0]);
991 }
992 
994 // testEdge: test if edges intersect with constraint. This problem
995 // is solved by a quadratic equation. Return true if there is
996 // an intersection.
997 //
998 bool
999 RangeConvex::testEdge(const SpatialVector & v0,
1000  const SpatialVector & v1,
1001  const SpatialVector & v2) {
1002 
1003  for(size_t i = 0; i < constraints_.size(); i++) {
1004  if ( constraints_[i].sign_ == nEG ) { // test only 'holes'
1005  if ( eSolve(v0, v1, i) ) return true;
1006  if ( eSolve(v1, v2, i) ) return true;
1007  if ( eSolve(v2, v0, i) ) return true;
1008  }
1009  }
1010  return false;
1011 }
1012 
1014 // eSolve: solve the quadratic eq. for intersection of an edge with a circle
1015 // constraint. Edge given by grand circle running through v1, v2
1016 // Constraint given by cIndex.
1017 bool
1018 RangeConvex::eSolve(const SpatialVector & v1,
1019  const SpatialVector & v2, size_t cIndex)
1020 {
1021 
1022  float64 gamma1 = v1 * constraints_[cIndex].a_ ;
1023  float64 gamma2 = v2 * constraints_[cIndex].a_ ;
1024  float64 mu = v1 * v2;
1025  float64 u2 = (1 - mu) / (1 + mu);
1026 
1027  float64 a = - u2 * (gamma1 + constraints_[cIndex].d_);
1028  float64 b = gamma1 * ( u2 - 1 ) + gamma2 * ( u2 + 1 );
1029  float64 c = gamma1 - constraints_[cIndex].d_;
1030 
1031  float64 D = b * b - 4 * a * c;
1032 
1033  if( D < 0.0L ) return false; // no intersection
1034 
1035  // calculate roots a'la Numerical Recipes
1036 
1037  float64 q = -0.5L * ( b + ( SGN(b) * sqrt(D) ) );
1038 
1039  float64 root1(0), root2(0);
1040  int i = 0;
1041 
1042  if ( a > gEpsilon || a < -gEpsilon ) { root1 = q / a; i++; }
1043  if ( q > gEpsilon || q < -gEpsilon ) { root2 = c / q; i++; }
1044 
1045  // Check whether the roots lie within [0,1]. If not, the intersection
1046  // is outside the edge.
1047 
1048  if (i == 0) return false; // no solution
1049  if ( root1 >= 0.0L && root1 <= 1.0L ) return true;
1050  if ( i == 2 && ( (root1 >= 0.0L && root1 <= 1.0L ) ||
1051  (root2 >= 0.0L && root2 <= 1.0L ) ) ) return true;
1052 
1053  return false;
1054 }
1055 
1057 // testBoundingCircle: test for boundingCircles intersecting with constraint
1058 //
1059 bool
1060 RangeConvex::testBoundingCircle(const SpatialVector & v0,
1061  const SpatialVector & v1,
1062  const SpatialVector & v2) {
1063 
1064  // Set the correct direction: The normal vector to the triangle plane
1065  SpatialVector c = ( v1 - v0 ) ^ ( v2 - v1 );
1066  c.normalize();
1067 
1068  // Set the correct opening angle: Since the plane cutting out the triangle
1069  // also correctly cuts out the bounding cap of the triangle on the sphere,
1070  // we can take any corner to calculate the opening angle
1071  float64 d = acos (c * v0);
1072 
1073  // for zero convexes, we have calculated a bounding circle for the convex.
1074  // only test with this single bounding circle.
1075 
1076  if(sign_ == zERO) {
1077  float64 tst;
1078  if ( ( (tst = c * boundingCircle_.a_) < -1.0L + gEpsilon ? gPi :
1079  acos(tst) ) >
1080  ( d + boundingCircle_.s_) ) return false;
1081  return true;
1082  }
1083 
1084  // for all other convexes, test every constraint. If the bounding
1085  // circle lies completely outside of one of the constraints, reject.
1086  // else, accept.
1087 
1088  size_t i;
1089  for(i = 0; i < constraints_.size(); i++) {
1090  if ( ( (c * constraints_[i].a_) < -1.0L + gEpsilon ? gPi :
1091  acos(c * constraints_[i].a_) ) >
1092  ( d + constraints_[i].s_) ) return false;
1093  }
1094  return true;
1095 }
1096 
1098 // testEdgeConstraint: test if edges intersect with a given constraint.
1099 //
1100 bool
1101 RangeConvex::testEdgeConstraint(const SpatialVector & v0,
1102  const SpatialVector & v1,
1103  const SpatialVector & v2,
1104  size_t cIndex) {
1105  if ( eSolve(v0, v1, cIndex) ) return true;
1106  if ( eSolve(v1, v2, cIndex) ) return true;
1107  if ( eSolve(v2, v0, cIndex) ) return true;
1108  return false;
1109 }
1110 
1112 // testOtherPosNone: test for other positive constraints that do
1113 // not intersect with an edge. Return its index
1114 //
1115 size_t
1116 RangeConvex::testOtherPosNone(const SpatialVector & v0,
1117  const SpatialVector & v1,
1118  const SpatialVector & v2) {
1119  size_t i = 1;
1120  while ( i < constraints_.size() && constraints_[i].sign_ == pOS ) {
1121  if ( !testEdgeConstraint ( v0,v1,v2, i ) ) return i;
1122  i++;
1123  }
1124  return 0;
1125 }
1126 
1128 // testConstraintInside: look if a constraint is inside the triangle
1129 //
1130 bool
1131 RangeConvex::testConstraintInside(const SpatialVector & v0,
1132  const SpatialVector & v1,
1133  const SpatialVector & v2,
1134  size_t i) {
1135  return testVectorInside(v0,v1,v2, constraints_[i].a_);
1136 }
1137 
1139 // testVectorInside: look if a vector is inside the triangle
1140 //
1141 bool
1142 RangeConvex::testVectorInside(const SpatialVector & v0,
1143  const SpatialVector & v1,
1144  const SpatialVector & v2,
1145  SpatialVector & v) {
1146 
1147  // If (a ^ b * c) < 0, vectors abc point clockwise.
1148  // -> center c not inside triangle, since vertices are ordered
1149  // counter-clockwise.
1150 
1151  if( ( (( v0 ^ v1 ) * v) < 0 ) ||
1152  ( (( v1 ^ v2 ) * v) < 0 ) ||
1153  ( (( v2 ^ v0 ) * v) < 0 ) )
1154  return false;
1155  return true;
1156 }
1157 
zERO
All constraints negative or zero.
Definition: SpatialSign.h:10
RangeConvex::olevel
int olevel
Definition: RangeConvex.h:88
SGN
#define SGN(x)
Definition: RangeConvex.cpp:18
SpatialIndex
The Spatial Index is a quad tree of spherical triangles.
Definition: SpatialIndex.h:59
RangeConvex::index_
const SpatialIndex * index_
Definition: RangeConvex.h:196
SpatialMarkup
SpatialMarkup
Enumerator.
Definition: RangeConvex.h:35
RangeConvex::testConstraints
int testConstraints(size_t i, size_t j)
Definition: RangeConvex.cpp:488
RangeConvex.h
RangeConvex::testNode
SpatialMarkup testNode(uint64 id)
Definition: RangeConvex.cpp:713
RangeConvex::intersect
void intersect(const SpatialIndex *index, HtmRange *hr)
Intersect with index.
Definition: RangeConvex.cpp:513
RangeConvex::boundingCircle_
SpatialConstraint boundingCircle_
Definition: RangeConvex.h:198
pARTIAL
Triangle partially intersected.
Definition: RangeConvex.h:39
RangeConvex::add
void add(SpatialConstraint &)
Add a constraint.
Definition: RangeConvex.cpp:115
RangeConvex::RangeConvex
RangeConvex()
Default Constructor.
Definition: RangeConvex.cpp:26
rEJECT
Triangle is outside the queried area.
Definition: RangeConvex.h:43
RangeConvex::eSolve
bool eSolve(const SpatialVector &v1, const SpatialVector &v2, size_t cIndex)
Definition: RangeConvex.cpp:1018
RangeConvex::testVectorInside
bool testVectorInside(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2, SpatialVector &v)
Definition: RangeConvex.cpp:1142
RangeConvex::testBoundingCircle
bool testBoundingCircle(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2)
Definition: RangeConvex.cpp:1060
SpatialConstraint
The Constraint is really a cone on the sky-sphere.
Definition: SpatialConstraint.h:76
gEpsilon
const float64 gEpsilon
Definition: SpatialGeneral.h:88
RangeConvex::addlevel_
size_t addlevel_
Definition: RangeConvex.h:199
RangeConvex::testEdge0
bool testEdge0(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2)
Definition: RangeConvex.cpp:935
F
#define F
Definition: satellite.cpp:58
RangeConvex::corners_
std::vector< SpatialVector > corners_
Definition: RangeConvex.h:197
N
#define N(n)
Definition: RangeConvex.cpp:13
RangeConvex::testEdgeConstraint
bool testEdgeConstraint(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2, size_t cIndex)
Definition: RangeConvex.cpp:1101
NV
#define NV(m)
Definition: RangeConvex.cpp:15
RangeConvex::testOtherPosNone
size_t testOtherPosNone(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2)
Definition: RangeConvex.cpp:1116
SpatialVector
The SpatialVector is a 3D vector usually living on the surface of the sphere.
Definition: SpatialVector.h:32
V
#define V(m)
Definition: RangeConvex.cpp:16
IDHIGHBIT2
#define IDHIGHBIT2
Definition: SpatialGeneral.h:127
RangeConvex::testHole
bool testHole(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2)
Definition: RangeConvex.cpp:897
HtmRange
Definition: HtmRange.h:14
HtmRange::mergeRange
void mergeRange(const Key lo, const Key hi)
Definition: HtmRange.cpp:45
nEG
Definition: SpatialSign.h:9
RangeConvex::testEdge
bool testEdge(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2)
Definition: RangeConvex.cpp:999
RangeConvex::testPartial
void testPartial(size_t level, uint64 id, const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2, int previousPartials)
Definition: RangeConvex.cpp:656
NaN::d
const double d
Definition: nan.h:35
fULL
All of the triangle is inside queried area.
Definition: RangeConvex.h:41
pOS
All constraints zero.
Definition: SpatialSign.h:11
RangeConvex::simplify0
void simplify0()
Definition: RangeConvex.cpp:181
RangeConvex::constraints_
std::vector< SpatialConstraint > constraints_
Definition: RangeConvex.h:195
RangeConvex::hr
HtmRange * hr
Definition: RangeConvex.h:84
mIXED
All constraints positive or zero.
Definition: SpatialSign.h:12
RangeConvex::testTrixel
SpatialMarkup testTrixel(uint64 nodeIndex)
Definition: RangeConvex.cpp:571
gPi
const float64 gPi
Definition: SpatialGeneral.h:86
RangeConvex::saveTrixel
void saveTrixel(uint64 htmid)
Definition: RangeConvex.cpp:531
uint64
unsigned long long uint64
Definition: SpatialGeneral.h:69
RangeConvex::simplify
void simplify()
Simplify the convex, remove redundancies.
Definition: RangeConvex.cpp:384
IDHIGHBIT
#define IDHIGHBIT
Definition: SpatialGeneral.h:126
RangeConvex::testConstraintInside
bool testConstraintInside(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2, size_t cIndex)
Definition: RangeConvex.cpp:1131
IDSIZE
#define IDSIZE
Definition: SpatialGeneral.h:77
SpatialGeneral.h
dONTKNOW
Uncertain.
Definition: RangeConvex.h:37
float64
double float64
Definition: SpatialGeneral.h:58
RangeConvex::sign_
Sign sign_
Definition: RangeConvex.h:89
RangeConvex::testTriangle
SpatialMarkup testTriangle(const SpatialVector &v0, const SpatialVector &v1, const SpatialVector &v2, int vsum)
Definition: RangeConvex.cpp:767
uint32
unsigned int uint32
Definition: SpatialGeneral.h:56
RangeConvex::testVertex
int testVertex(const SpatialVector &v)
Definition: RangeConvex.cpp:873
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:20 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