All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QuadNodePolarEuclid.h
Go to the documentation of this file.
1 /*
2  * QuadNodePolarEuclid.h
3  *
4  * Created on: 21.05.2014
5  * Author: Moritz v. Looz (moritz.looz-corswarem@kit.edu)
6  *
7  * Note: This is similar enough to QuadNode.h that one could merge these two classes.
8  */
9 
10 #ifndef QUADNODEPOLAREUCLID_H_
11 #define QUADNODEPOLAREUCLID_H_
12 
13 #include <vector>
14 #include <algorithm>
15 #include <functional>
16 #include <assert.h>
17 #include "../../auxiliary/Log.h"
18 #include "../../geometric/HyperbolicSpace.h"
19 
20 using std::vector;
21 using std::min;
22 using std::max;
23 using std::cos;
24 
25 namespace NetworKit {
26 
27 template <class T>
29  friend class QuadTreeGTest;
30 private:
31  double leftAngle;
32  double minR;
33  double rightAngle;
34  double maxR;
35  Point2D<double> a,b,c,d;
36  unsigned capacity;
37  static const unsigned coarsenLimit = 4;
38  count subTreeSize;
39  std::vector<T> content;
40  std::vector<Point2D<double> > positions;
41  std::vector<double> angles;
42  std::vector<double> radii;
43  bool isLeaf;
44  bool splitTheoretical;
45  double balance;
46  index ID;
47  double lowerBoundR;
48 
49 public:
50  std::vector<QuadNodePolarEuclid> children;
51 
53  //This should never be called.
54  leftAngle = 0;
55  rightAngle = 0;
56  minR = 0;
57  maxR = 0;
58  capacity = 20;
59  isLeaf = true;
60  subTreeSize = 0;
61  balance = 0.5;
62  splitTheoretical = false;
63  lowerBoundR = maxR;
64  ID = 0;
65  }
66 
82  QuadNodePolarEuclid(double leftAngle, double minR, double rightAngle, double maxR, unsigned capacity = 1000, bool splitTheoretical = false, double balance = 0.5) {
83  if (balance <= 0 || balance >= 1) throw std::runtime_error("Quadtree balance parameter must be between 0 and 1.");
84  this->leftAngle = leftAngle;
85  this->minR = minR;
86  this->maxR = maxR;
87  this->rightAngle = rightAngle;
88  this->a = HyperbolicSpace::polarToCartesian(leftAngle, minR);
89  this->b = HyperbolicSpace::polarToCartesian(rightAngle, minR);
90  this->c = HyperbolicSpace::polarToCartesian(rightAngle, maxR);
91  this->d = HyperbolicSpace::polarToCartesian(leftAngle, maxR);
92  this->capacity = capacity;
93  this->splitTheoretical = splitTheoretical;
94  this->balance = balance;
95  this->lowerBoundR = maxR;
96  this->ID = 0;
97  isLeaf = true;
98  subTreeSize = 0;
99  }
100 
101  void split() {
102  assert(isLeaf);
103  //heavy lifting: split up!
104  double middleAngle, middleR;
105  if (splitTheoretical) {
106  //Euclidean space is distributed equally
107  middleAngle = (rightAngle - leftAngle) / 2 + leftAngle;
108  middleR = pow(maxR*maxR*(1-balance)+minR*minR*balance, 0.5);
109  } else {
110  //median of points
111  vector<double> sortedAngles = angles;
112  std::sort(sortedAngles.begin(), sortedAngles.end());
113  middleAngle = sortedAngles[sortedAngles.size()/2];
114  vector<double> sortedRadii = radii;
115  std::sort(sortedRadii.begin(), sortedRadii.end());
116  middleR = sortedRadii[sortedRadii.size()/2];
117  }
118  assert(middleR < maxR);
119  assert(middleR > minR);
120 
121  QuadNodePolarEuclid southwest(leftAngle, minR, middleAngle, middleR, capacity, splitTheoretical, balance);
122  QuadNodePolarEuclid southeast(middleAngle, minR, rightAngle, middleR, capacity, splitTheoretical, balance);
123  QuadNodePolarEuclid northwest(leftAngle, middleR, middleAngle, maxR, capacity, splitTheoretical, balance);
124  QuadNodePolarEuclid northeast(middleAngle, middleR, rightAngle, maxR, capacity, splitTheoretical, balance);
125  children = {southwest, southeast, northwest, northeast};
126  isLeaf = false;
127  }
128 
136  void addContent(T input, double angle, double R) {
137  assert(this->responsible(angle, R));
138  if (lowerBoundR > R) lowerBoundR = R;
139  if (isLeaf) {
140  if (content.size() + 1 < capacity) {
141  content.push_back(input);
142  angles.push_back(angle);
143  radii.push_back(R);
145  positions.push_back(pos);
146  } else {
147 
148  split();
149 
150  for (index i = 0; i < content.size(); i++) {
151  this->addContent(content[i], angles[i], radii[i]);
152  }
153  assert(subTreeSize == content.size());//we have added everything twice
154  subTreeSize = content.size();
155  content.clear();
156  angles.clear();
157  radii.clear();
158  positions.clear();
159  this->addContent(input, angle, R);
160  }
161  }
162  else {
163  assert(children.size() > 0);
164  for (index i = 0; i < children.size(); i++) {
165  if (children[i].responsible(angle, R)) {
166  children[i].addContent(input, angle, R);
167  break;
168  }
169  }
170  subTreeSize++;
171  }
172  }
173 
183  bool removeContent(T input, double angle, double R) {
184  if (!responsible(angle, R)) return false;
185  if (isLeaf) {
186  index i = 0;
187  for (; i < content.size(); i++) {
188  if (content[i] == input) break;
189  }
190  if (i < content.size()) {
191  assert(angles[i] == angle);
192  assert(radii[i] == R);
193  //remove element
194  content.erase(content.begin()+i);
195  positions.erase(positions.begin()+i);
196  angles.erase(angles.begin()+i);
197  radii.erase(radii.begin()+i);
198  return true;
199  } else {
200  return false;
201  }
202  }
203  else {
204  bool removed = false;
205  bool allLeaves = true;
206  assert(children.size() > 0);
207  for (index i = 0; i < children.size(); i++) {
208  if (!children[i].isLeaf) allLeaves = false;
209  if (children[i].removeContent(input, angle, R)) {
210  assert(!removed);
211  removed = true;
212  }
213  }
214  if (removed) subTreeSize--;
215  //coarsen?
216  if (removed && allLeaves && size() < coarsenLimit) {
217  //coarsen!!
218  //why not assert empty containers and then insert directly?
219  vector<T> allContent;
220  vector<Point2D<double> > allPositions;
221  vector<double> allAngles;
222  vector<double> allRadii;
223  for (index i = 0; i < children.size(); i++) {
224  allContent.insert(allContent.end(), children[i].content.begin(), children[i].content.end());
225  allPositions.insert(allPositions.end(), children[i].positions.begin(), children[i].positions.end());
226  allAngles.insert(allAngles.end(), children[i].angles.begin(), children[i].angles.end());
227  allRadii.insert(allRadii.end(), children[i].radii.begin(), children[i].radii.end());
228  }
229  assert(subTreeSize == allContent.size());
230  assert(subTreeSize == allPositions.size());
231  assert(subTreeSize == allAngles.size());
232  assert(subTreeSize == allRadii.size());
233  children.clear();
234  content.swap(allContent);
235  positions.swap(allPositions);
236  angles.swap(allAngles);
237  radii.swap(allRadii);
238  isLeaf = true;
239  }
240 
241  return removed;
242  }
243  }
244 
245 
254  bool outOfReach(Point2D<double> query, double radius) const {
255  double phi, r;
256  HyperbolicSpace::cartesianToPolar(query, phi, r);
257  if (responsible(phi, r)) return false;
258 
259  //get four edge points
260  double topDistance, bottomDistance, leftDistance, rightDistance;
261 
262  if (phi < leftAngle || phi > rightAngle) {
263  topDistance = min(c.distance(query), d.distance(query));
264  } else {
265  topDistance = abs(r - maxR);
266  }
267  if (topDistance <= radius) return false;
268  if (phi < leftAngle || phi > rightAngle) {
269  bottomDistance = min(a.distance(query), b.distance(query));
270  } else {
271  bottomDistance = abs(r - minR);
272  }
273  if (bottomDistance <= radius) return false;
274 
275  double minDistanceR = r*cos(abs(phi-leftAngle));
276  if (minDistanceR > minR && minDistanceR < maxR) {
277  leftDistance = query.distance(HyperbolicSpace::polarToCartesian(phi, minDistanceR));
278  } else {
279  leftDistance = min(a.distance(query), d.distance(query));
280  }
281  if (leftDistance <= radius) return false;
282 
283  minDistanceR = r*cos(abs(phi-rightAngle));
284  if (minDistanceR > minR && minDistanceR < maxR) {
285  rightDistance = query.distance(HyperbolicSpace::polarToCartesian(phi, minDistanceR));
286  } else {
287  rightDistance = min(b.distance(query), c.distance(query));
288  }
289  if (rightDistance <= radius) return false;
290  return true;
291  }
292 
303  bool outOfReach(double angle_c, double r_c, double radius) const {
304  if (responsible(angle_c, r_c)) return false;
306  return outOfReach(query, radius);
307  }
308 
313  std::pair<double, double> EuclideanDistances(double phi, double r) const {
318  double maxDistance = 0;
319  double minDistance = std::numeric_limits<double>::max();
320 
321  if (responsible(phi, r)) minDistance = 0;
322 
323  auto euclidDistancePolar = [](double phi_a, double r_a, double phi_b, double r_b){
324  return pow(r_a*r_a+r_b*r_b-2*r_a*r_b*cos(phi_a-phi_b), 0.5);
325  };
326 
327  auto updateMinMax = [&minDistance, &maxDistance, phi, r, euclidDistancePolar](double phi_b, double r_b){
328  double extremalValue = euclidDistancePolar(phi, r, phi_b, r_b);
329  //assert(extremalValue <= r + r_b);
330  maxDistance = std::max(extremalValue, maxDistance);
331  minDistance = std::min(minDistance, extremalValue);
332  };
333 
337  //left
338  double extremum = r*cos(this->leftAngle - phi);
339  if (extremum < maxR && extremum > minR) {
340  updateMinMax(this->leftAngle, extremum);
341  }
342 
343  //right
344  extremum = r*cos(this->rightAngle - phi);
345  if (extremum < maxR && extremum > minR) {
346  updateMinMax(this->leftAngle, extremum);
347  }
348 
349 
353  if (phi > leftAngle && phi < rightAngle) {
354  updateMinMax(phi, maxR);
355  updateMinMax(phi, minR);
356  }
357  if (phi + M_PI > leftAngle && phi + M_PI < rightAngle) {
358  updateMinMax(phi + M_PI, maxR);
359  updateMinMax(phi + M_PI, minR);
360  }
361  if (phi - M_PI > leftAngle && phi -M_PI < rightAngle) {
362  updateMinMax(phi - M_PI, maxR);
363  updateMinMax(phi - M_PI, minR);
364  }
365 
369  updateMinMax(leftAngle, maxR);
370  updateMinMax(rightAngle, maxR);
371  updateMinMax(leftAngle, minR);
372  updateMinMax(rightAngle, minR);
373 
374  //double shortCutGainMax = maxR + r - maxDistance;
375  //assert(minDistance <= minR + r);
376  //assert(maxDistance <= maxR + r);
377  assert(minDistance < maxDistance);
378  return std::pair<double, double>(minDistance, maxDistance);
379  }
380 
381 
390  bool responsible(double angle, double r) const {
391  return (angle >= leftAngle && angle < rightAngle && r >= minR && r < maxR);
392  }
393 
399  std::vector<T> getElements() const {
400  if (isLeaf) {
401  return content;
402  } else {
403  assert(content.size() == 0);
404  assert(angles.size() == 0);
405  assert(radii.size() == 0);
406  vector<T> result;
407  for (index i = 0; i < children.size(); i++) {
408  std::vector<T> subresult = children[i].getElements();
409  result.insert(result.end(), subresult.begin(), subresult.end());
410  }
411  return result;
412  }
413  }
414 
415  void getCoordinates(vector<double> &anglesContainer, vector<double> &radiiContainer) const {
416  assert(angles.size() == radii.size());
417  if (isLeaf) {
418  anglesContainer.insert(anglesContainer.end(), angles.begin(), angles.end());
419  radiiContainer.insert(radiiContainer.end(), radii.begin(), radii.end());
420  }
421  else {
422  assert(content.size() == 0);
423  assert(angles.size() == 0);
424  assert(radii.size() == 0);
425  for (index i = 0; i < children.size(); i++) {
426  children[i].getCoordinates(anglesContainer, radiiContainer);
427  }
428  }
429  }
430 
447  void getElementsInEuclideanCircle(Point2D<double> center, double radius, vector<T> &result, double minAngle=0, double maxAngle=2*M_PI, double lowR=0, double highR = 1) const {
448  if (minAngle >= rightAngle || maxAngle <= leftAngle || lowR >= maxR || highR < lowerBoundR) return;
449  if (outOfReach(center, radius)) {
450  return;
451  }
452 
453  if (isLeaf) {
454  const double rsq = radius*radius;
455  const double queryX = center[0];
456  const double queryY = center[1];
457  const count cSize = content.size();
458 
459  for (int i=0; i < cSize; i++) {
460  const double deltaX = positions[i].getX() - queryX;
461  const double deltaY = positions[i].getY() - queryY;
462  if (deltaX*deltaX + deltaY*deltaY < rsq) {
463  result.push_back(content[i]);
464  }
465  }
466  } else {
467  for (index i = 0; i < children.size(); i++) {
468  children[i].getElementsInEuclideanCircle(center, radius, result, minAngle, maxAngle, lowR, highR);
469  }
470  }
471  }
472 
473  count getElementsProbabilistically(Point2D<double> euQuery, std::function<double(double)> prob, bool suppressLeft, vector<T> &result) const {
474  double phi_q, r_q;
475  HyperbolicSpace::cartesianToPolar(euQuery, phi_q, r_q);
476  if (suppressLeft && phi_q > rightAngle) return 0;
477  TRACE("Getting Euclidean distances");
478  auto distancePair = EuclideanDistances(phi_q, r_q);
479  double probUB = prob(distancePair.first);
480  double probLB = prob(distancePair.second);
481  assert(probLB <= probUB);
482  if (probUB > 0.5) probUB = 1;//if we are going to take every second element anyway, no use in calculating expensive jumps
483  if (probUB == 0) return 0;
484  //TODO: return whole if probLB == 1
485  double probdenom = std::log(1-probUB);
486  if (probdenom == 0) {
487  DEBUG(probUB, " not zero, but too small too process. Ignoring.");
488  return 0;
489  }
490  TRACE("probUB: ", probUB, ", probdenom: ", probdenom);
491 
492  count expectedNeighbours = probUB*size();
493  count candidatesTested = 0;
494 
495  if (isLeaf) {
496  const count lsize = content.size();
497  TRACE("Leaf of size ", lsize);
498  for (index i = 0; i < lsize; i++) {
499  //jump!
500  if (probUB < 1) {
501  double random = Aux::Random::real();
502  double delta = std::log(random) / probdenom;
503  assert(delta == delta);
504  assert(delta >= 0);
505  i += delta;
506  if (i >= lsize) break;
507  TRACE("Jumped with delta ", delta, " arrived at ", i);
508  }
509  assert(i >= 0);
510 
511  //see where we've arrived
512  candidatesTested++;
513  double distance = positions[i].distance(euQuery);
514  double q = prob(distance);
515  q = q / probUB; //since the candidate was selected by the jumping process, we have to adjust the probabilities
516  assert(q <= 1);
517  assert(q >= 0);
518 
519  //accept?
520  double acc = Aux::Random::real();
521  if (acc < q) {
522  TRACE("Accepted node ", i, " with probability ", q, ".");
523  result.push_back(content[i]);
524  }
525  }
526  } else {
527  if (expectedNeighbours < 4 || probUB < 1/1000) {//select candidates directly instead of calling recursively
528  TRACE("probUB = ", probUB, ", switching to direct candidate selection.");
529  assert(probUB < 1);
530  const count stsize = size();
531  for (index i = 0; i < stsize; i++) {
532  double delta = std::log(Aux::Random::real()) / probdenom;
533  assert(delta >= 0);
534  i += delta;
535  TRACE("Jumped with delta ", delta, " arrived at ", i, ". Calling maybeGetKthElement.");
536  if (i < size()) maybeGetKthElement(probUB, euQuery, prob, i, result);//this could be optimized. As of now, the offset is subtracted separately for each point
537  else break;
538  candidatesTested++;
539  }
540  } else {//carry on as normal
541  for (index i = 0; i < children.size(); i++) {
542  TRACE("Recursively calling child ", i);
543  candidatesTested += children[i].getElementsProbabilistically(euQuery, prob, suppressLeft, result);
544  }
545  }
546  }
547  //DEBUG("Expected at most ", expectedNeighbours, " neighbours, got ", result.size() - offset);
548  return candidatesTested;
549  }
550 
551 
552  void maybeGetKthElement(double upperBound, Point2D<double> euQuery, std::function<double(double)> prob, index k, vector<T> &circleDenizens) const {
553  TRACE("Maybe get element ", k, " with upper Bound ", upperBound);
554  assert(k < size());
555  if (isLeaf) {
556  double acceptance = prob(euQuery.distance(positions[k]))/upperBound;
557  TRACE("Is leaf, accept with ", acceptance);
558  if (Aux::Random::real() < acceptance) circleDenizens.push_back(content[k]);
559  } else {
560  TRACE("Call recursively.");
561  index offset = 0;
562  for (index i = 0; i < children.size(); i++) {
563  count childsize = children[i].size();
564  if (k - offset < childsize) {
565  children[i].maybeGetKthElement(upperBound, euQuery, prob, k - offset, circleDenizens);
566  break;
567  }
568  offset += childsize;
569  }
570  }
571  }
572 
577  void trim() {
578  content.shrink_to_fit();
579  positions.shrink_to_fit();
580  angles.shrink_to_fit();
581  radii.shrink_to_fit();
582  if (!isLeaf) {
583  for (index i = 0; i < children.size(); i++) {
584  children[i].trim();
585  }
586  }
587  }
588 
592  count size() const {
593  return isLeaf ? content.size() : subTreeSize;
594  }
595 
596  void recount() {
597  subTreeSize = 0;
598  for (index i = 0; i < children.size(); i++) {
599  children[i].recount();
600  subTreeSize += children[i].size();
601  }
602  }
603 
607  count height() const {
608  count result = 1;//if leaf node, the children loop will not execute
609  for (auto child : children) result = std::max(result, child.height()+1);
610  return result;
611  }
612 
616  count countLeaves() const {
617  if (isLeaf) return 1;
618  count result = 0;
619  for (index i = 0; i < children.size(); i++) {
620  result += children[i].countLeaves();
621  }
622  return result;
623  }
624 
625  double getLeftAngle() const {
626  return leftAngle;
627  }
628 
629  double getRightAngle() const {
630  return rightAngle;
631  }
632 
633  double getMinR() const {
634  return minR;
635  }
636 
637  double getMaxR() const {
638  return maxR;
639  }
640 
641  index getID() const {
642  return ID;
643  }
644 
646  index result = nextID;
647  assert(children.size() == 4 || children.size() == 0);
648  for (int i = 0; i < children.size(); i++) {
649  result = children[i].indexSubtree(result);
650  }
651  this->ID = result;
652  return result+1;
653  }
654 
655  index getCellID(double phi, double r) const {
656  if (!responsible(phi, r)) return NetworKit::none;
657  if (isLeaf) return getID();
658  else {
659  for (int i = 0; i < children.size(); i++) {
660  index childresult = children[i].getCellID(phi, r);
661  if (childresult != NetworKit::none) return childresult;
662  }
663  throw std::runtime_error("No responsible child node found even though this node is responsible.");
664  }
665  }
666 
668  if (isLeaf) return getID();
669  else {
670  index result = -1;
671  for (int i = 0; i < 4; i++) {
672  result = std::max(children[i].getMaxIDInSubtree(), result);
673  }
674  return std::max(result, getID());
675  }
676  }
677 
678  count reindex(count offset) {
679  if (isLeaf)
680  {
681  #pragma omp task
682  {
683  index p = offset;
684  std::generate(content.begin(), content.end(), [&p](){return p++;});
685  }
686  offset += size();
687  } else {
688  for (int i = 0; i < 4; i++) {
689  offset = children[i].reindex(offset);
690  }
691  }
692  return offset;
693  }
694 };
695 }
696 
697 #endif /* QUADNODE_H_ */
double getRightAngle() const
Definition: QuadNodePolarEuclid.h:629
std::pair< double, double > EuclideanDistances(double phi, double r) const
Definition: QuadNodePolarEuclid.h:313
void trim()
Shrink all vectors in this subtree to fit the content.
Definition: QuadNodePolarEuclid.h:577
double real()
Definition: Random.cpp:77
bool responsible(double angle, double r) const
Does the point at (angle, r) fall inside the region managed by this QuadNode?
Definition: QuadNodePolarEuclid.h:390
void maybeGetKthElement(double upperBound, Point2D< double > euQuery, std::function< double(double)> prob, index k, vector< T > &circleDenizens) const
Definition: QuadNodePolarEuclid.h:552
index getID() const
Definition: QuadNodePolarEuclid.h:641
void getCoordinates(vector< double > &anglesContainer, vector< double > &radiiContainer) const
Definition: QuadNodePolarEuclid.h:415
bool removeContent(T input, double angle, double R)
Remove content at polar coordinates (angle, R).
Definition: QuadNodePolarEuclid.h:183
std::vector< T > getElements() const
Get all Elements in this QuadNode or a descendant of it.
Definition: QuadNodePolarEuclid.h:399
count height() const
Height of subtree hanging from this QuadNode.
Definition: QuadNodePolarEuclid.h:607
void log(const Location &loc, LogLevel p, const std::string msg)
Definition: Log.cpp:202
count countLeaves() const
Leaf cells in the subtree hanging from this QuadNode.
Definition: QuadNodePolarEuclid.h:616
uint64_t index
Typedefs.
Definition: Globals.h:20
double getMaxR() const
Definition: QuadNodePolarEuclid.h:637
#define DEBUG(...)
Definition: Log.h:82
T distance(const Point2D< T > &p) const
Definition: Point2D.h:96
friend class QuadTreeGTest
Definition: QuadNodePolarEuclid.h:29
bool outOfReach(Point2D< double > query, double radius) const
Check whether the region managed by this node lies outside of an Euclidean circle.
Definition: QuadNodePolarEuclid.h:254
double getMinR() const
Definition: QuadNodePolarEuclid.h:633
static Point2D< double > polarToCartesian(double phi, double r)
Definition: HyperbolicSpace.cpp:98
bool outOfReach(double angle_c, double r_c, double radius) const
Check whether the region managed by this node lies outside of an Euclidean circle.
Definition: QuadNodePolarEuclid.h:303
index getMaxIDInSubtree() const
Definition: QuadNodePolarEuclid.h:667
std::vector< QuadNodePolarEuclid > children
Definition: QuadNodePolarEuclid.h:50
index getCellID(double phi, double r) const
Definition: QuadNodePolarEuclid.h:655
void split()
Definition: QuadNodePolarEuclid.h:101
QuadNodePolarEuclid()
Definition: QuadNodePolarEuclid.h:52
void recount()
Definition: QuadNodePolarEuclid.h:596
count getElementsProbabilistically(Point2D< double > euQuery, std::function< double(double)> prob, bool suppressLeft, vector< T > &result) const
Definition: QuadNodePolarEuclid.h:473
QuadNodePolarEuclid(double leftAngle, double minR, double rightAngle, double maxR, unsigned capacity=1000, bool splitTheoretical=false, double balance=0.5)
Construct a QuadNode for polar coordinates.
Definition: QuadNodePolarEuclid.h:82
uint64_t count
Definition: Globals.h:21
constexpr index none
Constants.
Definition: Globals.h:28
index indexSubtree(index nextID)
Definition: QuadNodePolarEuclid.h:645
count size() const
Number of points lying in the region managed by this QuadNode.
Definition: QuadNodePolarEuclid.h:592
void addContent(T input, double angle, double R)
Add a point at polar coordinates (angle, R) with content input.
Definition: QuadNodePolarEuclid.h:136
float distance
Definition: PubWebGenerator.h:25
double getLeftAngle() const
Definition: QuadNodePolarEuclid.h:625
Definition: QuadNodePolarEuclid.h:28
static void cartesianToPolar(Point2D< double > a, double &phi, double &r)
Definition: HyperbolicSpace.cpp:113
#define TRACE(...)
Definition: Log.h:92
void getElementsInEuclideanCircle(Point2D< double > center, double radius, vector< T > &result, double minAngle=0, double maxAngle=2 *M_PI, double lowR=0, double highR=1) const
Main query method, get points lying in a Euclidean circle around the center point.
Definition: QuadNodePolarEuclid.h:447
count reindex(count offset)
Definition: QuadNodePolarEuclid.h:678