1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 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 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 "IOstreams.H"
29 #include "mathematicalConstants.H"
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 template<class Point, class PointRef>
39 pointHit triangle<Point, PointRef>::nearestPoint
41 const Point& baseVertex,
48 const vector D(baseVertex - P);
50 // Some geometrical factors
51 const scalar a = E0 & E0;
52 const scalar b = E0 & E1;
53 const scalar c = E1 & E1;
55 // Precalculate distance factors
56 const scalar d = E0 & D;
57 const scalar e = E1 & D;
58 const scalar f = D & D;
61 const scalar det = a*c - b*b;
78 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
84 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
89 // Region 3. Min on edge s = 0
91 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
98 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
103 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: Foam::mag used since truncation error causes negative distances
172 // with points very close to one of the triangle vertices.
173 // (Up to -2.77556e-14 seen). Could use +SMALL but that not large enough.
178 baseVertex + s*E0 + t*E1,
181 Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f)
188 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
190 template<class Point, class PointRef>
191 inline triangle<Point, PointRef>::triangle
204 template<class Point, class PointRef>
205 inline triangle<Point, PointRef>::triangle(Istream& is)
207 // Read beginning of triangle point pair
208 is.readBegin("triangle");
210 is >> a_ >> b_ >> c_;
212 // Read end of triangle point pair
213 is.readEnd("triangle");
215 // Check state of Istream
216 is.check("triangle::triangle(Istream& is)");
220 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
222 template<class Point, class PointRef>
223 inline const Point& triangle<Point, PointRef>::a() const
228 template<class Point, class PointRef>
229 inline const Point& triangle<Point, PointRef>::b() const
234 template<class Point, class PointRef>
235 inline const Point& triangle<Point, PointRef>::c() const
241 template<class Point, class PointRef>
242 inline Point triangle<Point, PointRef>::centre() const
244 return (1.0/3.0)*(a_ + b_ + c_);
248 template<class Point, class PointRef>
249 inline scalar triangle<Point, PointRef>::mag() const
251 return ::Foam::mag(normal());
255 template<class Point, class PointRef>
256 inline vector triangle<Point, PointRef>::normal() const
258 return 0.5*((b_ - a_)^(c_ - a_));
262 template<class Point, class PointRef>
263 inline vector triangle<Point, PointRef>::circumCentre() const
265 scalar d1 = (c_ - a_)&(b_ - a_);
266 scalar d2 = -(c_ - b_)&(b_ - a_);
267 scalar d3 = (c_ - a_)&(c_ - b_);
273 scalar c = c1 + c2 + c3;
277 ((c2 + c3)*a_ + (c3 + c1)*b_ + (c1 + c2)*c_)/(2*c)
282 template<class Point, class PointRef>
283 inline scalar triangle<Point, PointRef>::circumRadius() const
285 scalar d1 = (c_ - a_) & (b_ - a_);
286 scalar d2 = - (c_ - b_) & (b_ - a_);
287 scalar d3 = (c_ - a_) & (c_ - b_);
289 scalar denom = d2*d3 + d3*d1 + d1*d2;
291 if (Foam::mag(denom) < VSMALL)
297 scalar a = (d1 + d2)*(d2 + d3)*(d3 + d1) / denom;
299 return 0.5*Foam::sqrt(min(GREAT, max(0, a)));
304 template<class Point, class PointRef>
305 inline scalar triangle<Point, PointRef>::quality() const
310 mathematicalConstant::pi
311 * Foam::sqr(circumRadius())
318 template<class Point, class PointRef>
319 inline scalar triangle<Point, PointRef>::sweptVol(const triangle& t) const
323 ((t.a_ - a_) & ((b_ - a_)^(c_ - a_)))
324 + ((t.b_ - b_) & ((c_ - b_)^(t.a_ - b_)))
325 + ((c_ - t.c_) & ((t.b_ - t.c_)^(t.a_ - t.c_)))
327 + ((t.a_ - a_) & ((b_ - a_)^(c_ - a_)))
328 + ((b_ - t.b_) & ((t.a_ - t.b_)^(t.c_ - t.b_)))
329 + ((c_ - t.c_) & ((b_ - t.c_)^(t.a_ - t.c_)))
334 template<class Point, class PointRef>
335 inline pointHit triangle<Point, PointRef>::ray
339 const intersection::algorithm alg,
340 const intersection::direction dir
343 // Express triangle in terms of baseVertex (point a_) and
348 // Initialize intersection to miss.
351 vector n(0.5*(E0 ^ E1));
352 scalar area = Foam::mag(n);
357 inter.setMiss(false);
359 // The miss point is the nearest point on the triangle. Take any one.
362 // The distance to the miss is the distance between the
363 // original point and plane of intersection. No normal so use
364 // distance from p to a_
365 inter.setDistance(Foam::mag(a_ - p));
370 vector q1 = q/Foam::mag(q);
372 if (dir == intersection::CONTACT_SPHERE)
376 return ray(p, q1 - n, alg, intersection::VECTOR);
379 // Intersection point with triangle plane
381 // Is intersection point inside triangle
384 // Reuse the fast ray intersection routine below in FULL_RAY
385 // mode since the original intersection routine has rounding problems.
386 pointHit fastInter = intersection(p, q1, intersection::FULL_RAY);
387 hit = fastInter.hit();
391 pInter = fastInter.rawPoint();
395 // Calculate intersection of ray with triangle plane
397 pInter = p + (q1&v)*q1;
401 // Distance to intersection point
402 scalar dist = q1 & (pInter - p);
404 const scalar planarPointTol =
413 )*intersection::planarTol();
416 alg == intersection::FULL_RAY
417 || (alg == intersection::HALF_RAY && dist > -planarPointTol)
419 alg == intersection::VISIBLE
420 && ((q1 & normal()) < -VSMALL)
425 // Hit. Set distance to intersection.
427 inter.setPoint(pInter);
428 inter.setDistance(dist);
432 // Miss or ineligible hit.
433 inter.setMiss(eligible);
435 // The miss point is the nearest point on the triangle
436 inter.setPoint(nearestPoint(a_, E0, E1, p).rawPoint());
438 // The distance to the miss is the distance between the
439 // original point and plane of intersection
440 inter.setDistance(Foam::mag(pInter - p));
448 // From "Fast, Minimum Storage Ray/Triangle Intersection"
450 template<class Point, class PointRef>
451 inline pointHit triangle<Point, PointRef>::intersection
455 const intersection::algorithm alg,
459 const vector edge1 = b_ - a_;
460 const vector edge2 = c_ - a_;
462 // begin calculating determinant - also used to calculate U parameter
463 const vector pVec = dir ^ edge2;
465 // if determinant is near zero, ray lies in plane of triangle
466 const scalar det = edge1 & pVec;
468 // Initialise to miss
469 pointHit intersection(false, vector::zero, GREAT, false);
471 if (alg == intersection::VISIBLE)
474 if (det < ROOTVSMALL)
476 // Ray on wrong side of triangle. Return miss
480 else if (alg == intersection::HALF_RAY || alg == intersection::FULL_RAY)
482 // Non-culling branch
483 if (det > -ROOTVSMALL && det < ROOTVSMALL)
485 // Ray parallel to triangle. Return miss
490 const scalar inv_det = 1.0 / det;
492 /* calculate distance from a_ to ray origin */
493 const vector tVec = orig-a_;
495 /* calculate U parameter and test bounds */
496 const scalar u = (tVec & pVec)*inv_det;
498 if (u < -tol || u > 1.0+tol)
504 /* prepare to test V parameter */
505 const vector qVec = tVec ^ edge1;
507 /* calculate V parameter and test bounds */
508 const scalar v = (dir & qVec) * inv_det;
510 if (v < -tol || u + v > 1.0+tol)
516 /* calculate t, scale parameters, ray intersects triangle */
517 const scalar t = (edge2 & qVec) * inv_det;
519 if (alg == intersection::HALF_RAY && t < -tol)
521 // Wrong side of orig. Return miss
525 intersection.setHit();
526 intersection.setPoint(a_ + u*edge1 + v*edge2);
527 intersection.setDistance(t);
533 template<class Point, class PointRef>
534 inline pointHit triangle<Point, PointRef>::nearestPoint
539 // Express triangle in terms of baseVertex (point a_) and
544 return nearestPoint(a_, E0, E1, p);
548 template<class Point, class PointRef>
549 inline bool triangle<Point, PointRef>::classify
557 const vector E0 = b_ - a_;
558 const vector E1 = c_ - a_;
559 const vector n = 0.5*(E0 ^ E1);
561 // Get largest component of normal
562 scalar magX = Foam::mag(n.x());
563 scalar magY = Foam::mag(n.y());
564 scalar magZ = Foam::mag(n.z());
567 if ((magX >= magY) && (magX >= magZ))
571 else if ((magY >= magX) && (magY >= magZ))
580 // Get other components
581 label i1 = (i0 + 1) % 3;
582 label i2 = (i1 + 1) % 3;
591 scalar det = v2*u1 - u2*v1;
593 scalar u0 = p[i1] - a_[i1];
594 scalar v0 = p[i2] - a_[i2];
601 if (Foam::mag(u1) < ROOTVSMALL)
605 alpha = (v0 - beta*v2)/v1;
607 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
611 beta = (v0*u1 - u0*v1)/det;
613 alpha = (u0 - beta*u2)/u1;
615 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
619 // Now alpha, beta are the coordinates in the triangle local coordinate
623 //Pout<< "alpha:" << alpha << endl;
624 //Pout<< "beta:" << beta << endl;
625 //Pout<< "hit:" << hit << endl;
626 //Pout<< "tol:" << tol << endl;
630 // alpha,beta might get negative due to precision errors
631 alpha = max(0.0, min(1.0, alpha));
632 beta = max(0.0, min(1.0, beta));
638 if (Foam::mag(alpha+beta-1) <= tol)
640 // On edge between vert 1-2 (=edge 1)
642 if (Foam::mag(alpha) <= tol)
647 else if (Foam::mag(beta) <= tol)
652 else if ((alpha >= 0) && (alpha <= 1) && (beta >= 0) && (beta <= 1))
658 else if (Foam::mag(alpha) <= tol)
660 // On edge between vert 2-0 (=edge 2)
662 if (Foam::mag(beta) <= tol)
667 else if (Foam::mag(beta-1) <= tol)
672 else if ((beta >= 0) && (beta <= 1))
678 else if (Foam::mag(beta) <= tol)
680 // On edge between vert 0-1 (= edge 0)
682 if (Foam::mag(alpha) <= tol)
687 else if (Foam::mag(alpha-1) <= tol)
692 else if ((alpha >= 0) && (alpha <= 1))
706 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
708 template<class point, class pointRef>
709 inline Istream& operator>>(Istream& is, triangle<point, pointRef>& t)
711 // Read beginning of triangle point pair
712 is.readBegin("triangle");
714 is >> t.a_ >> t.b_ >> t.c_;
716 // Read end of triangle point pair
717 is.readEnd("triangle");
719 // Check state of Ostream
720 is.check("Istream& operator>>(Istream&, triangle&)");
726 template<class Point, class PointRef>
727 inline Ostream& operator<<(Ostream& os, const triangle<Point, PointRef>& t)
731 << t.a_ << token::SPACE << t.b_ << token::SPACE << t.c_
738 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
740 } // End namespace Foam
742 // ************************************************************************* //