Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
Henry Weller
committed
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2017-2019 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/>.
\*---------------------------------------------------------------------------*/
#include "treeBoundBox.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
face({0, 4, 6, 2}), // 0: x-min, left
face({1, 3, 7, 5}), // 1: x-max, right
face({0, 1, 5, 4}), // 2: y-min, bottom
face({2, 6, 7, 3}), // 3: y-max, top
face({0, 2, 3, 1}), // 4: z-min, back
face({4, 5, 7, 6}) // 5: z-max, front
const Foam::edgeList Foam::treeBoundBox::edges
({
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::treeBoundBox::treeBoundBox(const UList<point>& points)
boundBox(points, false)
if (points.empty())
<< "No bounding box for zero-sized pointField" << nl;
const labelUList& indices
boundBox(points, indices, false)
if (points.empty() || indices.empty())
<< "No bounding box for zero-sized pointField" << nl;
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::tmp<Foam::pointField> Foam::treeBoundBox::points() const
auto tpts = tmp<pointField>::New(8);
auto& pts = tpts.ref();
forAll(pts, octant)
pts[octant] = corner(octant);
Foam::treeBoundBox Foam::treeBoundBox::subBbox(const direction octant) const
return subBbox(centre(), octant);
Foam::treeBoundBox Foam::treeBoundBox::subBbox
(
const point& mid,
const direction octant
) const
{
if (octant > 7)
{
FatalErrorInFunction
<< "octant should be [0..7]"
<< 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();
if (octant & treeBoundBox::RIGHTHALF)
{
if (octant & treeBoundBox::TOPHALF)
{
if (octant & treeBoundBox::FRONTHALF)
{
}
return subBb;
}
const point& overallStart,
const vector& overallVec,
const point& start,
const point& end,
point& pt,
direction& ptOnFaces
// Sutherlands algorithm:
// loop
// - start = intersection of line with one of the planes bounding
// the bounding box
// - stop if start inside bb (return true)
// - stop if start and end in same 'half' (e.g. both above bb)
// (return false)
//
// Uses posBits to efficiently determine 'half' in which start and end
// point are.
//
// Note:
// - sets coordinate to exact position: e.g. pt.x() = min().x()
// since plane intersect routine might have truncation error.
// This makes sure that posBits tests 'inside'
const direction endBits = posBits(end);
// Allow maximum of 3 clips.
for (label i = 0; i < 4; ++i)
{
direction ptBits = posBits(pt);
if (ptBits == 0)
{
// pt inside bb
ptOnFaces = faceBits(pt);
return true;
}
if ((ptBits & endBits) != 0)
{
// pt and end in same block outside of bb
ptOnFaces = faceBits(pt);
return false;
}
if (ptBits & LEFTBIT)
{
// Intersect with plane V=min, n=-1,0,0
if (Foam::mag(overallVec.x()) > VSMALL)
{
scalar s = (min().x() - overallStart.x())/overallVec.x();
pt.x() = min().x();
pt.y() = overallStart.y() + overallVec.y()*s;
pt.z() = overallStart.z() + overallVec.z()*s;
}
else
// Vector not in x-direction. But still intersecting bb planes.
// So must be close - just snap to bb.
pt.x() = min().x();
}
}
else if (ptBits & RIGHTBIT)
{
// Intersect with plane V=max, n=1,0,0
if (Foam::mag(overallVec.x()) > VSMALL)
{
scalar s = (max().x() - overallStart.x())/overallVec.x();
pt.x() = max().x();
pt.y() = overallStart.y() + overallVec.y()*s;
pt.z() = overallStart.z() + overallVec.z()*s;
}
else
{
pt.x() = max().x();
}
}
else if (ptBits & BOTTOMBIT)
{
// Intersect with plane V=min, n=0,-1,0
if (Foam::mag(overallVec.y()) > VSMALL)
scalar s = (min().y() - overallStart.y())/overallVec.y();
pt.x() = overallStart.x() + overallVec.x()*s;
pt.z() = overallStart.z() + overallVec.z()*s;
}
else
{
pt.x() = min().y();
else if (ptBits & TOPBIT)
{
// Intersect with plane V=max, n=0,1,0
if (Foam::mag(overallVec.y()) > VSMALL)
{
scalar s = (max().y() - overallStart.y())/overallVec.y();
pt.x() = overallStart.x() + overallVec.x()*s;
pt.y() = max().y();
pt.z() = overallStart.z() + overallVec.z()*s;
}
else
{
pt.y() = max().y();
}
}
else if (ptBits & BACKBIT)
{
// Intersect with plane V=min, n=0,0,-1
if (Foam::mag(overallVec.z()) > VSMALL)
{
scalar s = (min().z() - overallStart.z())/overallVec.z();
pt.x() = overallStart.x() + overallVec.x()*s;
pt.y() = overallStart.y() + overallVec.y()*s;
pt.z() = min().z();
}
else
{
pt.z() = min().z();
}
}
else if (ptBits & FRONTBIT)
{
// Intersect with plane V=max, n=0,0,1
if (Foam::mag(overallVec.z()) > VSMALL)
{
scalar s = (max().z() - overallStart.z())/overallVec.z();
pt.x() = overallStart.x() + overallVec.x()*s;
pt.y() = overallStart.y() + overallVec.y()*s;
pt.z() = max().z();
}
else
{
pt.z() = max().z();
}
}
}
// Can end up here if the end point is on the edge of the boundBox
return true;
bool Foam::treeBoundBox::intersects
(
const point& start,
const point& end,
point& pt
) const
{
direction ptBits;
return intersects(start, end-start, start, end, pt, ptBits);
}
bool Foam::treeBoundBox::contains(const vector& dir, const point& pt) const
{
// Compare all components against min and max of bb
for (direction cmpt=0; cmpt<3; ++cmpt)
{
return false;
}
{
// On edge. Outside if direction points outwards.
if (dir[cmpt] < 0)
{
return false;
}
}
{
return false;
}
{
// On edge. Outside if direction points outwards.
if (dir[cmpt] > 0)
{
return false;
}
}
}
// All components inside bb
return true;
}
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
Foam::direction Foam::treeBoundBox::faceBits(const point& pt) const
{
direction faceBits = 0;
if (pt.x() == min().x())
{
faceBits |= LEFTBIT;
}
else if (pt.x() == max().x())
{
faceBits |= RIGHTBIT;
}
if (pt.y() == min().y())
{
faceBits |= BOTTOMBIT;
}
else if (pt.y() == max().y())
{
faceBits |= TOPBIT;
}
if (pt.z() == min().z())
{
faceBits |= BACKBIT;
}
else if (pt.z() == max().z())
{
faceBits |= FRONTBIT;
}
return faceBits;
}
Foam::direction Foam::treeBoundBox::posBits(const point& pt) const
{
direction posBits = 0;
if (pt.x() < min().x())
{
posBits |= LEFTBIT;
}
else if (pt.x() > max().x())
{
posBits |= RIGHTBIT;
}
if (pt.y() < min().y())
{
else if (pt.y() > max().y())
}
if (pt.z() < min().z())
{
else if (pt.z() > max().z())
}
return posBits;
}
point& nearest,
point& furthest
) const
{
scalar nearX, nearY, nearZ;
scalar farX, farY, farZ;
if (Foam::mag(min().x() - pt.x()) < Foam::mag(max().x() - pt.x()))
{
nearX = min().x();
farX = max().x();
}
else
{
nearX = max().x();
farX = min().x();
}
if (Foam::mag(min().y() - pt.y()) < Foam::mag(max().y() - pt.y()))
{
nearY = min().y();
farY = max().y();
}
else
{
nearY = max().y();
farY = min().y();
}
if (Foam::mag(min().z() - pt.z()) < Foam::mag(max().z() - pt.z()))
{
nearZ = min().z();
farZ = max().z();
}
else
{
nearZ = max().z();
farZ = min().z();
}
nearest = point(nearX, nearY, nearZ);
furthest = point(farX, farY, farZ);
}
Foam::scalar Foam::treeBoundBox::maxDist(const point& pt) const
const treeBoundBox& other
) const
{
//
// Distance point <-> nearest and furthest away vertex of this
//
point nearThis, farThis;
// get nearest and furthest away vertex
sqr(nearThis.x() - pt.x())
+ sqr(nearThis.y() - pt.y())
+ sqr(nearThis.z() - pt.z());
sqr(farThis.x() - pt.x())
+ sqr(farThis.y() - pt.y())
+ sqr(farThis.z() - pt.z());
//
point nearOther, farOther;
// get nearest and furthest away vertex
sqr(nearOther.x() - pt.x())
+ sqr(nearOther.y() - pt.y())
+ sqr(nearOther.z() - pt.z());
sqr(farOther.x() - pt.x())
+ sqr(farOther.y() - pt.y())
+ sqr(farOther.z() - pt.z());
//
// Categorize
//
if (maxDistThis < minDistOther)
{
// All vertices of this are nearer to point than any vertex of other
return -1;
}
else if (minDistThis > maxDistOther)
{
// All vertices of this are further from point than any vertex of other
return 1;
}
else
{
// Mixed bag
return 0;
}
}
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const treeBoundBox& bb)
{
return os << static_cast<const boundBox&>(bb);
}
Foam::Istream& Foam::operator>>(Istream& is, treeBoundBox& bb)
}
// ************************************************************************* //