ENH: simplify sub-octant bound-box search
- basic support for splitting into two at a given position and face to keep
This commit is contained in:
parent
fc9311ba0d
commit
b129446221
3
applications/test/boundBox2/Make/files
Normal file
3
applications/test/boundBox2/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-boundBox2.C
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-boundBox2
|
2
applications/test/boundBox2/Make/options
Normal file
2
applications/test/boundBox2/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
235
applications/test/boundBox2/Test-boundBox2.C
Normal file
235
applications/test/boundBox2/Test-boundBox2.C
Normal file
@ -0,0 +1,235 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Description
|
||||
Test bounding box behaviour
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "polyMesh.H"
|
||||
#include "line.H"
|
||||
#include "Random.H"
|
||||
#include "treeBoundBox.H"
|
||||
#include "bitSet.H"
|
||||
#include "HashSet.H"
|
||||
#include "ListOps.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
//- simple helper to create a cube, given lower corner and width
|
||||
boundBox cube(scalar start, scalar width)
|
||||
{
|
||||
return boundBox
|
||||
(
|
||||
point::uniform(start),
|
||||
point::uniform(start + width)
|
||||
);
|
||||
}
|
||||
|
||||
//- simple helper to create a cube, given mid-point and width
|
||||
boundBox cubeAt(const point& mid, scalar width)
|
||||
{
|
||||
boundBox bb(mid);
|
||||
bb.grow(0.5*width);
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
word faceName(direction whichFace)
|
||||
{
|
||||
switch (whichFace)
|
||||
{
|
||||
case treeBoundBox::LEFT : return "-x";
|
||||
case treeBoundBox::RIGHT : return "+x";
|
||||
|
||||
case treeBoundBox::BOTTOM : return "-y";
|
||||
case treeBoundBox::TOP : return "+y";
|
||||
|
||||
case treeBoundBox::BACK : return "-z";
|
||||
case treeBoundBox::FRONT : return "+z";
|
||||
}
|
||||
|
||||
return "??";
|
||||
}
|
||||
|
||||
|
||||
word octantName(direction octant)
|
||||
{
|
||||
word str("-x-y-z");
|
||||
|
||||
if (octant & treeBoundBox::RIGHTHALF)
|
||||
{
|
||||
str[0] = '+';
|
||||
}
|
||||
if (octant & treeBoundBox::TOPHALF)
|
||||
{
|
||||
str[2] = '+';
|
||||
}
|
||||
if (octant & treeBoundBox::FRONTHALF)
|
||||
{
|
||||
str[4] = '+';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void testOverlaps(const treeBoundBox& bb, const treeBoundBox& searchBox)
|
||||
{
|
||||
FixedList<bool, 8> overlaps;
|
||||
|
||||
for (direction octant = 0; octant < 8; ++octant)
|
||||
{
|
||||
overlaps[octant] = bb.subOverlaps(octant, searchBox);
|
||||
}
|
||||
|
||||
Info<< "box " << bb << " and " << searchBox << nl;
|
||||
|
||||
Info<< "overlaps any:" << bb.overlaps(searchBox)
|
||||
<< " octants: " << overlaps << nl;
|
||||
}
|
||||
|
||||
|
||||
void testOverlaps
|
||||
(
|
||||
const treeBoundBox& bb,
|
||||
const point& sample,
|
||||
const scalar nearestDistSqr
|
||||
)
|
||||
{
|
||||
FixedList<bool, 8> overlaps;
|
||||
|
||||
for (direction octant = 0; octant < 8; ++octant)
|
||||
{
|
||||
overlaps[octant] = bb.subOverlaps(octant, sample, nearestDistSqr);
|
||||
}
|
||||
|
||||
Info<< "box " << bb << " and "
|
||||
<< sample << " distSqr:" << nearestDistSqr << nl;
|
||||
|
||||
Info<< "overlaps any:" << bb.overlaps(sample, nearestDistSqr)
|
||||
<< " octants: " << overlaps << nl;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#include "setRootCase.H"
|
||||
|
||||
treeBoundBox bb(cube(0, 1));
|
||||
treeBoundBox sub(cube(0.1, 0.8));
|
||||
|
||||
Info<< nl
|
||||
<< "box: " << bb << nl;
|
||||
|
||||
Info<< nl;
|
||||
for (direction octant = 0; octant < 8; ++octant)
|
||||
{
|
||||
Info<< "octant:" << octant
|
||||
<< " (" << octantName(octant) << ") = "
|
||||
<< bb.subBbox(octant) << nl;
|
||||
}
|
||||
|
||||
Info<< nl;
|
||||
for (direction facei = 0; facei < 6; ++facei)
|
||||
{
|
||||
Info<< "sub-half:" << facei
|
||||
<< " (" << faceName(facei) << ") = "
|
||||
<< bb.subHalf(facei) << nl;
|
||||
}
|
||||
|
||||
Info<< nl;
|
||||
for (direction octant = 0; octant < 8; ++octant)
|
||||
{
|
||||
const point pt = sub.corner(octant);
|
||||
const direction subOctant = bb.subOctant(pt);
|
||||
|
||||
Info<< "point:" << pt
|
||||
<< " in octant " << subOctant
|
||||
<< " sub-box: " << bb.subBbox(subOctant) << nl;
|
||||
}
|
||||
|
||||
for (const scalar dist : {0.1})
|
||||
{
|
||||
Info<< nl;
|
||||
for (direction octant = 0; octant < 8; ++octant)
|
||||
{
|
||||
treeBoundBox searchBox(cubeAt(bb.corner(octant), dist));
|
||||
testOverlaps(bb, searchBox);
|
||||
}
|
||||
|
||||
Info<< nl;
|
||||
for (direction facei = 0; facei < 6; ++facei)
|
||||
{
|
||||
treeBoundBox searchBox(cubeAt(bb.faceCentre(facei), dist));
|
||||
testOverlaps(bb, searchBox);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
treeBoundBox largerBox(bb);
|
||||
largerBox.grow(0.2);
|
||||
|
||||
// Checking at corners,
|
||||
// larger by 0.2 in three directions: radius = 0.3464
|
||||
|
||||
for (const scalar dist : {0.1, 0.35})
|
||||
{
|
||||
const scalar distSqr = sqr(dist);
|
||||
|
||||
Info<< nl;
|
||||
for (direction octant = 0; octant < 8; ++octant)
|
||||
{
|
||||
testOverlaps(bb, largerBox.corner(octant), distSqr);
|
||||
}
|
||||
}
|
||||
|
||||
// Checking at face centres,
|
||||
// larger by 0.2 in a single direction
|
||||
|
||||
for (const scalar dist : {0.1, 0.25})
|
||||
{
|
||||
const scalar distSqr = sqr(dist);
|
||||
|
||||
Info<< nl;
|
||||
for (direction facei = 0; facei < 6; ++facei)
|
||||
{
|
||||
testOverlaps(bb, largerBox.faceCentre(facei), distSqr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< nl << "End" << nl << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -38,105 +38,6 @@ Foam::scalar Foam::dynamicIndexedOctree<Type>::perturbTol_ = 10*SMALL;
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
bool Foam::dynamicIndexedOctree<Type>::overlaps
|
||||
(
|
||||
const point& p0,
|
||||
const point& p1,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
)
|
||||
{
|
||||
// Find out where sample is in relation to bb.
|
||||
// Find nearest point on bb.
|
||||
scalar distSqr = 0;
|
||||
|
||||
for (direction dir = 0; dir < vector::nComponents; dir++)
|
||||
{
|
||||
scalar d0 = p0[dir] - sample[dir];
|
||||
scalar d1 = p1[dir] - sample[dir];
|
||||
|
||||
if ((d0 > 0) != (d1 > 0))
|
||||
{
|
||||
// sample inside both extrema. This component does not add any
|
||||
// distance.
|
||||
}
|
||||
else if (mag(d0) < mag(d1))
|
||||
{
|
||||
distSqr += d0*d0;
|
||||
}
|
||||
else
|
||||
{
|
||||
distSqr += d1*d1;
|
||||
}
|
||||
|
||||
if (distSqr > nearestDistSqr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::dynamicIndexedOctree<Type>::overlaps
|
||||
(
|
||||
const treeBoundBox& parentBb,
|
||||
const direction octant,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
)
|
||||
{
|
||||
//- Accelerated version of
|
||||
// treeBoundBox subBb(parentBb.subBbox(mid, octant))
|
||||
// overlaps
|
||||
// (
|
||||
// subBb.min(),
|
||||
// subBb.max(),
|
||||
// nearestDistSqr,
|
||||
// sample
|
||||
// )
|
||||
|
||||
const point& min = parentBb.min();
|
||||
const point& max = parentBb.max();
|
||||
|
||||
point other;
|
||||
|
||||
if (octant & treeBoundBox::RIGHTHALF)
|
||||
{
|
||||
other.x() = max.x();
|
||||
}
|
||||
else
|
||||
{
|
||||
other.x() = min.x();
|
||||
}
|
||||
|
||||
if (octant & treeBoundBox::TOPHALF)
|
||||
{
|
||||
other.y() = max.y();
|
||||
}
|
||||
else
|
||||
{
|
||||
other.y() = min.y();
|
||||
}
|
||||
|
||||
if (octant & treeBoundBox::FRONTHALF)
|
||||
{
|
||||
other.z() = max.z();
|
||||
}
|
||||
else
|
||||
{
|
||||
other.z() = min.z();
|
||||
}
|
||||
|
||||
const point mid(0.5*(min+max));
|
||||
|
||||
return overlaps(mid, other, nearestDistSqr, sample);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::dynamicIndexedOctree<Type>::divide
|
||||
(
|
||||
@ -483,14 +384,10 @@ void Foam::dynamicIndexedOctree<Type>::findNearest
|
||||
const node& nod = nodes_[nodeI];
|
||||
|
||||
// Determine order to walk through octants
|
||||
FixedList<direction, 8> octantOrder;
|
||||
nod.bb_.searchOrder(sample, octantOrder);
|
||||
|
||||
// Go into all suboctants (one containing sample first) and update nearest.
|
||||
for (direction i = 0; i < 8; i++)
|
||||
{
|
||||
direction octant = octantOrder[i];
|
||||
|
||||
for (const direction octant : nod.bb_.searchOrder(sample))
|
||||
{
|
||||
labelBits index = nod.subNodes_[octant];
|
||||
|
||||
if (isNode(index))
|
||||
@ -499,7 +396,7 @@ void Foam::dynamicIndexedOctree<Type>::findNearest
|
||||
|
||||
const treeBoundBox& subBb = nodes_[subNodeI].bb_;
|
||||
|
||||
if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
|
||||
if (subBb.overlaps(sample, nearestDistSqr))
|
||||
{
|
||||
findNearest
|
||||
(
|
||||
@ -514,16 +411,7 @@ void Foam::dynamicIndexedOctree<Type>::findNearest
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
if
|
||||
(
|
||||
overlaps
|
||||
(
|
||||
nod.bb_,
|
||||
octant,
|
||||
nearestDistSqr,
|
||||
sample
|
||||
)
|
||||
)
|
||||
if (nod.bb_.subOverlaps(octant, sample, nearestDistSqr))
|
||||
{
|
||||
shapes_.findNearest
|
||||
(
|
||||
@ -556,14 +444,10 @@ void Foam::dynamicIndexedOctree<Type>::findNearest
|
||||
const treeBoundBox& nodeBb = nod.bb_;
|
||||
|
||||
// Determine order to walk through octants
|
||||
FixedList<direction, 8> octantOrder;
|
||||
nod.bb_.searchOrder(ln.centre(), octantOrder);
|
||||
|
||||
// Go into all suboctants (one containing sample first) and update nearest.
|
||||
for (direction i = 0; i < 8; i++)
|
||||
{
|
||||
direction octant = octantOrder[i];
|
||||
|
||||
for (const direction octant : nod.bb_.searchOrder(ln.centre()))
|
||||
{
|
||||
labelBits index = nod.subNodes_[octant];
|
||||
|
||||
if (isNode(index))
|
||||
@ -586,9 +470,7 @@ void Foam::dynamicIndexedOctree<Type>::findNearest
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
const treeBoundBox subBb(nodeBb.subBbox(octant));
|
||||
|
||||
if (subBb.overlaps(tightest))
|
||||
if (nodeBb.subOverlaps(octant, tightest))
|
||||
{
|
||||
shapes_.findNearest
|
||||
(
|
||||
@ -1791,9 +1673,7 @@ void Foam::dynamicIndexedOctree<Type>::findBox
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
const treeBoundBox subBb(nodeBb.subBbox(octant));
|
||||
|
||||
if (subBb.overlaps(searchBox))
|
||||
if (nodeBb.subOverlaps(octant, searchBox))
|
||||
{
|
||||
const labelList& indices = *(contents_[getContent(index)]);
|
||||
|
||||
@ -1839,9 +1719,7 @@ void Foam::dynamicIndexedOctree<Type>::findSphere
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
const treeBoundBox subBb(nodeBb.subBbox(octant));
|
||||
|
||||
if (subBb.overlaps(centre, radiusSqr))
|
||||
if (nodeBb.subOverlaps(octant, centre, radiusSqr))
|
||||
{
|
||||
const labelList& indices = *(contents_[getContent(index)]);
|
||||
|
||||
|
@ -127,18 +127,8 @@ class dynamicIndexedOctree
|
||||
//- Per node per octant whether is fully inside/outside/mixed.
|
||||
mutable PackedList<2> nodeTypes_;
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Helper: does bb intersect a sphere around sample? Or is any
|
||||
// corner point of bb closer than nearestDistSqr to sample.
|
||||
// (bb is implicitly provided as parent bb + octant)
|
||||
static bool overlaps
|
||||
(
|
||||
const treeBoundBox& parentBb,
|
||||
const direction octant,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
);
|
||||
// Private Member Functions
|
||||
|
||||
// Construction
|
||||
|
||||
@ -492,16 +482,6 @@ public:
|
||||
const vector& vec
|
||||
);
|
||||
|
||||
//- Helper: does bb intersect a sphere around sample? Or is any
|
||||
// corner point of bb closer than nearestDistSqr to sample.
|
||||
static bool overlaps
|
||||
(
|
||||
const point& bbMin,
|
||||
const point& bbMax,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
);
|
||||
|
||||
//- Find near pairs and apply CompareOp to them.
|
||||
// tree2 can be *this or different tree.
|
||||
template<class CompareOp>
|
||||
|
@ -40,78 +40,6 @@ Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL;
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
bool Foam::indexedOctree<Type>::overlaps
|
||||
(
|
||||
const point& p0,
|
||||
const point& p1,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
)
|
||||
{
|
||||
boundBox bb(p0, p1);
|
||||
|
||||
return bb.overlaps(sample, nearestDistSqr);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::indexedOctree<Type>::overlaps
|
||||
(
|
||||
const treeBoundBox& parentBb,
|
||||
const direction octant,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
)
|
||||
{
|
||||
//- Accelerated version of
|
||||
// treeBoundBox subBb(parentBb.subBbox(mid, octant))
|
||||
// overlaps
|
||||
// (
|
||||
// subBb.min(),
|
||||
// subBb.max(),
|
||||
// nearestDistSqr,
|
||||
// sample
|
||||
// )
|
||||
|
||||
const point& min = parentBb.min();
|
||||
const point& max = parentBb.max();
|
||||
|
||||
point other;
|
||||
|
||||
if (octant & treeBoundBox::RIGHTHALF)
|
||||
{
|
||||
other.x() = max.x();
|
||||
}
|
||||
else
|
||||
{
|
||||
other.x() = min.x();
|
||||
}
|
||||
|
||||
if (octant & treeBoundBox::TOPHALF)
|
||||
{
|
||||
other.y() = max.y();
|
||||
}
|
||||
else
|
||||
{
|
||||
other.y() = min.y();
|
||||
}
|
||||
|
||||
if (octant & treeBoundBox::FRONTHALF)
|
||||
{
|
||||
other.z() = max.z();
|
||||
}
|
||||
else
|
||||
{
|
||||
other.z() = min.z();
|
||||
}
|
||||
|
||||
const point mid(0.5*(min+max));
|
||||
|
||||
return overlaps(mid, other, nearestDistSqr, sample);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::indexedOctree<Type>::divide
|
||||
(
|
||||
@ -498,14 +426,10 @@ void Foam::indexedOctree<Type>::findNearest
|
||||
const node& nod = nodes_[nodeI];
|
||||
|
||||
// Determine order to walk through octants
|
||||
FixedList<direction, 8> octantOrder;
|
||||
nod.bb_.searchOrder(sample, octantOrder);
|
||||
|
||||
// Go into all suboctants (one containing sample first) and update nearest.
|
||||
for (direction i = 0; i < 8; i++)
|
||||
{
|
||||
direction octant = octantOrder[i];
|
||||
|
||||
for (const direction octant : nod.bb_.searchOrder(sample))
|
||||
{
|
||||
labelBits index = nod.subNodes_[octant];
|
||||
|
||||
if (isNode(index))
|
||||
@ -514,7 +438,7 @@ void Foam::indexedOctree<Type>::findNearest
|
||||
|
||||
const treeBoundBox& subBb = nodes_[subNodeI].bb_;
|
||||
|
||||
if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
|
||||
if (subBb.overlaps(sample, nearestDistSqr))
|
||||
{
|
||||
findNearest
|
||||
(
|
||||
@ -531,16 +455,7 @@ void Foam::indexedOctree<Type>::findNearest
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
if
|
||||
(
|
||||
overlaps
|
||||
(
|
||||
nod.bb_,
|
||||
octant,
|
||||
nearestDistSqr,
|
||||
sample
|
||||
)
|
||||
)
|
||||
if (nod.bb_.subOverlaps(octant, sample, nearestDistSqr))
|
||||
{
|
||||
fnOp
|
||||
(
|
||||
@ -576,14 +491,10 @@ void Foam::indexedOctree<Type>::findNearest
|
||||
const treeBoundBox& nodeBb = nod.bb_;
|
||||
|
||||
// Determine order to walk through octants
|
||||
FixedList<direction, 8> octantOrder;
|
||||
nod.bb_.searchOrder(ln.centre(), octantOrder);
|
||||
|
||||
// Go into all suboctants (one containing sample first) and update nearest.
|
||||
for (direction i = 0; i < 8; i++)
|
||||
{
|
||||
direction octant = octantOrder[i];
|
||||
|
||||
for (const direction octant : nod.bb_.searchOrder(ln.centre()))
|
||||
{
|
||||
labelBits index = nod.subNodes_[octant];
|
||||
|
||||
if (isNode(index))
|
||||
@ -608,9 +519,7 @@ void Foam::indexedOctree<Type>::findNearest
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
const treeBoundBox subBb(nodeBb.subBbox(octant));
|
||||
|
||||
if (subBb.overlaps(tightest))
|
||||
if (nodeBb.subOverlaps(octant, tightest))
|
||||
{
|
||||
fnOp
|
||||
(
|
||||
@ -1819,9 +1728,7 @@ void Foam::indexedOctree<Type>::findBox
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
const treeBoundBox subBb(nodeBb.subBbox(octant));
|
||||
|
||||
if (subBb.overlaps(searchBox))
|
||||
if (nodeBb.subOverlaps(octant, searchBox))
|
||||
{
|
||||
const labelList& indices = contents_[getContent(index)];
|
||||
|
||||
@ -1867,9 +1774,7 @@ void Foam::indexedOctree<Type>::findSphere
|
||||
}
|
||||
else if (isContent(index))
|
||||
{
|
||||
const treeBoundBox subBb(nodeBb.subBbox(octant));
|
||||
|
||||
if (subBb.overlaps(centre, radiusSqr))
|
||||
if (nodeBb.subOverlaps(octant, centre, radiusSqr))
|
||||
{
|
||||
const labelList& indices = contents_[getContent(index)];
|
||||
|
||||
|
@ -262,17 +262,6 @@ class indexedOctree
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Helper: does bb intersect a sphere around sample? Or is any
|
||||
// corner point of bb closer than nearestDistSqr to sample.
|
||||
// (bb is implicitly provided as parent bb + octant)
|
||||
static bool overlaps
|
||||
(
|
||||
const treeBoundBox& parentBb,
|
||||
const direction octant,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
);
|
||||
|
||||
// Construction
|
||||
|
||||
//- Split list of indices into 8 bins
|
||||
@ -701,16 +690,6 @@ public:
|
||||
const vector& vec
|
||||
);
|
||||
|
||||
//- Helper: does bb intersect a sphere around sample? Or is any
|
||||
// corner point of bb closer than nearestDistSqr to sample.
|
||||
static bool overlaps
|
||||
(
|
||||
const point& bbMin,
|
||||
const point& bbMax,
|
||||
const scalar nearestDistSqr,
|
||||
const point& sample
|
||||
);
|
||||
|
||||
//- Find near pairs and apply CompareOp to them.
|
||||
// tree2 can be *this or different tree.
|
||||
template<class CompareOp>
|
||||
|
@ -73,6 +73,31 @@ class boundBox
|
||||
//- Minimum and maximum points describing the bounding box
|
||||
point min_, max_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Test for overlap of box and box (inclusive check)
|
||||
inline static bool box_box_overlaps
|
||||
(
|
||||
const point& minA, // boxA (min)
|
||||
const point& maxA, // boxA (max)
|
||||
const point& minB, // boxB (min)
|
||||
const point& maxB // boxB (max)
|
||||
);
|
||||
|
||||
//- Test for overlap of box and boundingSphere (centre + sqr(radius))
|
||||
// Note: ordering of corners is irrelevant
|
||||
inline static bool box_sphere_overlaps
|
||||
(
|
||||
const point& corner0, // box corner
|
||||
const point& corner1, // box corner
|
||||
const point& centre, // sphere centre
|
||||
const scalar radiusSqr // sqr(radius)
|
||||
);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Static Data Members
|
||||
|
@ -377,53 +377,71 @@ inline void Foam::boundBox::inflate(const scalar factor)
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::boundBox::overlaps(const boundBox& bb) const
|
||||
inline bool Foam::boundBox::box_box_overlaps
|
||||
(
|
||||
const point& minA, const point& maxA, // boxA
|
||||
const point& minB, const point& maxB // boxB
|
||||
)
|
||||
{
|
||||
return
|
||||
(
|
||||
min_.x() <= bb.max_.x() && bb.min_.x() <= max_.x()
|
||||
&& min_.y() <= bb.max_.y() && bb.min_.y() <= max_.y()
|
||||
&& min_.z() <= bb.max_.z() && bb.min_.z() <= max_.z()
|
||||
minA.x() <= maxB.x() && minB.x() <= maxA.x()
|
||||
&& minA.y() <= maxB.y() && minB.y() <= maxA.y()
|
||||
&& minA.z() <= maxB.z() && minB.z() <= maxA.z()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::boundBox::box_sphere_overlaps
|
||||
(
|
||||
const point& corner0,
|
||||
const point& corner1,
|
||||
const point& centre,
|
||||
const scalar radiusSqr
|
||||
)
|
||||
{
|
||||
// Find out where centre is in relation to bb.
|
||||
// Find nearest point on bb.
|
||||
scalar distSqr = 0;
|
||||
|
||||
for (direction dir = 0; dir < vector::nComponents; ++dir)
|
||||
{
|
||||
const scalar d0 = corner0[dir] - centre[dir];
|
||||
const scalar d1 = corner1[dir] - centre[dir];
|
||||
|
||||
if ((d0 > 0) != (d1 > 0))
|
||||
{
|
||||
// centre inside both extrema. This component does not add any
|
||||
// distance.
|
||||
}
|
||||
else
|
||||
{
|
||||
distSqr += ::Foam::min(Foam::magSqr(d0), Foam::magSqr(d1));
|
||||
|
||||
if (distSqr > radiusSqr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::boundBox::overlaps(const boundBox& bb) const
|
||||
{
|
||||
return box_box_overlaps(min_, max_, bb.min(), bb.max());
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::boundBox::overlaps
|
||||
(
|
||||
const point& centre,
|
||||
const scalar radiusSqr
|
||||
) const
|
||||
{
|
||||
// Find out where centre is in relation to bb.
|
||||
// Find nearest point on bb.
|
||||
scalar distSqr = 0;
|
||||
|
||||
for (direction dir = 0; dir < vector::nComponents; ++dir)
|
||||
{
|
||||
const scalar d0 = min_[dir] - centre[dir];
|
||||
const scalar d1 = max_[dir] - centre[dir];
|
||||
|
||||
if ((d0 > 0) != (d1 > 0))
|
||||
{
|
||||
// centre inside both extrema. This component does not add any
|
||||
// distance.
|
||||
}
|
||||
else if (Foam::mag(d0) < Foam::mag(d1))
|
||||
{
|
||||
distSqr += d0*d0;
|
||||
}
|
||||
else
|
||||
{
|
||||
distSqr += d1*d1;
|
||||
}
|
||||
|
||||
if (distSqr > radiusSqr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return box_sphere_overlaps(min_, max_, centre, radiusSqr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,12 +105,6 @@ Foam::tmp<Foam::pointField> Foam::treeBoundBox::points() const
|
||||
}
|
||||
|
||||
|
||||
Foam::treeBoundBox Foam::treeBoundBox::subBbox(const direction octant) const
|
||||
{
|
||||
return subBbox(centre(), octant);
|
||||
}
|
||||
|
||||
|
||||
Foam::treeBoundBox Foam::treeBoundBox::subBbox
|
||||
(
|
||||
const point& mid,
|
||||
@ -124,39 +118,143 @@ Foam::treeBoundBox Foam::treeBoundBox::subBbox
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
// start with a copy of this bounding box and adjust limits accordingly
|
||||
treeBoundBox subBb(*this);
|
||||
point& bbMin = subBb.min();
|
||||
point& bbMax = subBb.max();
|
||||
// Start the box with a single point (the mid-point) and push out the
|
||||
// min/max dimensions according to the octant.
|
||||
|
||||
treeBoundBox bb(mid);
|
||||
|
||||
if (octant & treeBoundBox::RIGHTHALF)
|
||||
{
|
||||
bbMin.x() = mid.x(); // mid -> max
|
||||
bb.max().x() = max().x();
|
||||
}
|
||||
else
|
||||
{
|
||||
bbMax.x() = mid.x(); // min -> mid
|
||||
bb.min().x() = min().x();
|
||||
}
|
||||
|
||||
if (octant & treeBoundBox::TOPHALF)
|
||||
{
|
||||
bbMin.y() = mid.y(); // mid -> max
|
||||
bb.max().y() = max().y();
|
||||
}
|
||||
else
|
||||
{
|
||||
bbMax.y() = mid.y(); // min -> mid
|
||||
bb.min().y() = min().y();
|
||||
}
|
||||
|
||||
if (octant & treeBoundBox::FRONTHALF)
|
||||
{
|
||||
bbMin.z() = mid.z(); // mid -> max
|
||||
bb.max().z() = max().z();
|
||||
}
|
||||
else
|
||||
{
|
||||
bbMax.z() = mid.z(); // min -> mid
|
||||
bb.min().z() = min().z();
|
||||
}
|
||||
|
||||
return subBb;
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
Foam::treeBoundBox Foam::treeBoundBox::subHalf
|
||||
(
|
||||
const scalar mid,
|
||||
const direction whichFace
|
||||
) const
|
||||
{
|
||||
// Start with a copy of this bounding box and adjust limits accordingly
|
||||
// - corresponds to a clipping plane
|
||||
|
||||
treeBoundBox bb(*this);
|
||||
|
||||
switch (whichFace)
|
||||
{
|
||||
case LEFT : bb.max().x() = mid; break;
|
||||
case RIGHT : bb.min().x() = mid; break;
|
||||
|
||||
case BOTTOM : bb.max().y() = mid; break;
|
||||
case TOP : bb.min().y() = mid; break;
|
||||
|
||||
case BACK : bb.max().z() = mid; break;
|
||||
case FRONT : bb.min().z() = mid; break;
|
||||
|
||||
default:
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "face:" << int(whichFace) << " should be [0..5]"
|
||||
<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
Foam::treeBoundBox Foam::treeBoundBox::subHalf
|
||||
(
|
||||
const direction whichFace
|
||||
) const
|
||||
{
|
||||
direction cmpt =
|
||||
(
|
||||
(whichFace == faceId::LEFT || whichFace == faceId::RIGHT)
|
||||
? vector::X
|
||||
: (whichFace == faceId::BOTTOM || whichFace == faceId::TOP)
|
||||
? vector::Y
|
||||
: vector::Z
|
||||
);
|
||||
|
||||
scalar mid = 0.5*(min()[cmpt] + max()[cmpt]);
|
||||
|
||||
return subHalf(mid, whichFace);
|
||||
}
|
||||
|
||||
|
||||
Foam::treeBoundBox Foam::treeBoundBox::subBbox(const direction octant) const
|
||||
{
|
||||
return subBbox(centre(), octant);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::treeBoundBox::subOverlaps
|
||||
(
|
||||
const direction octant,
|
||||
const boundBox& bb
|
||||
) const
|
||||
{
|
||||
// Slightly accelerated version of
|
||||
// subBbox(octant).overlaps(bb)
|
||||
|
||||
point subMin = centre();
|
||||
point subMax = subMin;
|
||||
|
||||
if (octant & RIGHTHALF)
|
||||
{
|
||||
subMax.x() = max().x();
|
||||
}
|
||||
else
|
||||
{
|
||||
subMin.x() = min().x();
|
||||
}
|
||||
|
||||
if (octant & TOPHALF)
|
||||
{
|
||||
subMax.y() = max().y();
|
||||
}
|
||||
else
|
||||
{
|
||||
subMin.y() = min().y();
|
||||
}
|
||||
|
||||
if (octant & FRONTHALF)
|
||||
{
|
||||
subMax.z() = max().z();
|
||||
}
|
||||
else
|
||||
{
|
||||
subMin.z() = min().z();
|
||||
}
|
||||
|
||||
// NB: ordering of corners *is* irrelevant
|
||||
return box_box_overlaps(subMin, subMax, bb.min(), bb.max());
|
||||
}
|
||||
|
||||
|
||||
|
@ -254,6 +254,17 @@ public:
|
||||
//- Sub-box given by octant number. Midpoint provided.
|
||||
treeBoundBox subBbox(const point& mid, const direction) const;
|
||||
|
||||
//- Sub-box half for given face
|
||||
treeBoundBox subHalf(const direction whichFace) const;
|
||||
|
||||
//- Sub-box half for given face with prescribed mid point value.
|
||||
//- Eg, subHalf(scalar, LEFT)
|
||||
treeBoundBox subHalf
|
||||
(
|
||||
const scalar mid,
|
||||
const direction whichFace
|
||||
) const;
|
||||
|
||||
//- Returns octant number given point and the calculated midpoint.
|
||||
inline direction subOctant
|
||||
(
|
||||
@ -315,6 +326,21 @@ public:
|
||||
//- Overlaps with other bounding box, sphere etc?
|
||||
using boundBox::overlaps;
|
||||
|
||||
//- Does sub-octant overlap/touch boundingBox?
|
||||
bool subOverlaps
|
||||
(
|
||||
const direction octant,
|
||||
const boundBox& bb
|
||||
) const;
|
||||
|
||||
//- Does sub-octant overlap boundingSphere (centre + sqr(radius))?
|
||||
inline bool subOverlaps
|
||||
(
|
||||
const direction octant,
|
||||
const point& centre,
|
||||
const scalar radiusSqr
|
||||
) const;
|
||||
|
||||
//- intersects other bounding box, sphere etc?
|
||||
using boundBox::intersects;
|
||||
|
||||
|
@ -316,6 +316,27 @@ Foam::treeBoundBox::searchOrder(const point& pt) const
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::treeBoundBox::subOverlaps
|
||||
(
|
||||
const direction octant,
|
||||
const point& centre,
|
||||
const scalar radiusSqr
|
||||
) const
|
||||
{
|
||||
// Accelerated version of
|
||||
// subBbox(octant).overlaps(centre, radiusSqr)
|
||||
|
||||
// NB: ordering of corners is irrelevant
|
||||
return box_sphere_overlaps
|
||||
(
|
||||
this->centre(),
|
||||
corner(octant),
|
||||
centre,
|
||||
radiusSqr
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::treeBoundBox::intersects
|
||||
(
|
||||
const linePointRef& ln,
|
||||
|
Loading…
Reference in New Issue
Block a user