1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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 "treeDataTriSurface.H"
28 #include "triSurfaceTools.H"
29 #include "triangleFuncs.H"
30 #include "indexedOctree.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 defineTypeNameAndDebug(Foam::treeDataTriSurface, 0);
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 // Fast distance to triangle calculation. From
40 // "Distance Between Point and Trangle in 3D"
41 // David Eberly, Magic Software Inc. Aug. 2003.
42 // Works on function Q giving distance to point and tries to minimize this.
43 Foam::scalar Foam::treeDataTriSurface::nearestCoords
57 const vector D(base - P);
59 // Precalculate distance factors.
60 const scalar d = E0 & D;
61 const scalar e = E1 & D;
64 const scalar det = a*c - b*b;
80 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
86 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
91 //region 3. Min on edge s = 0
93 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
100 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
105 const scalar invDet = 1/det;
115 const scalar tmp0 = b + d;
116 const scalar tmp1 = c + e;
120 const scalar numer = tmp1 - tmp0;
121 const scalar denom = a-2*b+c;
122 s = (numer >= denom ? 1 : numer/denom);
129 t = (tmp1 <= 0 ? 1 : (e >= 0 ? 0 : - e/c));
135 const scalar tmp0 = b + d;
136 const scalar tmp1 = c + e;
140 const scalar numer = tmp1 - tmp0;
141 const scalar denom = a-2*b+c;
142 s = (numer >= denom ? 1 : numer/denom);
149 s = (tmp1 <= 0 ? 1 : (d >= 0 ? 0 : - d/a));
155 const scalar numer = c+e-(b+d);
162 const scalar denom = a-2*b+c;
163 s = (numer >= denom ? 1 : numer/denom);
170 // Calculate distance.
171 // Note: abs should not be needed but truncation error causes problems
172 // with points very close to one of the triangle vertices.
173 // (seen up to -9e-15). Alternatively add some small value.
175 const scalar f = D & D;
176 return Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f);
180 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
182 // Construct from components
183 Foam::treeDataTriSurface::treeDataTriSurface(const triSurface& surface)
189 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
191 Foam::pointField Foam::treeDataTriSurface::points() const
193 const pointField& points = surface_.points();
195 pointField centres(surface_.size());
197 forAll(surface_, triI)
199 centres[triI] = surface_[triI].centre(points);
205 //- Get type of sample (inside/outside/mixed) w.r.t. surface.
206 Foam::label Foam::treeDataTriSurface::getVolumeType
208 const indexedOctree<treeDataTriSurface>& tree,
212 // Find nearest point
213 const treeBoundBox& treeBb = tree.bb();
215 pointIndexHit pHit = tree.findNearest
221 Foam::magSqr(treeBb.span())
227 FatalErrorIn("treeDataTriSurface::getVolumeType(..)")
228 << "treeBb:" << treeBb
229 << " sample:" << sample
231 << abort(FatalError);
234 triSurfaceTools::sideType t = triSurfaceTools::surfaceSide
240 indexedOctree<treeDataTriSurface>::perturbTol()
243 if (t == triSurfaceTools::UNKNOWN)
245 return indexedOctree<treeDataTriSurface>::UNKNOWN;
247 else if (t == triSurfaceTools::INSIDE)
249 return indexedOctree<treeDataTriSurface>::INSIDE;
251 else if (t == triSurfaceTools::OUTSIDE)
253 return indexedOctree<treeDataTriSurface>::OUTSIDE;
257 FatalErrorIn("treeDataTriSurface::getVolumeType(..)")
258 << "problem" << abort(FatalError);
259 return indexedOctree<treeDataTriSurface>::UNKNOWN;
264 // Check if any point on triangle is inside cubeBb.
265 bool Foam::treeDataTriSurface::overlaps
268 const treeBoundBox& cubeBb
271 const pointField& points = surface_.points();
272 const labelledTri& f = surface_[index];
275 const point& p0 = points[f[0]];
276 const point& p1 = points[f[1]];
277 const point& p2 = points[f[2]];
279 treeBoundBox triBb(p0, p0);
280 triBb.min() = min(triBb.min(), p1);
281 triBb.min() = min(triBb.min(), p2);
283 triBb.max() = max(triBb.max(), p1);
284 triBb.max() = max(triBb.max(), p2);
286 //- For testing: robust one
287 //return cubeBb.overlaps(triBb);
289 //- Exact test of triangle intersecting bb
291 // Quick rejection. If whole bounding box of tri is outside cubeBb then
292 // there will be no intersection.
293 if (!cubeBb.overlaps(triBb))
298 // Check if one or more triangle point inside
299 if (cubeBb.contains(p0) || cubeBb.contains(p1) || cubeBb.contains(p2))
301 // One or more points inside
305 // Now we have the difficult case: all points are outside but connecting
306 // edges might go through cube. Use fast intersection of bounding box.
308 //return triangleFuncs::intersectBbExact(p0, p1, p2, cubeBb);
309 return triangleFuncs::intersectBb(p0, p1, p2, cubeBb);
313 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
315 void Foam::treeDataTriSurface::findNearest
317 const labelList& indices,
320 scalar& nearestDistSqr,
325 const pointField& points = surface_.points();
329 label index = indices[i];
330 const labelledTri& f = surface_[index];
333 const point& p0 = points[f[0]];
334 const point& p1 = points[f[1]];
335 const point& p2 = points[f[2]];
338 ////- Possible optimization: do quick rejection of triangle if bounding
339 //// sphere does not intersect triangle bounding box. From simplistic
340 //// test was not found to speed up things.
342 //// Triangle bounding box.
343 //point triBbMin = min(p0, min(p1, p2));
344 //point triBbMax = max(p0, max(p1, p2));
348 // indexedOctree<treeDataTriSurface>::intersects
357 // Get spanning vectors of triangle
366 // Get nearest point in s,t coordinates (s is along E0, t is along
371 scalar distSqr = nearestCoords
385 if (distSqr < nearestDistSqr)
387 nearestDistSqr = distSqr;
389 nearestPoint = base + s*E0 + t*E1;
396 // Calculate nearest point to line. Updates (if any) nearestDistSqr, minIndex,
398 void Foam::treeDataTriSurface::findNearest
400 const labelList& indices,
401 const linePointRef& ln,
403 treeBoundBox& tightest,
411 "treeDataTriSurface::findNearest(const labelList&"
412 ", const linePointRef&, treeBoundBox&, label&, point&, point&) const"
417 bool Foam::treeDataTriSurface::intersects
422 point& intersectionPoint
425 const pointField& points = surface_.points();
427 const labelledTri& f = surface_[index];
429 // Do quick rejection test
430 treeBoundBox triBb(points[f[0]], points[f[0]]);
431 triBb.min() = min(triBb.min(), points[f[1]]);
432 triBb.max() = max(triBb.max(), points[f[1]]);
433 triBb.min() = min(triBb.min(), points[f[2]]);
434 triBb.max() = max(triBb.max(), points[f[2]]);
436 const direction startBits(triBb.posBits(start));
437 const direction endBits(triBb.posBits(end));
439 if ((startBits & endBits) != 0)
441 // start and end in same block outside of triBb.
445 const triPointRef tri(points[f[0]], points[f[1]], points[f[2]]);
447 const vector dir(end - start);
449 pointHit inter = tri.fastIntersection(start, dir, intersection::HALF_RAY);
451 if (inter.hit() && inter.distance() <= 1)
453 // Note: no extra test on whether intersection is in front of us
454 // since using half_ray.
455 intersectionPoint = inter.hitPoint();
465 //- Using exact intersections
466 //pointHit info = f.tri(points).intersectionExact(start, end);
470 // intersectionPoint = info.hitPoint();
476 // ************************************************************************* //