mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
484 lines
12 KiB
C
484 lines
12 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
|
|
\\/ M anipulation |
|
|
-------------------------------------------------------------------------------
|
|
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 "treeDataTriSurface.H"
|
|
#include "triSurfaceTools.H"
|
|
#include "triangleFuncs.H"
|
|
#include "indexedOctree.H"
|
|
|
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
|
|
defineTypeNameAndDebug(Foam::treeDataTriSurface, 0);
|
|
|
|
|
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
|
|
// Fast distance to triangle calculation. From
|
|
// "Distance Between Point and Trangle in 3D"
|
|
// David Eberly, Magic Software Inc. Aug. 2003.
|
|
// Works on function Q giving distance to point and tries to minimize this.
|
|
Foam::scalar Foam::treeDataTriSurface::nearestCoords
|
|
(
|
|
const point& base,
|
|
const point& E0,
|
|
const point& E1,
|
|
const scalar a,
|
|
const scalar b,
|
|
const scalar c,
|
|
const point& P,
|
|
scalar& s,
|
|
scalar& t
|
|
)
|
|
{
|
|
// distance vector
|
|
const vector D(base - P);
|
|
|
|
// Precalculate distance factors.
|
|
const scalar d = E0 & D;
|
|
const scalar e = E1 & D;
|
|
|
|
// Do classification
|
|
const scalar det = a*c - b*b;
|
|
|
|
s = b*e - c*d;
|
|
t = b*d - a*e;
|
|
|
|
if (s+t < det)
|
|
{
|
|
if (s < 0)
|
|
{
|
|
if (t < 0)
|
|
{
|
|
//region 4
|
|
if (e > 0)
|
|
{
|
|
//min on edge t = 0
|
|
t = 0;
|
|
s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
|
|
}
|
|
else
|
|
{
|
|
//min on edge s=0
|
|
s = 0;
|
|
t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//region 3. Min on edge s = 0
|
|
s = 0;
|
|
t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
|
|
}
|
|
}
|
|
else if (t < 0)
|
|
{
|
|
//region 5
|
|
t = 0;
|
|
s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
|
|
}
|
|
else
|
|
{
|
|
//region 0
|
|
const scalar invDet = 1/det;
|
|
s *= invDet;
|
|
t *= invDet;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (s < 0)
|
|
{
|
|
//region 2
|
|
const scalar tmp0 = b + d;
|
|
const scalar tmp1 = c + e;
|
|
if (tmp1 > tmp0)
|
|
{
|
|
//min on edge s+t=1
|
|
const scalar numer = tmp1 - tmp0;
|
|
const scalar denom = a-2*b+c;
|
|
s = (numer >= denom ? 1 : numer/denom);
|
|
t = 1 - s;
|
|
}
|
|
else
|
|
{
|
|
//min on edge s=0
|
|
s = 0;
|
|
t = (tmp1 <= 0 ? 1 : (e >= 0 ? 0 : - e/c));
|
|
}
|
|
}
|
|
else if (t < 0)
|
|
{
|
|
//region 6
|
|
const scalar tmp0 = b + d;
|
|
const scalar tmp1 = c + e;
|
|
if (tmp1 > tmp0)
|
|
{
|
|
//min on edge s+t=1
|
|
const scalar numer = tmp1 - tmp0;
|
|
const scalar denom = a-2*b+c;
|
|
s = (numer >= denom ? 1 : numer/denom);
|
|
t = 1 - s;
|
|
}
|
|
else
|
|
{
|
|
//min on edge t=0
|
|
t = 0;
|
|
s = (tmp1 <= 0 ? 1 : (d >= 0 ? 0 : - d/a));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//region 1
|
|
const scalar numer = c+e-(b+d);
|
|
if (numer <= 0)
|
|
{
|
|
s = 0;
|
|
}
|
|
else
|
|
{
|
|
const scalar denom = a-2*b+c;
|
|
s = (numer >= denom ? 1 : numer/denom);
|
|
}
|
|
}
|
|
t = 1 - s;
|
|
}
|
|
|
|
|
|
// Calculate distance.
|
|
// Note: abs should not be needed but truncation error causes problems
|
|
// with points very close to one of the triangle vertices.
|
|
// (seen up to -9e-15). Alternatively add some small value.
|
|
|
|
const scalar f = D & D;
|
|
return Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f);
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
|
|
// Construct from components
|
|
Foam::treeDataTriSurface::treeDataTriSurface(const triSurface& surface)
|
|
:
|
|
surface_(surface)
|
|
{}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
Foam::pointField Foam::treeDataTriSurface::points() const
|
|
{
|
|
const pointField& points = surface_.points();
|
|
|
|
pointField centres(surface_.size());
|
|
|
|
forAll(surface_, triI)
|
|
{
|
|
centres[triI] = surface_[triI].centre(points);
|
|
}
|
|
return centres;
|
|
}
|
|
|
|
|
|
//- Get type of sample (inside/outside/mixed) w.r.t. surface.
|
|
Foam::label Foam::treeDataTriSurface::getVolumeType
|
|
(
|
|
const indexedOctree<treeDataTriSurface>& tree,
|
|
const point& sample
|
|
) const
|
|
{
|
|
// Find nearest point
|
|
const treeBoundBox& treeBb = tree.bb();
|
|
|
|
pointIndexHit pHit = tree.findNearest
|
|
(
|
|
sample,
|
|
max
|
|
(
|
|
Foam::sqr(GREAT),
|
|
Foam::magSqr(treeBb.span())
|
|
)
|
|
);
|
|
|
|
if (!pHit.hit())
|
|
{
|
|
FatalErrorIn("treeDataTriSurface::getVolumeType(..)")
|
|
<< "treeBb:" << treeBb
|
|
<< " sample:" << sample
|
|
<< " pHit:" << pHit
|
|
<< abort(FatalError);
|
|
}
|
|
|
|
triSurfaceTools::sideType t = triSurfaceTools::surfaceSide
|
|
(
|
|
surface_,
|
|
sample,
|
|
pHit.index(),
|
|
pHit.hitPoint(),
|
|
indexedOctree<treeDataTriSurface>::perturbTol()
|
|
);
|
|
|
|
if (t == triSurfaceTools::UNKNOWN)
|
|
{
|
|
return indexedOctree<treeDataTriSurface>::UNKNOWN;
|
|
}
|
|
else if (t == triSurfaceTools::INSIDE)
|
|
{
|
|
return indexedOctree<treeDataTriSurface>::INSIDE;
|
|
}
|
|
else if (t == triSurfaceTools::OUTSIDE)
|
|
{
|
|
return indexedOctree<treeDataTriSurface>::OUTSIDE;
|
|
}
|
|
else
|
|
{
|
|
FatalErrorIn("treeDataTriSurface::getVolumeType(..)")
|
|
<< "problem" << abort(FatalError);
|
|
return indexedOctree<treeDataTriSurface>::UNKNOWN;
|
|
}
|
|
}
|
|
|
|
|
|
// Check if any point on triangle is inside cubeBb.
|
|
bool Foam::treeDataTriSurface::overlaps
|
|
(
|
|
const label index,
|
|
const treeBoundBox& cubeBb
|
|
) const
|
|
{
|
|
const pointField& points = surface_.points();
|
|
const labelledTri& f = surface_[index];
|
|
|
|
// Triangle points
|
|
const point& p0 = points[f[0]];
|
|
const point& p1 = points[f[1]];
|
|
const point& p2 = points[f[2]];
|
|
|
|
treeBoundBox triBb(p0, p0);
|
|
triBb.min() = min(triBb.min(), p1);
|
|
triBb.min() = min(triBb.min(), p2);
|
|
|
|
triBb.max() = max(triBb.max(), p1);
|
|
triBb.max() = max(triBb.max(), p2);
|
|
|
|
//- For testing: robust one
|
|
//return cubeBb.overlaps(triBb);
|
|
|
|
//- Exact test of triangle intersecting bb
|
|
|
|
// Quick rejection. If whole bounding box of tri is outside cubeBb then
|
|
// there will be no intersection.
|
|
if (!cubeBb.overlaps(triBb))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check if one or more triangle point inside
|
|
if (cubeBb.contains(p0) || cubeBb.contains(p1) || cubeBb.contains(p2))
|
|
{
|
|
// One or more points inside
|
|
return true;
|
|
}
|
|
|
|
// Now we have the difficult case: all points are outside but connecting
|
|
// edges might go through cube. Use fast intersection of bounding box.
|
|
|
|
//return triangleFuncs::intersectBbExact(p0, p1, p2, cubeBb);
|
|
return triangleFuncs::intersectBb(p0, p1, p2, cubeBb);
|
|
}
|
|
|
|
|
|
// Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
|
|
// nearestPoint.
|
|
void Foam::treeDataTriSurface::findNearest
|
|
(
|
|
const labelList& indices,
|
|
const point& sample,
|
|
|
|
scalar& nearestDistSqr,
|
|
label& minIndex,
|
|
point& nearestPoint
|
|
) const
|
|
{
|
|
const pointField& points = surface_.points();
|
|
|
|
forAll(indices, i)
|
|
{
|
|
label index = indices[i];
|
|
const labelledTri& f = surface_[index];
|
|
|
|
// Triangle points
|
|
const point& p0 = points[f[0]];
|
|
const point& p1 = points[f[1]];
|
|
const point& p2 = points[f[2]];
|
|
|
|
|
|
////- Possible optimization: do quick rejection of triangle if bounding
|
|
//// sphere does not intersect triangle bounding box. From simplistic
|
|
//// test was not found to speed up things.
|
|
//
|
|
//// Triangle bounding box.
|
|
//point triBbMin = min(p0, min(p1, p2));
|
|
//point triBbMax = max(p0, max(p1, p2));
|
|
//
|
|
//if
|
|
//(
|
|
// indexedOctree<treeDataTriSurface>::intersects
|
|
// (
|
|
// triBbMin,
|
|
// triBbMax,
|
|
// nearestDistSqr,
|
|
// sample
|
|
// )
|
|
//)
|
|
{
|
|
// Get spanning vectors of triangle
|
|
vector base(p1);
|
|
vector E0(p0 - p1);
|
|
vector E1(p2 - p1);
|
|
|
|
scalar a(E0& E0);
|
|
scalar b(E0& E1);
|
|
scalar c(E1& E1);
|
|
|
|
// Get nearest point in s,t coordinates (s is along E0, t is along
|
|
// E1)
|
|
scalar s;
|
|
scalar t;
|
|
|
|
scalar distSqr = nearestCoords
|
|
(
|
|
base,
|
|
E0,
|
|
E1,
|
|
a,
|
|
b,
|
|
c,
|
|
sample,
|
|
|
|
s,
|
|
t
|
|
);
|
|
|
|
if (distSqr < nearestDistSqr)
|
|
{
|
|
nearestDistSqr = distSqr;
|
|
minIndex = index;
|
|
nearestPoint = base + s*E0 + t*E1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Calculate nearest point to line. Updates (if any) nearestDistSqr, minIndex,
|
|
// nearestPoint.
|
|
void Foam::treeDataTriSurface::findNearest
|
|
(
|
|
const labelList& indices,
|
|
const linePointRef& ln,
|
|
|
|
treeBoundBox& tightest,
|
|
label& minIndex,
|
|
point& linePoint,
|
|
point& nearestPoint
|
|
) const
|
|
{
|
|
notImplemented
|
|
(
|
|
"treeDataTriSurface::findNearest(const labelList&"
|
|
", const linePointRef&, treeBoundBox&, label&, point&, point&) const"
|
|
);
|
|
}
|
|
|
|
|
|
bool Foam::treeDataTriSurface::intersects
|
|
(
|
|
const label index,
|
|
const point& start,
|
|
const point& end,
|
|
point& intersectionPoint
|
|
) const
|
|
{
|
|
const pointField& points = surface_.points();
|
|
|
|
const labelledTri& f = surface_[index];
|
|
|
|
// Do quick rejection test
|
|
treeBoundBox triBb(points[f[0]], points[f[0]]);
|
|
triBb.min() = min(triBb.min(), points[f[1]]);
|
|
triBb.max() = max(triBb.max(), points[f[1]]);
|
|
triBb.min() = min(triBb.min(), points[f[2]]);
|
|
triBb.max() = max(triBb.max(), points[f[2]]);
|
|
|
|
const direction startBits(triBb.posBits(start));
|
|
const direction endBits(triBb.posBits(end));
|
|
|
|
if ((startBits & endBits) != 0)
|
|
{
|
|
// start and end in same block outside of triBb.
|
|
return false;
|
|
}
|
|
|
|
const triPointRef tri(points[f[0]], points[f[1]], points[f[2]]);
|
|
|
|
const vector dir(end - start);
|
|
|
|
// Use relative tolerance (from octree) to determine intersection.
|
|
|
|
pointHit inter = tri.intersection
|
|
(
|
|
start,
|
|
dir,
|
|
intersection::HALF_RAY,
|
|
indexedOctree<treeDataTriSurface>::perturbTol()
|
|
);
|
|
|
|
if (inter.hit() && inter.distance() <= 1)
|
|
{
|
|
// Note: no extra test on whether intersection is in front of us
|
|
// since using half_ray.
|
|
intersectionPoint = inter.hitPoint();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
//- Using exact intersections
|
|
//pointHit info = f.tri(points).intersectionExact(start, end);
|
|
//
|
|
//if (info.hit())
|
|
//{
|
|
// intersectionPoint = info.hitPoint();
|
|
//}
|
|
//return info.hit();
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|