1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "octreeDataTriSurface.H"
30 #include "labelList.H"
31 #include "treeBoundBox.H"
33 #include "triPointRef.H"
35 #include "triSurfaceTools.H"
36 #include "triangleFuncs.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(Foam::octreeDataTriSurface, 0);
42 Foam::scalar Foam::octreeDataTriSurface::tol(1E-6);
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 // Fast distance to triangle calculation. From
48 // "Distance Between Point and Trangle in 3D"
49 // David Eberly, Magic Software Inc. Aug. 2003.
50 // Works on function Q giving distance to point and tries to minimize this.
51 void Foam::octreeDataTriSurface::nearestCoords
65 const vector D(base - P);
67 // Precalculate distance factors.
68 const scalar d = E0 & D;
69 const scalar e = E1 & D;
72 const scalar det = a*c - b*b;
88 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
94 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
99 //region 3. Min on edge s = 0
101 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
108 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
113 const scalar invDet = 1/det;
123 const scalar tmp0 = b + d;
124 const scalar tmp1 = c + e;
128 const scalar numer = tmp1 - tmp0;
129 const scalar denom = a-2*b+c;
130 s = (numer >= denom ? 1 : numer/denom);
137 t = (tmp1 <= 0 ? 1 : (e >= 0 ? 0 : - e/c));
143 const scalar tmp0 = b + d;
144 const scalar tmp1 = c + e;
148 const scalar numer = tmp1 - tmp0;
149 const scalar denom = a-2*b+c;
150 s = (numer >= denom ? 1 : numer/denom);
157 s = (tmp1 <= 0 ? 1 : (d >= 0 ? 0 : - d/a));
163 const scalar numer = c+e-(b+d);
170 const scalar denom = a-2*b+c;
171 s = (numer >= denom ? 1 : numer/denom);
178 // Calculate distance.
179 // Note: abs should not be needed but truncation error causes problems
180 // with points very close to one of the triangle vertices.
181 // (seen up to -9e-15). Alternatively add some small value.
183 // const scalar f = D & D;
184 // return a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f + SMALL;
185 // return Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f);
189 Foam::point Foam::octreeDataTriSurface::nearestPoint
211 return base_[index] + s*E0_[index] + t*E1_[index];
215 // Helper function to calculate tight fitting bounding boxes.
216 Foam::treeBoundBoxList Foam::octreeDataTriSurface::calcBb
218 const triSurface& surf
221 treeBoundBoxList allBb(surf.size(), treeBoundBox::invertedBox);
223 const labelListList& pointFcs = surf.pointFaces();
224 const pointField& localPts = surf.localPoints();
226 forAll(pointFcs, pointI)
228 const labelList& myFaces = pointFcs[pointI];
229 const point& vertCoord = localPts[pointI];
231 forAll(myFaces, myFaceI)
234 label faceI = myFaces[myFaceI];
236 treeBoundBox& bb = allBb[faceI];
238 bb.min() = min(bb.min(), vertCoord);
239 bb.max() = max(bb.max(), vertCoord);
247 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
249 // Construct from components
250 Foam::octreeDataTriSurface::octreeDataTriSurface(const triSurface& surface)
253 allBb_(calcBb(surface_)),
254 base_(surface_.size()),
255 E0_(surface_.size()),
256 E1_(surface_.size()),
261 // Precalculate factors for distance calculation
262 const pointField& points = surface_.points();
264 forAll(surface_, faceI)
266 const labelledTri& f = surface_[faceI];
268 // Calculate base and spanning vectors of triangles
269 base_[faceI] = points[f[1]];
270 E0_[faceI] = points[f[0]] - points[f[1]];
271 E1_[faceI] = points[f[2]] - points[f[1]];
273 a_[faceI] = E0_[faceI] & E0_[faceI];
274 b_[faceI] = E0_[faceI] & E1_[faceI];
275 c_[faceI] = E1_[faceI] & E1_[faceI];
280 // Construct from components
281 Foam::octreeDataTriSurface::octreeDataTriSurface
283 const triSurface& surface,
284 const treeBoundBoxList& allBb
289 base_(surface_.size()),
290 E0_(surface_.size()),
291 E1_(surface_.size()),
296 const pointField& points = surface_.points();
298 forAll(surface_, faceI)
300 const labelledTri& f = surface_[faceI];
302 // Calculate base and spanning vectors of triangles
303 base_[faceI] = points[f[1]];
304 E0_[faceI] = points[f[0]] - points[f[1]];
305 E1_[faceI] = points[f[2]] - points[f[1]];
307 a_[faceI] = E0_[faceI] & E0_[faceI];
308 b_[faceI] = E0_[faceI] & E1_[faceI];
309 c_[faceI] = E1_[faceI] & E1_[faceI];
314 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
316 Foam::label Foam::octreeDataTriSurface::getSampleType
318 const octree<octreeDataTriSurface>& oc,
323 treeBoundBox tightest(treeBoundBox::greatBox);
324 scalar tightestDist(treeBoundBox::great);
326 // Find nearest face to sample
327 label faceI = oc.findNearest(sample, tightest, tightestDist);
331 Pout<< "getSampleType : sample:" << sample
332 << " nearest face:" << faceI;
339 "octreeDataTriSurface::getSampleType"
340 "(octree<octreeDataTriSurface>&, const point&)"
341 ) << "Could not find " << sample << " in octree."
342 << abort(FatalError);
345 const pointField& pts = surface_.points();
346 const labelledTri& f = surface_[faceI];
348 pointHit curHit = triPointRef
353 ).nearestPoint(sample);
355 // Get normal according to position on face. On point -> pointNormal,
356 // on edge-> edge normal, face normal on interior.
359 triSurfaceTools::surfaceNormal
368 octree<octreeDataTriSurface>::getVolType(n, sample - curHit.rawPoint());
372 // Check if any point on triangle is inside cubeBb.
373 bool Foam::octreeDataTriSurface::overlaps
376 const treeBoundBox& cubeBb
379 //return cubeBb.overlaps(allBb_[index]);
381 //- Exact test of triangle intersecting bb
384 if (!cubeBb.overlaps(allBb_[index]))
390 const pointField& points = surface_.points();
391 const labelledTri& f = surface_[index];
392 const point& p0 = points[f[0]];
393 const point& p1 = points[f[1]];
394 const point& p2 = points[f[2]];
396 // Check if one or more triangle point inside
397 if (cubeBb.contains(p0) || cubeBb.contains(p1) || cubeBb.contains(p2))
399 // One or more points inside
403 // Now we have the difficult case: all points are outside but connecting
404 // edges might go through cube. Use fast intersection of bounding box.
406 return triangleFuncs::intersectBb(p0, p1, p2, cubeBb);
410 bool Foam::octreeDataTriSurface::contains
418 "octreeDataTriSurface::contains(const label, const point&)"
425 bool Foam::octreeDataTriSurface::intersects
430 point& intersectionPoint
433 if (mag(surface_.faceNormals()[index]) < VSMALL)
438 const pointField& points = surface_.points();
440 const labelledTri& f = surface_[index];
442 triPointRef tri(points[f[0]], points[f[1]], points[f[2]]);
444 const vector dir(end - start);
446 // Disable picking up intersections behind us.
447 scalar oldTol = intersection::setPlanarTol(0.0);
449 pointHit inter = tri.ray(start, dir, intersection::HALF_RAY);
451 intersection::setPlanarTol(oldTol);
453 if (inter.hit() && inter.distance() <= mag(dir))
455 // Note: no extra test on whether intersection is in front of us
456 // since using half_ray AND zero tolerance. (note that tolerance
457 // is used to look behind us)
458 intersectionPoint = inter.hitPoint();
469 bool Foam::octreeDataTriSurface::findTightest
473 treeBoundBox& tightest
477 // get nearest and furthest away vertex
479 allBb_[index].calcExtremities(sample, myNear, myFar);
481 const point dist = myFar - sample;
482 scalar myFarDist = mag(dist);
484 point tightestNear, tightestFar;
485 tightest.calcExtremities(sample, tightestNear, tightestFar);
487 scalar tightestFarDist = mag(tightestFar - sample);
489 if (tightestFarDist < myFarDist)
491 // Keep current tightest.
496 // Construct bb around sample and myFar
497 const point dist2(fabs(dist.x()), fabs(dist.y()), fabs(dist.z()));
499 tightest.min() = sample - dist2;
500 tightest.max() = sample + dist2;
507 // Determine numerical value of sign of sample compared to shape at index
508 Foam::scalar Foam::octreeDataTriSurface::calcSign
515 n = surface_.faceNormals()[index];
517 const labelledTri& tri = surface_[index];
519 // take vector from sample to any point on triangle (we use vertex 0)
520 vector vec = sample - surface_.points()[tri[0]];
522 vec /= mag(vec) + VSMALL;
528 // Calculate nearest point to sample on/in shapei. !Does not set nearest
529 Foam::scalar Foam::octreeDataTriSurface::calcNearest
536 return mag(nearestPoint(index, sample) - sample);
540 // Calculate nearest point on/in shapei
541 Foam::scalar Foam::octreeDataTriSurface::calcNearest
544 const linePointRef& ln,
551 "octreeDataTriSurface::calcNearest"
552 "(const label, const linePointRef&, point& linePt, point&)"
558 void Foam::octreeDataTriSurface::write
564 os << surface_[index] << token::SPACE << allBb_[index];
568 // ************************************************************************* //