AABBTree.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "AABBTree.H"
27 #include "meshTools.H"
28 #include "PackedBoolList.H"
29 //#include "OFstream.H"
30 
31 template<class Type>
32 Foam::scalar Foam::AABBTree<Type>::tolerance_ = 1e-4;
33 
34 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
35 
36 template<class Type>
38 (
39  const bool writeLinesOnly,
40  const treeBoundBox& bb,
41  label& vertI,
42  Ostream& os
43 ) const
44 {
45  const pointField pts(bb.points());
46  forAll(pts, i)
47  {
48  meshTools::writeOBJ(os, pts[i]);
49  }
50 
51  if (writeLinesOnly)
52  {
53  forAll(bb.edges, i)
54  {
55  const edge& e = bb.edges[i];
56  os << "l " << e[0] + vertI + 1 << ' ' << e[1] + vertI + 1 << nl;
57  }
58  }
59  else
60  {
61  forAll(bb.faces, i)
62  {
63  const face& f = bb.faces[i];
64 
65  os << 'f';
66  forAll(f, fp)
67  {
68  os << ' ' << f[fp] + vertI + 1;
69  }
70  os << nl;
71  }
72  }
73 
74  vertI += pts.size();
75 }
76 
77 
78 template<class Type>
80 (
81  const bool leavesOnly,
82  const bool writeLinesOnly,
83  const treeBoundBox& bb,
84  const label nodeI,
85  const List<Pair<treeBoundBox> >& bbs,
86  const List<Pair<label> >& nodes,
87  label& vertI,
88  Ostream& os
89 ) const
90 {
91  if (!leavesOnly || nodeI < 0)
92  {
93  writeOBJ(writeLinesOnly, bb, vertI, os);
94  }
95 
96  // recurse to find leaves
97  if (nodeI >= 0)
98  {
99  writeOBJ
100  (
101  leavesOnly,
102  writeLinesOnly,
103  bbs[nodeI].first(),
104  nodes[nodeI].first(),
105  bbs,
106  nodes,
107  vertI,
108  os
109  );
110  writeOBJ
111  (
112  leavesOnly,
113  writeLinesOnly,
114  bbs[nodeI].second(),
115  nodes[nodeI].second(),
116  bbs,
117  nodes,
118  vertI,
119  os
120  );
121  }
122 }
123 
124 
125 template<class Type>
127 (
128  const bool equalBinSize,
129  const label level,
130  const List<Type>& objects,
131  const pointField& points,
132  const DynamicList<label>& objectIDs,
133  const treeBoundBox& bb,
134  const label nodeI,
135 
137  DynamicList<labelPair>& nodes,
138  DynamicList<labelList>& addressing
139 ) const
140 {
141  const vector span = bb.span();
142 
143  // Determine which direction to divide the box
144 
145  direction maxDir = 0;
146  scalar maxSpan = span[maxDir];
147  for (label dirI = 1; dirI < 3; dirI++)
148  {
149  if (span[dirI] > maxSpan)
150  {
151  maxSpan = span[dirI];
152  maxDir = dirI;
153  }
154  }
155 
156 
157  scalar divide;
158 
159  if (equalBinSize)
160  {
161  // Pick up points used by this set of objects
162 
163  PackedBoolList isUsedPoint(points.size());
165 
166  forAll(objectIDs, i)
167  {
168  const label objI = objectIDs[i];
169  const Type& obj = objects[objI];
170 
171  forAll(obj, pI)
172  {
173  const label pointI = obj[pI];
174  if (isUsedPoint.set(pointI))
175  {
176  component.append(points[pointI][maxDir]);
177  }
178  }
179  }
180 
181  // Determine the median
182 
184 
185  divide = component[component.size()/2];
186  }
187  else
188  {
189  // Geometric middle
190  divide = bb.min()[maxDir] + 0.5*maxSpan;
191  }
192 
193 
194  scalar divMin = divide + tolerance_*maxSpan;
195  scalar divMax = divide - tolerance_*maxSpan;
196 
197 
198  // Assign the objects to min or max bin
199 
200  DynamicList<label> minBinObjectIDs(objectIDs.size());
202 
203  DynamicList<label> maxBinObjectIDs(objectIDs.size());
205 
206  forAll(objectIDs, i)
207  {
208  const label objI = objectIDs[i];
209  const Type& obj = objects[objI];
210 
211  bool intoMin = false;
212  bool intoMax = false;
213 
214  forAll(obj, pI)
215  {
216  const label pointI = obj[pI];
217  const point& pt = points[pointI];
218  if (pt[maxDir] < divMin)
219  {
220  intoMin = true;
221  }
222  if (pt[maxDir] > divMax)
223  {
224  intoMax = true;
225  }
226  }
227 
228 
229  if (intoMin)
230  {
231  minBinObjectIDs.append(objI);
232  const boundBox objBb(points, obj, false);
233  minBb.min() = min(minBb.min(), objBb.min());
234  minBb.max() = max(minBb.max(), objBb.max());
235  }
236  if (intoMax)
237  {
238  maxBinObjectIDs.append(objI);
239  const boundBox objBb(points, obj, false);
240  maxBb.min() = min(maxBb.min(), objBb.min());
241  maxBb.max() = max(maxBb.max(), objBb.max());
242  }
243  }
244 
245  // inflate box in case geometry reduces to 2-D
246  if (minBinObjectIDs.size())
247  {
248  minBb.inflate(0.01);
249  }
250  if (maxBinObjectIDs.size())
251  {
252  maxBb.inflate(0.01);
253  }
254 
255  minBinObjectIDs.shrink();
256  maxBinObjectIDs.shrink();
257 
258 
259  label minI;
260  if (minBinObjectIDs.size() > minLeafSize_ && level < maxLevel_)
261  {
262  // new leaf
263  minI = nodes.size();
264  nodes.append(labelPair(-1, -1));
265  }
266  else
267  {
268  // update existing leaf
269  minI = -addressing.size() - 1;
270  addressing.append(minBinObjectIDs);
271  }
272 
273  label maxI;
274  if (maxBinObjectIDs.size() > minLeafSize_ && level < maxLevel_)
275  {
276  // new leaf
277  maxI = nodes.size();
278  nodes.append(labelPair(-1, -1));
279  }
280  else
281  {
282  // update existing leaf
283  maxI = -addressing.size() - 1;
284  addressing.append(maxBinObjectIDs);
285  }
286 
287  nodes(nodeI) = labelPair(minI, maxI);
288  bbs(nodeI) = Pair<treeBoundBox>(minBb, maxBb);
289 
290  // recurse
291  if (minI >= 0)
292  {
293  createBoxes
294  (
295  equalBinSize,
296  level + 1,
297  objects,
298  points,
299  minBinObjectIDs,
300  minBb,
301  minI,
302  bbs,
303  nodes,
304  addressing
305  );
306  }
307  if (maxI >= 0)
308  {
309  createBoxes
310  (
311  equalBinSize,
312  level + 1,
313  objects,
314  points,
315  maxBinObjectIDs,
316  maxBb,
317  maxI,
318  bbs,
319  nodes,
320  addressing
321  );
322  }
323 }
324 
325 
326 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
327 
328 template<class Type>
330 :
331  maxLevel_(0),
332  minLeafSize_(0),
333  boundBoxes_(),
334  addressing_()
335 {}
336 
337 
338 template<class Type>
340 (
341  const UList<Type>& objects,
342  const pointField& points,
343  const bool equalBinSize,
344  const label maxLevel,
345  const label minLeafSize
346 )
347 :
348  maxLevel_(maxLevel),
349  minLeafSize_(minLeafSize),
350  boundBoxes_(),
351  addressing_()
352 {
353  if (objects.empty())
354  {
355  return;
356  }
357 
358 
359  DynamicList<Pair<treeBoundBox> > bbs(maxLevel);
360  DynamicList<labelPair> nodes(maxLevel);
361  DynamicList<labelList> addr(maxLevel);
362 
363  nodes.append(labelPair(-1, -1));
364  treeBoundBox topBb(points);
365  topBb.inflate(0.01);
366 
367  DynamicList<label> objectIDs(identity(objects.size()));
368 
370  (
371  equalBinSize,
372  0, // starting at top level
373  objects,
374  points,
375  objectIDs,
376  topBb,
377  0, // starting node
378 
379  bbs,
380  nodes,
381  addr
382  );
383 
384 
385  //{
386  // OFstream os("tree.obj");
387  // label vertI = 0;
388  // writeOBJ
389  // (
390  // true, // leavesOnly
391  // false, // writeLinesOnly
392  //
393  // topBb,
394  // 0,
395  // bbs,
396  // nodes,
397  // vertI,
398  // os
399  // );
400  //}
401 
402 
403  // transfer flattened tree to persistent storage
404  DynamicList<treeBoundBox> boundBoxes(2*bbs.size());
405  DynamicList<labelList> addressing(2*addr.size());
406  forAll(nodes, nodeI)
407  {
408  if (nodes[nodeI].first() < 0)
409  {
410  boundBoxes.append(bbs[nodeI].first());
411  addressing.append(addr[nodeI + 1]);
412  }
413  if (nodes[nodeI].second() < 0)
414  {
415  boundBoxes.append(bbs[nodeI].second());
416  addressing.append(addr[nodeI + 1]);
417  }
418  }
419 
422 }
423 
424 
425 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
426 
427 template<class Type>
429 {
430  return boundBoxes_;
431 }
432 
433 
434 template<class Type>
436 {
437  return addressing_;
438 }
439 
440 
441 template<class Type>
443 {
444  forAll(boundBoxes_, i)
445  {
446  const treeBoundBox& bb = boundBoxes_[i];
447 
448  if (bb.contains(pt))
449  {
450  return true;
451  }
452  }
453 
454  return false;
455 }
456 
457 
458 template<class Type>
460 {
461  forAll(boundBoxes_, i)
462  {
463  const treeBoundBox& bb = boundBoxes_[i];
464 
465  if (bb.overlaps(bbIn))
466  {
467  return true;
468  }
469  }
470 
471  return false;
472 }
473 
474 
475 // * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * * //
476 
477 template<class Type>
479 {
480  if (os.format() == IOstream::ASCII)
481  {
482  os << tree.maxLevel_ << token::SPACE
483  << tree.minLeafSize_ << token::SPACE
484  << tree.boundBoxes_ << token::SPACE
485  << tree.addressing_ << token::SPACE;
486  }
487  else
488  {
489  os.write
490  (
491  reinterpret_cast<const char*>(&tree.maxLevel_),
492  sizeof(tree.maxLevel_)
493  + sizeof(tree.minLeafSize_)
494  );
495  os << tree.boundBoxes_
496  << tree.addressing_;
497  }
498 
499  os.check("Ostream& operator<<(Ostream&, const AABBTree<Type>&)");
500  return os;
501 }
502 
503 
504 template<class Type>
505 Foam::Istream& Foam::operator>>(Istream& is, AABBTree<Type>& tree)
506 {
507  if (is.format() == IOstream::ASCII)
508  {
509  is >> tree.maxLevel_
510  >> tree.minLeafSize_
511  >> tree.boundBoxes_
512  >> tree.addressing_;
513  }
514  else
515  {
516  is.read
517  (
518  reinterpret_cast<char*>(&tree.maxLevel_),
519  sizeof(tree.maxLevel_)
520  + sizeof(tree.minLeafSize_)
521  );
522  is >> tree.boundBoxes_
523  >> tree.addressing_;
524  }
525 
526  is.check("Istream& operator>>(Istream&, AABBTree<Type>&)");
527  return is;
528 }
529 
530 
531 // ************************************************************************* //
Foam::IOstream::format
streamFormat format() const
Return current stream format.
Definition: IOstream.H:377
meshTools.H
Foam::PackedBoolList
A bit-packed bool list.
Definition: PackedBoolList.H:63
Foam::component
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
Definition: FieldFieldFunctions.C:41
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:60
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
writeOBJ
void writeOBJ(Ostream &os, label &vertI, const tetPoints &tet)
Definition: Test-tetTetOverlap.C:38
Foam::treeBoundBox::points
tmp< pointField > points() const
Vertex coordinates. In octant coding.
Definition: treeBoundBox.C:163
Foam::DynamicList< label >
Foam::AABBTree::pointInside
bool pointInside(const point &pt) const
Determine whether a point is inside the bounding boxes.
Definition: AABBTree.C:442
Foam::boundBox::inflate
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
Definition: boundBox.C:210
Foam::PackedBoolList::set
void set(const PackedList< 1 > &)
Set specified bits.
Definition: PackedBoolList.C:169
Foam::treeBoundBox
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:75
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
Foam::AABBTree::overlaps
bool overlaps(const boundBox &bbIn) const
Determine whether a bounding box overlaps the tree bounding.
Definition: AABBTree.C:459
Foam::List::transfer
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Foam::AABBTree::boundBoxes
const List< treeBoundBox > & boundBoxes() const
Return the bounding boxes making up the tree.
Definition: AABBTree.C:428
Foam::AABBTree::boundBoxes_
List< treeBoundBox > boundBoxes_
Bounding boxes making up the tree.
Definition: AABBTree.H:87
Foam::treeBoundBox::edges
static const edgeList edges
Edge to point addressing.
Definition: treeBoundBox.H:157
Foam::AABBTree::writeOBJ
void writeOBJ(const bool writeLinesOnly, const treeBoundBox &bb, label &vertI, Ostream &os) const
Write OBJ file of bounding box.
Definition: AABBTree.C:38
Foam::AABBTree::createBoxes
void createBoxes(const bool equalBinSize, const label level, const List< Type > &objects, const pointField &points, const DynamicList< label > &objectIDs, const treeBoundBox &bb, const label nodeI, DynamicList< Pair< treeBoundBox > > &bbs, DynamicList< labelPair > &nodes, DynamicList< labelList > &addressing) const
Create the bounding boxes by interrogating points.
Definition: AABBTree.C:127
Foam::divide
void divide(FieldField< Field, Type > &f, const FieldField< Field, Type > &f1, const FieldField< Field, scalar > &f2)
Foam::boundBox::span
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:84
Foam::IOstream::ASCII
@ ASCII
Definition: IOstream.H:88
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:57
Foam::List::append
void append(const T &)
Append an element at the end of the list.
Foam::Ostream::write
virtual Ostream & write(const token &)=0
Write next token to stream.
Foam::nl
static const char nl
Definition: Ostream.H:260
PackedBoolList.H
Foam::treeBoundBox::faces
static const faceList faces
Face to point addressing.
Definition: treeBoundBox.H:154
AABBTree.H
Foam::DynamicList::shrink
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:258
Foam::boundBox::min
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:54
Foam::operator<<
Ostream & operator<<(Ostream &, const edgeMesh &)
Definition: edgeMeshIO.C:130
Foam::AABBTree::AABBTree
AABBTree()
Null constructor.
Definition: AABBTree.C:329
Foam::identity
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Foam::IOstream::check
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:92
Foam::AABBTree::maxLevel_
label maxLevel_
Maximum tree level.
Definition: AABBTree.H:81
Foam::DynamicList::append
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::treeBoundBox::contains
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Definition: treeBoundBox.C:395
Foam::Pair
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
Foam::AABBTree::addressing
const List< labelList > & addressing() const
Return the contents addressing.
Definition: AABBTree.C:435
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::AABBTree
Templated tree of axis-aligned bounding boxes (AABB)
Definition: AABBTree.H:57
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::UList< Type >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: doubleFloat.H:94
Foam::operator>>
Istream & operator>>(Istream &, edgeMesh &)
Definition: edgeMeshIO.C:141
Foam::direction
unsigned char direction
Definition: direction.H:43
Foam::boundBox
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:55
Foam::UList::empty
bool empty() const
Return true if the UList is empty (ie, size() is zero).
Definition: UListI.H:313
Foam::AABBTree::minLeafSize_
label minLeafSize_
Minimum points per leaf.
Definition: AABBTree.H:84
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
Foam::treeBoundBox::overlaps
bool overlaps(const boundBox &) const
Overlaps other bounding box?
Definition: boundBoxI.H:120
Foam::sort
void sort(UList< T > &)
Definition: UList.C:107
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:53
Foam::UList::size
label size() const
Return the number of elements in the UList.
Definition: UListI.H:299
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::labelPair
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
Foam::AABBTree::addressing_
List< labelList > addressing_
Leaf adressing.
Definition: AABBTree.H:90
Foam::token::SPACE
@ SPACE
Definition: token.H:95
Foam::Istream::read
virtual Istream & read(token &)=0
Return next token from stream.