Memosa-FVM  0.2
Octree.cpp
Go to the documentation of this file.
1 // This file os part of FVM
2 // Copyright (c) 2012 FVM Authors
3 // See LICENSE file for terms.
4 
5 #include "Octree.h"
6 #include "NumType.h"
7 
8 //#include <cstdio>
9 //#include <stdlib.h>
10 //#include <string.h>
11 
16 using namespace std;
17 
18 inline double max ( double x, double y)
19 {
20  return (x>y ? x:y);
21 }
22 
23 inline double min ( double x, double y)
24 {
25  return (x>y ? y:x);
26 }
27 // -----------------------------------------------------------------------------
28 // Construction -- "nullify" the class
29 // -----------------------------------------------------------------------------
30 
32  {
33  memset(_child, 0, sizeof(_child));
34  _pointCount=0;
35  _points=NULL;
36  _center=0.0;
37  _radius=0.0;
38  _nodeType=0;
39 }
40 
41 // -----------------------------------------------------------------------------
42 // Destruction -- free up memory
43 // -----------------------------------------------------------------------------
44 //???how to delete the entire octree//
46 {
47  // delete[] _data;
48 }
49 
50 // -----------------------------------------------------------------------------
51 // Build the octree
52 // -----------------------------------------------------------------------------
53  // count: number of points
54  // threshold:maximum number of points each node contains
55  // maximumDepth:
56 bool Octree::build(Point *points,
57  const unsigned int count,
58  const unsigned int threshold,
59  const unsigned int maximumDepth,
60  const Bounds &bounds,
61  const unsigned int currentDepth
62  )
63 
64 {
65  //store the information for current node
66  _pointCount=count;
67  _center=bounds.center;
68  _radius=bounds.radius;
69  _currentDepth=currentDepth;
70 
71  // The node is a leaf when...
72  // 1. The number of points <= the threshold
73  // 2. We've recursed too deep into the tree
74  // (currentDepth >= maximumDepth)
75  //
76  // NOTE: We specifically use ">=" for the depth comparison so that we
77  // can set the maximumDepth depth to 0 if we want a tree with
78  // no depth.
79 
80  if (count <= threshold || currentDepth >= maximumDepth)
81  {
82  // Just store the points in the node, making it a leaf
83 
84  _points = new Point [count];
85  memcpy(_points, points, sizeof (Point)* count);
86 
87  _nodeType=1;
88 
89  return true;
90  }
91  // else, the current node is a intermediate node.
92 
93  //set the data and node type
94  _nodeType=0;
95  _points=NULL;
96 
97  // then creat the child nodes
98 
99 
100  unsigned int childPointCounts[8]={0};
101 
102  // Loop over all the points in current node,
103  // Classify each point to a child node
104 
105  for (unsigned int i = 0; i < count; i++)
106  {
107  // Current point
108 
109  Point &p = points[i];
110 
111  // Center of this node
112 
113  const VectorT3 &c = bounds.center;
114 
115  // Here, we need to know which child each point belongs to. To
116  // do this, we build an index into the _child[] array using the
117  // relative position of the point to the center of the current
118  // node
119 
120  p.code = 0;
121  // bitwise OR x|y each bit in x OR each bit in y
122  // bitwise OR assignment x|=y assign x|y to x
123  if (p.coordinate[0] > c[0]) p.code |= 1;
124  if (p.coordinate[1] > c[1]) p.code |= 2;
125  if (p.coordinate[2] > c[2]) p.code |= 4;
126 
127  // keep track of how many points get assigned in each child
128 
129  childPointCounts[p.code]++;
130  }
131 
132  // Recursively call build() for each of the 8 children
133 
134  for (int i = 0; i < 8; i++)
135  {
136  // Don't bother going any further if there aren't any points for
137  // this child
138 
139  if (!childPointCounts[i]) continue;
140 
141  // Allocate the child
142 
143  _child[i] = new Octree;
144 
145  // Allocate a list of points that were coded JUST for this child
146  // only
147 
148  Point *newList = new Point [childPointCounts[i]];
149 
150  // Go through the input list of points and copy over the points
151  // that were coded for this child
152 
153  Point *ptr = newList;
154 
155  for (unsigned int j = 0; j < count; j++)
156  {
157  if (points[j].code == i)
158  {
159  *ptr = points[j];
160  ptr++;
161  }
162  }
163 
164  // At this point, we have a list of points that will belong to
165  // this child node
166 
167  // assume newCount is the same as childPointCount
168  int newCount=childPointCounts[i];
169 
170  // Generate a new bounding volume //
171  // We use a table of offsets. These offsets determine where a
172  // node is, relative to it's parent. So, for example, if want to
173  // generate the bottom-left-rear (-x, -y, -z) child for a node,
174  // we use (-1, -1, -1).
175  //
176  // However, since the radius of a child is always half of its
177  // parent's, we use a table of 0.5, rather than 1.0.
178  //
179  // These values are stored the following table.
180  static VectorT3 boundsOffsetTable[8];
181 
182  boundsOffsetTable[0][0]=-0.5;
183  boundsOffsetTable[0][1]=-0.5;
184  boundsOffsetTable[0][2]=-0.5;
185 
186  boundsOffsetTable[1][0]=+0.5;
187  boundsOffsetTable[1][1]=-0.5;
188  boundsOffsetTable[1][2]=-0.5;
189 
190  boundsOffsetTable[2][0]=-0.5;
191  boundsOffsetTable[2][1]=+0.5;
192  boundsOffsetTable[2][2]=-0.5;
193 
194  boundsOffsetTable[3][0]=+0.5;
195  boundsOffsetTable[3][1]=+0.5;
196  boundsOffsetTable[3][2]=-0.5;
197 
198  boundsOffsetTable[4][0]=-0.5;
199  boundsOffsetTable[4][1]=-0.5;
200  boundsOffsetTable[4][2]=+0.5;
201 
202  boundsOffsetTable[5][0]=+0.5;
203  boundsOffsetTable[5][1]=-0.5;
204  boundsOffsetTable[5][2]=+0.5;
205 
206  boundsOffsetTable[6][0]=-0.5;
207  boundsOffsetTable[6][1]=+0.5;
208  boundsOffsetTable[6][2]=+0.5;
209 
210  boundsOffsetTable[7][0]=+0.5;
211  boundsOffsetTable[7][1]=+0.5;
212  boundsOffsetTable[7][2]=+0.5;
213 
214 
215 
216  /* { {-0.5, -0.5, -0.5},
217  {+0.5, -0.5, -0.5},
218  {-0.5, +0.5, -0.5},
219  {+0.5, +0.5, -0.5},
220  {-0.5, -0.5, +0.5},
221  {+0.5, -0.5, +0.5},
222  {-0.5, +0.5, +0.5},
223  {+0.5, +0.5, +0.5}
224  };*/
225 
226  // Calculate our offset from the center of the parent's node to
227  // the center of the child's node
228 
229  VectorT3 offset= boundsOffsetTable[i]*bounds.radius;
230 
231  // Create a new Bounds, with the center offset and half the
232  // radius
233 
234  Bounds newBounds;
235  newBounds.radius = bounds.radius * 0.5;
236  newBounds.center = bounds.center + offset;
237 
238  // Recurse
239 
240  _child[i]->build(newList, newCount, threshold, maximumDepth,
241  newBounds, currentDepth+1);
242 
243  // Clean up
244 
245  delete[] newList;
246  }
247 
248  return true;
249 }
250 
251 // -----------------------------------------------------------------------------
252 // Determine the [cubic] bounding volume for a set of points
253 // -----------------------------------------------------------------------------
254 
256  const unsigned int count)
257 {
258  // What will be returned to the caller
259 
260  Bounds b;
261 
262  // Determine min/max of the given set of points
263 
264  VectorT3 min = points[0].coordinate;
265  VectorT3 max = points[0].coordinate;
266 
267  for (unsigned int i = 0; i < count; i++)
268  {
269  const VectorT3 &p = points[i].coordinate;
270  if (p[0] < min[0]) min[0] = p[0];
271  if (p[1] < min[1]) min[1] = p[1];
272  if (p[2] < min[2]) min[2] = p[2];
273  if (p[0] > max[0]) max[0] = p[0];
274  if (p[1] > max[1]) max[1] = p[1];
275  if (p[2] > max[2]) max[2] = p[2];
276  //if (p VectorT3::< min) min=p;
277  //if (p VectorT3::> max) max=p;
278  //min=setMin(min,p);
279  //max=setMax(max,p);
280  }
281 
282  // The radius of the volume (dimensions in each direction)
283 
284  VectorT3 radius;
285  radius=(max-min)/2.;
286 
287  // Find the center of this space
288  b.center=min+radius;
289 
290 
291  // We want a CUBIC space. By this, I mean we want a bounding cube, not
292  // just a bounding box. We already have the center, we just need a
293  // radius that contains the entire volume. To do this, we find the
294  // maxumum value of the radius' X/Y/Z components and use that
295 
296  b.radius = radius[0];
297  if (b.radius < radius[1]) b.radius = radius[1];
298  if (b.radius < radius[2]) b.radius = radius[2];
299 
300  // Done
301 
302  return b;
303 }
304 
305 // -----------------------------------------------------------------------------
306 // Print out the octree leaf nodes
307 // -----------------------------------------------------------------------------
308 
309 bool Octree::report(FILE *fp)
310 {
311 
312  //if it is a leaf, then print out the data
313  if (_nodeType==1){
314  fprintf(fp,"currentDepth is %i\n", _currentDepth);
315  fprintf(fp,"node center is %f\t%f\t%f\n", _center[0],_center[1],_center[2]);
316  fprintf(fp,"node radius is %f\n", _radius);
317  fprintf(fp,"data in this node is ");
318  for(unsigned int i=0; i<_pointCount; i++){
319  fprintf(fp,"%i\t", _points[i].cellIndex);
320  }
321  fprintf(fp,"\n end of node\n");
322  }
323  //if it is a node, recursively traverse to child node
324  if(_nodeType==0){
325  for(int i=0; i<8;i++){
326  //not guarantee a node has all 8 children
327  if(!_child[i]) continue;
328  else{
329  _child[i]->report(fp);
330  }
331  }
332  }
333  return(true);
334 }
335 
336 
337 
341 
342 const double Octree::borderDistance(const VectorT3 coordinate){
343  double x=coordinate[0];
344  double y=coordinate[1];
345  double z=coordinate[2];
346  double nsdistance;
347  double ewdistance;
348  double fbdistance;
349 
350  double leftBound=_center[0]-_radius;
351  double rightBound=_center[0]+_radius;
352  double frontBound=_center[1]-_radius;
353  double backBound=_center[1]+_radius;
354  double bottomBound=_center[2]-_radius;
355  double topBound=_center[2]+_radius;
356 
357  if(leftBound <= x && x <= rightBound)
358  ewdistance = 0;
359  else
360  ewdistance = min(fabs(x-rightBound), fabs(x-leftBound));
361 
362  if(frontBound <= y && y <= backBound)
363  fbdistance = 0;
364  else
365  fbdistance = min(fabs(y-backBound), fabs(y-frontBound));
366 
367  if(bottomBound <= z && z <= topBound)
368  nsdistance = 0;
369  else
370  nsdistance = min(fabs(z-topBound), fabs(z-bottomBound));
371 
372  return (nsdistance * nsdistance +
373  ewdistance * ewdistance +
374  fbdistance * fbdistance);
375  //note: it actually return the distance square
376 }
377 
378 
386 
387 const int Octree::getNode(const VectorT3 coordinate, double& shortestDistance)
388 {
389  static int node;
390  double distance;
391  VectorT3 dR;
392 
393  //if it is a leaf, search all data in this leaf to find out the best distance
394  if (_nodeType==1){
395  for (unsigned int i=0; i<_pointCount; i++){
396  dR=_points[i].coordinate-coordinate;
397  //dR=0;
398  distance=mag2(dR);
399  if(distance < shortestDistance*shortestDistance){
400  shortestDistance=sqrt(distance);
401  node=_points[i].cellIndex;
402  }
403  }
404  return node;
405  }
406  //if it is a node, recursively traverse to child node
407  else if(_nodeType==0){
408  // Check the distance of the bounds of the branch,
409  // versus the bestDistance. If there is a boundary that
410  // is closer, then it is possible that another node has an
411  // object that is closer.
412  for (int i=0; i<8;i++){
413  //not guarantee a node has all 8 children
414  if(!_child[i]) continue;
415  else{
416  double childDistance=_child[i]->borderDistance(coordinate);
417  if (childDistance < shortestDistance*shortestDistance){
418  int test=-1;
419  test=_child[i]->getNode(coordinate, shortestDistance);
420  if(test >= 0)
421  node=test;
422  }
423  }
424  }
425  }
426 
427  return(node);
428 }
429 
430 
431 
432 
433 
434 // -----------------------------------------------------------------------------
435 // Get an node closest to a (x,y,z)
436 // <returns> the data in the node that matches the best distance,
437 // null if no node were found.
438 // for this case, the data is an integer (cellIndex)
439 // -----------------------------------------------------------------------------
440 
441 const int Octree::getNode(const double x, const double y, const double z)
442 {
443  int node;
444  VectorT3 coordinate;
445  double LargeNumber=1.0e20;
446  coordinate[0]=x;
447  coordinate[1]=y;
448  coordinate[2]=z;
449  node=Octree::getNode(coordinate, LargeNumber);
450  return(node);
451 }
452 
453 const int Octree::getNode(const VectorT3 coordinate)
454 {
455  int node;
456  double LargeNumber=1.0e20;
457  node=Octree::getNode(coordinate, LargeNumber);
458  return(node);
459 }
460 
461 /**********************************************************************/
464 /**********************************************************************/
465 
466 void Octree::getNodes(const VectorT3 coordinate, const double radius, vector<int>& cellList)
467 {
468 
469  double distance;
470  VectorT3 dR;
471 
472  //if it is a leaf, search all data in this leaf to find out the best distance
473  if (_nodeType==1){
474  for (unsigned int i=0; i<_pointCount; i++){
475  dR=_points[i].coordinate-coordinate;
476  distance=mag2(dR);
477  if(distance <= radius*radius){
478  cellList.push_back(_points[i].cellIndex);
479  }
480  }
481  }
482  //if it is a node, recursively traverse to child node
483  else if(_nodeType==0){
484  // Check the distance of the bounds of the branch,
485  // versus the bestDistance. If there is a boundary that
486  // is closer, then it is possible that another node has an
487  // object that is closer.
488  for (int i=0; i<8;i++){
489  //not guarantee a node has all 8 children
490  if(!_child[i]) continue;
491  else{
492  double childDistance=_child[i]->borderDistance(coordinate);
493  if (childDistance <= radius*radius){
494  _child[i]->getNodes(coordinate, radius, cellList);
495  }
496  }
497  }
498  }
499 }
500 
501 void Octree::getNodes(const double x, const double y, const double z,
502  const double radius, vector<int>& cellList)
503 {
504  VectorT3 coordinate;
505  coordinate[0] = x;
506  coordinate[1] = y;
507  coordinate[2] = z;
508  Octree::getNodes(coordinate, radius, cellList);
509 }
510 
511 /**********************************************************************/
514 /**********************************************************************/
515 
516 const int Octree::Naive_getNode(const VectorT3 coordinate, const int count, const Point * points)
517 {
518 
519  //naive search by looping over all points
520  double shortestDistance=100000;
521  double shortestDistanceSqr=shortestDistance*shortestDistance;
522  int cellIndex;
523  cellIndex=-1;
524 
525  for (int i=0; i<count; i++){
526  VectorT3 dR=coordinate-points[i].coordinate;
527  double distanceSqr=mag2(dR);
528  if(distanceSqr < shortestDistanceSqr){
529  shortestDistance=sqrt(distanceSqr);
530  shortestDistanceSqr=shortestDistance*shortestDistance;
531  cellIndex=points[i].cellIndex;
532  }
533  }
534  return(cellIndex);
535 }
536 
537 
538 const vector<int> Octree::Naive_getNodes(const VectorT3 coordinate, const int count, const Point * points, const double radius)
539 {
540 
541  //naive search by looping over all points
542 
543  vector<int> cellIndexList;
544 
545  double radiusSqr=radius*radius;
546  for (int i=0; i<count; i++){
547  VectorT3 dR=coordinate-points[i].coordinate;
548  double distanceSqr=mag2(dR);
549  if(distanceSqr < radiusSqr){
550  cellIndexList.push_back(points[i].cellIndex);
551  }
552  }
553  return(cellIndexList);
554 }
555 
556 
557 void Octree::Impl(const Mesh& mesh, const GeomFields& geomFields)
558 //void Octree::Impl(const int nCells, shared_ptr<VectorT3Array> cellCentroid)
559 {
560 //---build up Octree for cell centroid---//
561  const StorageSite& cells = mesh.getCells();
562  const int nCells = cells.getCount(); //need to include BC cells?
563  const VectorT3Array& cellCentroid = dynamic_cast<const VectorT3Array& > (geomFields.coordinate[cells]);
564  Point *points = new Point [nCells];
565 
566  for(int i=0; i<nCells; i++){
567  points[i].coordinate=(cellCentroid)[i];
568  points[i].cellIndex=i;
569  points[i].code=0;
570  }
571 
572  //Octree build up parameters
573 
574  const int threshold=1;
575  const int maxDepth=20;
576  const int count=nCells;
577  int currentDepth=0;
578 
579  //define a new Octree object
580 
581  // Octree O;
582 
583  //calculate entire domain bounds
584 
585  Bounds bounds=Octree::calcCubicBounds(points, count);
586 
587  //build Octree
588  Octree::build(points, count, threshold, maxDepth, bounds, currentDepth);
589 
590 }
591 
592 
593 void Octree::Create(const Mesh& mesh, const GeomFields& geomFields, const int faceGroupID)
594 
595 {
596  //---build up Octree for a specific face group---//
597 
598  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
599  {
600  const FaceGroup& fg = *fgPtr;
601  if (fg.id == faceGroupID)
602  {
603  const StorageSite& faces = fg.site;
604  const int nFaces = faces.getCount();
605  const VectorT3Array& faceCentroid = dynamic_cast<const VectorT3Array& > (geomFields.coordinate[faces]);
606 
607  Point *points = new Point [nFaces];
608 
609  for(int i=0; i<nFaces; i++){
610  points[i].coordinate=(faceCentroid)[i];
611  points[i].cellIndex=i;
612  points[i].code=0;
613  }
614 
615  //Octree build up parameters
616 
617  const int threshold=1;
618  const int maxDepth=20;
619  const int count=nFaces;
620  int currentDepth=0;
621 
622  //calculate entire domain bounds
623 
624  Bounds bounds=Octree::calcCubicBounds(points, count);
625 
626  //build Octree
627  Octree::build(points, count, threshold, maxDepth, bounds, currentDepth);
628  }
629  }
630 
631 }
void Impl(const Mesh &mesh, const GeomFields &geomFields)
Definition: Octree.cpp:557
void Create(const Mesh &mesh, const GeomFields &geomFields, const int faceGroupID)
Definition: Octree.cpp:593
const FaceGroupList & getBoundaryFaceGroups() const
Definition: Mesh.h:187
int cellIndex
Definition: Octree.h:34
shared_ptr< FaceGroup > FaceGroupPtr
Definition: Mesh.h:46
Field coordinate
Definition: GeomFields.h:19
Definition: Mesh.h:28
Octree::Bounds Bounds
Definition: Octree.cpp:13
const vector< int > Naive_getNodes(const VectorT3 coordinate, const int count, const Point *points, const double radius)
Definition: Octree.cpp:538
const double borderDistance(const VectorT3 coordinate)
A utility method to figure out the closest distance of a border to a point. If the point is inside th...
Definition: Octree.cpp:342
Definition: Mesh.h:49
int code
Definition: Octree.h:35
double max(double x, double y)
Definition: Octree.cpp:18
virtual ~Octree()
Definition: Octree.cpp:45
Tangent sqrt(const Tangent &a)
Definition: Tangent.h:317
const int id
Definition: Mesh.h:41
Definition: Octree.h:22
double radius
Definition: Octree.h:44
void getNodes(const VectorT3 coordinate, const double radius, vector< int > &cellList)
Get all objects closest to a x/y/z within a radius. search mechanism similar to getNode(coordinate) ...
Definition: Octree.cpp:466
const int Naive_getNode(const VectorT3 coordinate, const int count, const Point *points)
Get all objects closest to a x/y/z within a radius. by simply looping over all the points ...
Definition: Octree.cpp:516
const StorageSite & getCells() const
Definition: Mesh.h:109
Octree::VectorT3Array VectorT3Array
Definition: Octree.cpp:14
VectorT3 coordinate
Definition: Octree.h:33
bool report(FILE *fp)
Definition: Octree.cpp:309
Tangent fabs(const Tangent &a)
Definition: Tangent.h:312
Definition: Array.h:14
VectorT3 center
Definition: Octree.h:43
const Bounds calcCubicBounds(const Point *points, const unsigned int count)
Definition: Octree.cpp:255
const int getNode(const double x, const double y, const double z)
Definition: Octree.cpp:441
int getCount() const
Definition: StorageSite.h:39
Octree::Point Point
Definition: Octree.cpp:12
double min(double x, double y)
Definition: Octree.cpp:23
virtual bool build(Point *points, const unsigned int count, const unsigned int threshold, const unsigned int maximumDepth, const Bounds &bounds, const unsigned int currentDepth=0)
Definition: Octree.cpp:56
Octree::VectorT3 VectorT3
Definition: Octree.cpp:15
StorageSite site
Definition: Mesh.h:40
Octree()
Definition: Octree.cpp:31
T mag2(const Vector< T, 3 > &a)
Definition: Vector.h:267