1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "indexedOctree.H"
28 #include "linePointRef.H"
29 #include "triSurface.H"
30 #include "meshTools.H"
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 // Does bb intersect a sphere around sample? Or is any corner point of bb
41 // closer than nearestDistSqr to sample.
43 bool indexedOctree<Type>::intersects
47 const scalar nearestDistSqr,
51 // Find out where sample is in relation to bb.
52 // Find nearest point on bb.
55 for (direction dir = 0; dir < vector::nComponents; dir++)
57 scalar d0 = p0[dir] - sample[dir];
58 scalar d1 = p1[dir] - sample[dir];
60 if ((d0 > 0) != (d1 > 0))
62 // sample inside both extrema. This component does not add any
65 else if (mag(d0) < mag(d1))
74 if (distSqr > nearestDistSqr)
84 // Does bb intersect a sphere around sample? Or is any corner point of bb
85 // closer than nearestDistSqr to sample.
87 bool indexedOctree<Type>::intersects
89 const treeBoundBox& parentBb,
90 const direction octant,
91 const scalar nearestDistSqr,
95 //- Speeded up version of
96 // treeBoundBox subBb(parentBb.subBbox(mid, octant))
105 const point& min = parentBb.min();
106 const point& max = parentBb.max();
110 if (octant & treeBoundBox::RIGHTHALF)
119 if (octant & treeBoundBox::TOPHALF)
128 if (octant & treeBoundBox::FRONTHALF)
137 const point mid(0.5*(min+max));
139 return intersects(mid, other, nearestDistSqr, sample);
144 // Construction helper routines
145 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 // Split list of indices into 8 bins
149 template <class Type>
150 void indexedOctree<Type>::divide
152 const labelList& indices,
153 const treeBoundBox& bb,
154 labelListList& result
157 List<DynamicList<label> > subIndices(8);
158 for (direction octant = 0; octant < subIndices.size(); octant++)
160 subIndices[octant].setSize(indices.size()/8);
163 // Precalculate bounding boxes.
164 FixedList<treeBoundBox, 8> subBbs;
165 for (direction octant = 0; octant < subBbs.size(); octant++)
167 subBbs[octant] = bb.subBbox(octant);
172 label shapeI = indices[i];
174 for (direction octant = 0; octant < 8; octant++)
176 if (shapes_.overlaps(shapeI, subBbs[octant]))
178 subIndices[octant].append(shapeI);
184 for (direction octant = 0; octant < subIndices.size(); octant++)
186 subIndices[octant].shrink();
187 result[octant].transfer(subIndices[octant]);
188 subIndices[octant].clear();
193 // Subdivide the (content) node.
194 template <class Type>
195 typename indexedOctree<Type>::node indexedOctree<Type>::divide
197 const treeBoundBox& bb,
198 DynamicList<labelList>& contents,
202 const labelList& indices = contents[contentI];
208 bb.min()[0] >= bb.max()[0]
209 || bb.min()[1] >= bb.max()[1]
210 || bb.min()[2] >= bb.max()[2]
213 FatalErrorIn("indexedOctree<Type>::divide")
214 << "Badly formed bounding box:" << bb
215 << abort(FatalError);
221 labelListList dividedIndices(8);
222 divide(indices, bb, dividedIndices);
224 // Have now divided the indices into 8 (possibly empty) subsets.
225 // Replace current contentI with the first (non-empty) subset.
227 bool replaced = false;
229 for (direction octant = 0; octant < dividedIndices.size(); octant++)
231 labelList& subIndices = dividedIndices[octant];
233 if (subIndices.size() > 0)
237 contents[contentI].transfer(subIndices);
238 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
243 // Store at end of contents.
244 // note dummy append + transfer trick
245 label sz = contents.size();
246 contents.append(labelList(0));
247 contents[sz].transfer(subIndices);
248 nod.subNodes_[octant] = contentPlusOctant(sz, octant);
253 // Mark node as empty
254 nod.subNodes_[octant] = emptyPlusOctant(octant);
262 // Split any contents node with more than minSize elements.
263 template <class Type>
264 void indexedOctree<Type>::splitNodes
267 DynamicList<indexedOctree<Type>::node>& nodes,
268 DynamicList<labelList>& contents
271 label currentSize = nodes.size();
273 // Take care to loop only over old nodes.
274 // Also we loop over the same DynamicList which gets modified and
275 // moved so make sure not to keep any references!
276 for (label nodeI = 0; nodeI < currentSize; nodeI++)
280 direction octant = 0;
281 octant < nodes[nodeI].subNodes_.size();
285 labelBits index = nodes[nodeI].subNodes_[octant];
289 // tree node. Leave intact.
291 else if (isContent(index))
293 label contentI = getContent(index);
295 if (contents[contentI].size() > minSize)
297 // Create node for content.
299 // Find the bounding box for the subnode
300 const node& nod = nodes[nodeI];
301 const treeBoundBox bb(nod.bb_.subBbox(octant));
303 node subNode(divide(bb, contents, contentI));
304 subNode.parent_ = nodeI;
305 label sz = nodes.size();
306 nodes.append(subNode);
307 nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
315 // Reorder contents to be in same order as nodes. Returns number of nodes on
317 template <class Type>
318 label indexedOctree<Type>::compactContents
320 DynamicList<node>& nodes,
321 DynamicList<labelList>& contents,
322 const label compactLevel,
326 List<labelList>& compactedContents,
330 const node& nod = nodes[nodeI];
334 if (level < compactLevel)
336 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
338 labelBits index = nod.subNodes_[octant];
342 nNodes += compactContents
355 else if (level == compactLevel)
357 // Compact all content on this level
358 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
360 labelBits index = nod.subNodes_[octant];
362 if (isContent(index))
364 label contentI = getContent(index);
366 compactedContents[compactI].transfer(contents[contentI]);
368 // Subnode is at compactI. Adapt nodeI to point to it
369 nodes[nodeI].subNodes_[octant] =
370 contentPlusOctant(compactI, octant);
374 else if (isNode(index))
384 // Pre-calculates wherever possible the volume status per node/subnode.
385 // Recurses to determine status of lowest level boxes. Level above is
386 // combination of octants below.
387 template <class Type>
388 typename indexedOctree<Type>::volumeType indexedOctree<Type>::calcVolumeType
393 const node& nod = nodes_[nodeI];
395 volumeType myType = UNKNOWN;
397 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
401 labelBits index = nod.subNodes_[octant];
405 // tree node. Recurse.
406 subType = calcVolumeType(getNode(index));
408 else if (isContent(index))
410 // Contents. Depending on position in box might be on either
416 // No data in this octant. Set type for octant acc. to the mid
417 // of its bounding box.
418 const treeBoundBox subBb = nod.bb_.subBbox(octant);
420 subType = volumeType(shapes_.getVolumeType(*this, subBb.mid()));
424 nodeTypes_.set((nodeI<<3)+octant, subType);
426 // Combine sub node types into type for treeNode. Result is 'mixed' if
427 // types differ among subnodes.
428 if (myType == UNKNOWN)
432 else if (subType != myType)
441 template <class Type>
442 typename indexedOctree<Type>::volumeType indexedOctree<Type>::getVolumeType
448 const node& nod = nodes_[nodeI];
450 direction octant = nod.bb_.subOctant(sample);
452 volumeType octantType = volumeType(nodeTypes_.get((nodeI<<3)+octant));
454 if (octantType == INSIDE)
458 else if (octantType == OUTSIDE)
462 else if (octantType == UNKNOWN)
464 // Can happen for e.g. non-manifold surfaces.
467 else if (octantType == MIXED)
469 labelBits index = nod.subNodes_[octant];
474 volumeType subType = getVolumeType(getNode(index), sample);
478 else if (isContent(index))
480 // Content. Defer to shapes.
481 return volumeType(shapes_.getVolumeType(*this, sample));
485 // Empty node. Cannot have 'mixed' as its type since not divided
486 // up and has no items inside it.
489 "indexedOctree<Type>::getVolumeType"
490 "(const label, const point&)"
491 ) << "Sample:" << sample << " node:" << nodeI
492 << " with bb:" << nodes_[nodeI].bb_ << nl
493 << "Empty subnode has invalid volume type MIXED."
494 << abort(FatalError);
503 "indexedOctree<Type>::getVolumeType"
504 "(const label, const point&)"
505 ) << "Sample:" << sample << " at node:" << nodeI
506 << " octant:" << octant
507 << " with bb:" << nod.bb_.subBbox(octant) << nl
508 << "Node has invalid volume type " << octantType
509 << abort(FatalError);
516 template <class Type>
517 typename indexedOctree<Type>::volumeType indexedOctree<Type>::getSide
519 const vector& outsideNormal,
523 if ((outsideNormal&vec) >= 0)
539 // Find nearest point starting from nodeI
540 template <class Type>
541 void indexedOctree<Type>::findNearest
546 scalar& nearestDistSqr,
547 label& nearestShapeI,
551 const node& nod = nodes_[nodeI];
553 // Determine order to walk through octants
554 FixedList<direction, 8> octantOrder;
555 nod.bb_.searchOrder(sample, octantOrder);
557 // Go into all suboctants (one containing sample first) and update nearest.
558 for (direction i = 0; i < 8; i++)
560 direction octant = octantOrder[i];
562 labelBits index = nod.subNodes_[octant];
566 label subNodeI = getNode(index);
568 const treeBoundBox& subBb = nodes_[subNodeI].bb_;
570 if (intersects(subBb.min(), subBb.max(), nearestDistSqr, sample))
583 else if (isContent(index))
598 contents_[getContent(index)],
611 // Find nearest point to line.
612 template <class Type>
613 void indexedOctree<Type>::findNearest
616 const linePointRef& ln,
618 treeBoundBox& tightest,
619 label& nearestShapeI,
624 const node& nod = nodes_[nodeI];
625 const treeBoundBox& nodeBb = nod.bb_;
627 // Determine order to walk through octants
628 FixedList<direction, 8> octantOrder;
629 nod.bb_.searchOrder(ln.centre(), octantOrder);
631 // Go into all suboctants (one containing sample first) and update nearest.
632 for (direction i = 0; i < 8; i++)
634 direction octant = octantOrder[i];
636 labelBits index = nod.subNodes_[octant];
640 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
642 if (subBb.intersects(tightest))
656 else if (isContent(index))
658 const treeBoundBox subBb(nodeBb.subBbox(octant));
660 if (subBb.intersects(tightest))
664 contents_[getContent(index)],
678 // Walk tree to neighbouring node. Gets current position as
679 // node and octant in this node and walks in the direction given by
680 // the faceID (one of treeBoundBox::LEFTBIT, RIGHTBIT etc.)
681 // Returns false if edge of tree hit.
682 template <class Type>
683 bool indexedOctree<Type>::walkToNeighbour
685 const point& facePoint,
686 const direction faceID, // direction to walk in
691 // Find out how to test for octant. Say if we want to go left we need
692 // to traverse up the tree until we hit a node where our octant is
695 direction octantMask = 0;
696 direction valueMask = 0;
698 if ((faceID & treeBoundBox::LEFTBIT) != 0)
700 // We want to go left so check if in right octant.
701 octantMask |= treeBoundBox::RIGHTHALF;
702 valueMask |= treeBoundBox::RIGHTHALF;
704 else if ((faceID & treeBoundBox::RIGHTBIT) != 0)
706 octantMask |= treeBoundBox::RIGHTHALF; // valueMask already 0
709 if ((faceID & treeBoundBox::BOTTOMBIT) != 0)
711 octantMask |= treeBoundBox::TOPHALF;
712 valueMask |= treeBoundBox::TOPHALF;
714 else if ((faceID & treeBoundBox::TOPBIT) != 0)
716 octantMask |= treeBoundBox::TOPHALF;
719 if ((faceID & treeBoundBox::BACKBIT) != 0)
721 octantMask |= treeBoundBox::FRONTHALF;
722 valueMask |= treeBoundBox::FRONTHALF;
724 else if ((faceID & treeBoundBox::FRONTBIT) != 0)
726 octantMask |= treeBoundBox::FRONTHALF;
729 // Go up until we have chance to cross to the wanted direction
730 while (valueMask != (octant & octantMask))
732 label parentNodeI = nodes_[nodeI].parent_;
734 if (parentNodeI == -1)
736 // Reached edge of tree
740 const node& parentNode = nodes_[parentNodeI];
742 // Find octant nodeI is in.
743 direction parentOctant = 255;
745 for (direction i = 0; i < parentNode.subNodes_.size(); i++)
747 labelBits index = parentNode.subNodes_[i];
749 if (isNode(index) && getNode(index) == nodeI)
756 if (parentOctant == 255)
758 FatalErrorIn("walkToNeighbour")
759 << abort(FatalError);
762 octant = parentOctant;
765 // So now we hit the correct parent node. Switch to the correct octant
766 octant ^= octantMask;
768 // See if we need to travel down. Note that we already go into the
769 // the first level ourselves (instead of having findNode decide) since
770 // the facePoint is now exactly on the mid of the node so there could
771 // be truncation problems.
772 labelBits index = nodes_[nodeI].subNodes_[octant];
776 labelBits node = findNode(getNode(index), facePoint);
778 nodeI = getNode(node);
779 octant = getOctant(node);
786 // Return unique number for the face of a bounding box a point is on.
787 // (number is single bit but not really nessecary)
788 // Return 0 if point not on any face of bb.
789 template <class Type>
790 direction indexedOctree<Type>::getFace(const treeBoundBox& bb, const point& pt)
792 direction faceID = 0;
794 if (pt.x() <= bb.min().x())
796 faceID |= treeBoundBox::LEFTBIT;
798 if (pt.x() >= bb.max().x())
800 faceID |= treeBoundBox::RIGHTBIT;
803 if (pt.y() <= bb.min().y())
805 faceID |= treeBoundBox::BOTTOMBIT;
807 if (pt.y() >= bb.max().y())
809 faceID |= treeBoundBox::TOPBIT;
812 if (pt.z() <= bb.min().z())
814 faceID |= treeBoundBox::BACKBIT;
816 if (pt.z() >= bb.max().z())
818 faceID |= treeBoundBox::FRONTBIT;
824 // Traverse a node. If intersects a triangle return first intersection point.
825 // Else return the bounxing box face hit:
826 // hitInfo.point = coordinate of intersection of ray with bounding box
827 // faceID = index of bounding box face
828 template <class Type>
829 void indexedOctree<Type>::traverseNode
836 const direction octant,
838 pointIndexHit& hitInfo,
842 const node& nod = nodes_[nodeI];
844 labelBits index = nod.subNodes_[octant];
846 if (isContent(index))
848 const labelList& indices = contents_[getContent(index)];
852 // Find any intersection
854 forAll(indices, elemI)
856 label shapeI = indices[elemI];
859 bool hit = shapes_.intersects(shapeI, start, end, pt);
863 // Hit so pt is nearer than nearestPoint.
866 hitInfo.setIndex(shapeI);
867 hitInfo.setPoint(pt);
874 // Find nearest intersection.
876 point nearestPoint(end);
878 forAll(indices, elemI)
880 label shapeI = indices[elemI];
883 bool hit = shapes_.intersects(shapeI, start, nearestPoint, pt);
887 // Hit so pt is nearer than nearestPoint.
891 hitInfo.setIndex(shapeI);
892 hitInfo.setPoint(pt);
898 // Found intersected shape.
904 // Nothing intersected in this node
905 // Traverse to end of node. Do by ray tracing back from end and finding
906 // intersection with bounding box of node.
912 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
914 if (!subBb.intersects(end, start, pt))
918 WarningIn("indexedOctree<Type>::traverseNode")
919 << "Did not hit side of box " << subBb
920 << " with ray from " << start << " to " << end
925 faceID = getFace(subBb, pt);
930 const treeBoundBox subBb(nod.bb_.subBbox(octant));
932 if (!subBb.intersects(end, start, pt))
936 WarningIn("indexedOctree<Type>::traverseNode")
937 << "Did not hit side of box " << subBb
938 << " with ray from " << start << " to " << end
943 faceID = getFace(subBb, pt);
948 // Return miss. Set misspoint to face.
949 hitInfo.setPoint(pt);
953 // Find first intersection
954 template <class Type>
955 pointIndexHit indexedOctree<Type>::findLine
958 const point& treeStart,
959 const point& treeEnd,
960 const label startNodeI,
961 const direction startOctant
964 const vector dir(treeEnd - treeStart);
966 // Current node as parent+octant
967 label nodeI = startNodeI;
968 direction octant = startOctant;
970 // Current position. Initialize to miss
971 pointIndexHit hitInfo(false, treeStart, -1);
973 // Side of current bounding box current point is on
974 direction faceID = 0;
978 // Ray-trace to end of current node. Updates point (either on triangle
979 // in case of hit or on node bounding box in case of miss)
981 point startPoint(hitInfo.rawPoint());
986 startPoint, // Note: pass in copy since hitInfo
987 // also used in return value.
997 // Did we hit a triangle?
1005 // Was never inside the tree. Return miss.
1009 //Pout<< "findLine : treeStart:" << treeStart
1010 // << " treeEnd:" << treeEnd
1011 // << " tracked from " << startPoint << " to edge of nodeBb:"
1012 // << hitInfo.missPoint()
1013 // << " node:" << nodeI << " octant:" << octant
1015 // << nodes_[nodeI].bb_.subBbox(octant)
1019 // Nothing hit so we are on face of bounding box (given as node+octant+
1020 // faceID). Traverse to neighbouring node.
1022 bool ok = walkToNeighbour
1024 hitInfo.rawPoint(), // point on face
1025 faceID, // direction to walk in
1032 // Hit the edge of the tree. Return miss.
1040 // Find first intersection
1041 template <class Type>
1042 pointIndexHit indexedOctree<Type>::findLine
1049 pointIndexHit hitInfo;
1051 if (nodes_.size() > 0)
1053 const treeBoundBox& treeBb = nodes_[0].bb_;
1055 direction startBit = treeBb.posBits(start);
1056 direction endBit = treeBb.posBits(end);
1058 if ((startBit & endBit) != 0)
1060 // Both start and end outside domain and in same block.
1061 return pointIndexHit(false, vector::zero, -1);
1064 point trackStart(start);
1065 point trackEnd(end);
1069 // Track start to inside domain.
1070 if (!treeBb.intersects(start, end, trackStart))
1072 return pointIndexHit(false, vector::zero, -1);
1078 // Track end to inside domain.
1079 if (!treeBb.intersects(end, trackStart, trackEnd))
1081 return pointIndexHit(false, vector::zero, -1);
1085 // Find lowest level tree node that start is in.
1086 labelBits index = findNode(0, trackStart);
1088 label parentNodeI = getNode(index);
1089 direction octant = getOctant(index);
1105 template <class Type>
1106 void indexedOctree<Type>::findBox
1109 const treeBoundBox& searchBox,
1110 labelHashSet& elements
1113 const node& nod = nodes_[nodeI];
1114 const treeBoundBox& nodeBb = nod.bb_;
1116 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
1118 labelBits index = nod.subNodes_[octant];
1122 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
1124 if (subBb.intersects(searchBox))
1126 findBox(getNode(index), searchBox, elements);
1129 else if (isContent(index))
1131 const treeBoundBox subBb(nodeBb.subBbox(octant));
1133 if (subBb.intersects(searchBox))
1135 const labelList& indices = contents_[getContent(index)];
1139 label shapeI = indices[i];
1141 if (shapes_.overlaps(shapeI, searchBox))
1143 elements.insert(shapeI);
1152 // Number of elements in node.
1153 template <class Type>
1154 label indexedOctree<Type>::countElements(const labelBits index) const
1161 label nodeI = getNode(index);
1163 const node& nod = nodes_[nodeI];
1165 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
1167 nElems += countElements(nod.subNodes_[octant]);
1170 else if (isContent(index))
1172 nElems += contents_[getContent(index)].size();
1183 template <class Type>
1184 void indexedOctree<Type>::writeOBJ
1187 const direction octant
1192 "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
1195 labelBits index = nodes_[nodeI].subNodes_[octant];
1201 subBb = nodes_[getNode(index)].bb_;
1203 else if (isContent(index))
1205 subBb = nodes_[nodeI].bb_.subBbox(octant);
1208 Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
1209 << " to " << str.name() << endl;
1213 // Dump bounding box
1214 pointField bbPoints(subBb.points());
1216 label pointVertI = vertI;
1219 meshTools::writeOBJ(str, bbPoints[i]);
1223 forAll(treeBoundBox::edges, i)
1225 const edge& e = treeBoundBox::edges[i];
1227 str<< "l " << e[0]+pointVertI+1 << ' ' << e[1]+pointVertI+1 << nl;
1232 //if (isContent(index))
1234 // const labelList& indices = contents_[getContent(index)];
1235 // const triSurface& surf = shapes_.surface();
1236 // const pointField& points = surf.points();
1238 // forAll(indices, i)
1240 // label shapeI = indices[i];
1242 // const labelledTri& f = surf[shapeI];
1244 // meshTools::writeOBJ(str, points[f[0]]);
1246 // meshTools::writeOBJ(str, points[f[1]]);
1248 // meshTools::writeOBJ(str, points[f[2]]);
1251 // str<< "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI << ' '
1252 // << vertI-2 << nl;
1258 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1260 template <class Type>
1261 indexedOctree<Type>::indexedOctree(const Type& shapes)
1270 template <class Type>
1271 indexedOctree<Type>::indexedOctree
1274 const List<node>& nodes,
1275 const labelListList& contents
1280 contents_(contents),
1285 template <class Type>
1286 indexedOctree<Type>::indexedOctree
1289 const treeBoundBox& bb,
1290 const label maxLevels, // maximum number of levels
1291 const scalar maxLeafRatio,
1292 const scalar maxDuplicity
1300 if (shapes.size() == 0)
1305 // Start off with one node with all shapes in it.
1306 DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
1307 DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
1308 contents.append(identity(shapes.size()));
1311 node topNode(divide(bb, contents, 0));
1312 nodes.append(topNode);
1315 // Now have all contents at level 1. Create levels by splitting levels
1320 for (; nLevels < maxLevels; nLevels++)
1322 // Count number of references into shapes (i.e. contents)
1326 nEntries += contents[i].size();
1331 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
1332 << " nLevels:" << nLevels << nl
1333 << " nEntries per treeLeaf:" << nEntries/contents.size()
1335 << " nEntries per shape (duplicity):"
1336 << nEntries/shapes.size()
1343 //nEntries < maxLeafRatio*contents.size()
1345 nEntries > maxDuplicity*shapes.size()
1352 // Split nodes with more than maxLeafRatio elements
1353 label nOldNodes = nodes.size();
1356 label(maxLeafRatio),
1361 if (nOldNodes == nodes.size())
1372 // Compact such that deeper level contents are always after the
1373 // ones for a shallower level. This way we can slice a coarser level
1375 contents_.setSize(contents.size());
1393 if (compactI == contents_.size())
1395 // Transferred all contents to contents_ (in order breadth first)
1401 nodes_.transfer(nodes);
1408 forAll(contents_, i)
1410 nEntries += contents_[i].size();
1413 Pout<< "indexedOctree<Type>::indexedOctree : finished construction:"
1415 << " shapes:" << shapes.size() << nl
1416 << " nLevels:" << nLevels << nl
1417 << " treeNodes:" << nodes_.size() << nl
1418 << " nEntries:" << nEntries << nl
1419 << " per treeLeaf:" << nEntries/contents.size() << nl
1420 << " per shape (duplicity):" << nEntries/shapes.size() << nl
1426 template <class Type>
1427 indexedOctree<Type>::indexedOctree
1440 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1442 template <class Type>
1443 pointIndexHit indexedOctree<Type>::findNearest
1445 const point& sample,
1446 const scalar startDistSqr
1449 scalar nearestDistSqr = startDistSqr;
1450 label nearestShapeI = -1;
1453 if (nodes_.size() == 0)
1455 nearestPoint = vector::zero;
1470 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
1474 template <class Type>
1475 pointIndexHit indexedOctree<Type>::findNearest
1477 const linePointRef& ln,
1478 treeBoundBox& tightest,
1482 label nearestShapeI = -1;
1485 if (nodes_.size() == 0)
1487 nearestPoint = vector::zero;
1503 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
1507 // Find nearest intersection
1508 template <class Type>
1509 pointIndexHit indexedOctree<Type>::findLine
1515 return findLine(false, start, end);
1519 // Find nearest intersection
1520 template <class Type>
1521 pointIndexHit indexedOctree<Type>::findLineAny
1527 return findLine(true, start, end);
1531 template <class Type>
1532 labelList indexedOctree<Type>::findBox(const boundBox& searchBox) const
1534 // Storage for labels of shapes inside bb. Size estimate.
1535 labelHashSet elements(shapes_.size() / 100);
1537 if (nodes_.size() > 0)
1539 findBox(0, searchBox, elements);
1542 return elements.toc();
1546 // Find node (as parent+octant) containing point
1547 template <class Type>
1548 labelBits indexedOctree<Type>::findNode
1554 if (nodes_.size() == 0)
1556 // Empty tree. Return what?
1557 return nodePlusOctant(nodeI, 0);
1560 const node& nod = nodes_[nodeI];
1562 direction octant = nod.bb_.subOctant(sample);
1564 labelBits index = nod.subNodes_[octant];
1569 return findNode(getNode(index), sample);
1571 else if (isContent(index))
1573 // Content. Return treenode+octant
1574 return nodePlusOctant(nodeI, octant);
1578 // Empty. Return treenode+octant
1579 return nodePlusOctant(nodeI, octant);
1584 // Determine type (inside/outside/mixed) per node.
1585 template <class Type>
1586 typename indexedOctree<Type>::volumeType indexedOctree<Type>::getVolumeType
1591 if (nodes_.size() == 0)
1596 if (nodeTypes_.size() != 8*nodes_.size())
1598 // Calculate type for every octant of node.
1600 nodeTypes_.setSize(8*nodes_.size());
1601 nodeTypes_ = UNKNOWN;
1612 forAll(nodeTypes_, i)
1614 volumeType type = volumeType(nodeTypes_.get(i));
1616 if (type == UNKNOWN)
1620 else if (type == MIXED)
1624 else if (type == INSIDE)
1628 else if (type == OUTSIDE)
1634 FatalErrorIn("getVolumeType") << abort(FatalError);
1638 Pout<< "indexedOctree<Type>::getVolumeType : "
1640 << " nodes_:" << nodes_.size()
1641 << " nodeTypes_:" << nodeTypes_.size()
1642 << " nUNKNOWN:" << nUNKNOWN
1643 << " nMIXED:" << nMIXED
1644 << " nINSIDE:" << nINSIDE
1645 << " nOUTSIDE:" << nOUTSIDE
1650 return getVolumeType(0, sample);
1654 // Print contents of nodeI
1655 template <class Type>
1656 void indexedOctree<Type>::print
1659 const bool printContents,
1663 const node& nod = nodes_[nodeI];
1664 const treeBoundBox& bb = nod.bb_;
1666 os << "nodeI:" << nodeI << " bb:" << bb << nl
1667 << "parent:" << nod.parent_ << nl
1668 << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
1670 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
1672 const treeBoundBox subBb(bb.subBbox(octant));
1674 labelBits index = nod.subNodes_[octant];
1679 label subNodeI = getNode(index);
1681 os << "octant:" << octant
1682 << " node: n:" << countElements(index)
1683 << " bb:" << subBb << endl;
1685 string oldPrefix = os.prefix();
1686 os.prefix() = " " + oldPrefix;
1688 print(os, printContents, subNodeI);
1690 os.prefix() = oldPrefix;
1692 else if (isContent(index))
1694 const labelList& indices = contents_[getContent(index)];
1696 os << "octant:" << octant
1697 << " content: n:" << indices.size()
1705 os << ' ' << indices[j];
1712 os << "octant:" << octant << " empty:" << subBb << endl;
1718 // Print contents of nodeI
1719 template <class Type>
1720 bool indexedOctree<Type>::write(Ostream& os) const
1728 template <class Type>
1729 Ostream& operator<<(Ostream& os, const indexedOctree<Type>& t)
1732 os << t.bb() << token::SPACE << t.nodes()
1733 << token::SPACE << t.contents();
1737 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1739 } // End namespace Foam
1741 // ************************************************************************* //