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
458 const vector edge1 = b_ - a_;
459 const vector edge2 = c_ - a_;
461 // begin calculating determinant - also used to calculate U parameter
462 const vector pVec = dir ^ edge2;
464 // if determinant is near zero, ray lies in plane of triangle
465 const scalar det = edge1 & pVec;
467 // Initialise to miss
468 pointHit intersection(false, vector::zero, GREAT, false);
470 if (alg == intersection::VISIBLE)
478 /* calculate distance from a_ to ray origin */
479 const vector tVec = orig-a_;
481 /* calculate U parameter and test bounds */
482 scalar u = tVec & pVec;
484 if (u < 0.0 || u > det)
490 /* prepare to test V parameter */
491 const vector qVec = tVec ^ edge1;
493 /* calculate V parameter and test bounds */
494 scalar v = dir & qVec;
496 if (v < 0.0 || u + v > det)
502 /* calculate t, scale parameters, ray intersects triangle */
503 scalar t = edge2 & qVec;
504 scalar inv_det = 1.0 / det;
509 intersection.setHit();
510 intersection.setPoint(a_ + u*edge1 + v*edge2);
511 intersection.setDistance(t);
513 else if (alg == intersection::HALF_RAY || alg == intersection::FULL_RAY)
515 // Non-culling branch
516 if (det > -SMALL && det < SMALL)
521 const scalar inv_det = 1.0 / det;
523 /* calculate distance from a_ to ray origin */
524 const vector tVec = orig - a_;
525 /* calculate U parameter and test bounds */
526 const scalar u = (tVec & pVec)*inv_det;
528 if (u < 0.0 || u > 1.0)
533 /* prepare to test V parameter */
534 const vector qVec = tVec ^ edge1;
535 /* calculate V parameter and test bounds */
536 const scalar v = (dir & qVec) * inv_det;
538 if (v < 0.0 || u + v > 1.0)
543 /* calculate t, ray intersects triangle */
544 const scalar t = (edge2 & qVec) * inv_det;
546 if (alg == intersection::HALF_RAY && t < 0)
552 intersection.setHit();
553 intersection.setPoint(a_ + u*edge1 + v*edge2);
554 intersection.setDistance(t);
560 "triangle<Point, PointRef>::intersection(const point&"
561 ", const vector&, const intersection::algorithm)"
562 ) << "intersection only defined for VISIBLE, FULL_RAY or HALF_RAY"
563 << abort(FatalError);
570 template<class Point, class PointRef>
571 inline pointHit triangle<Point, PointRef>::nearestPoint
576 // Express triangle in terms of baseVertex (point a_) and
581 return nearestPoint(a_, E0, E1, p);
585 template<class Point, class PointRef>
586 inline bool triangle<Point, PointRef>::classify
594 const vector E0 = b_ - a_;
595 const vector E1 = c_ - a_;
596 const vector n = 0.5*(E0 ^ E1);
598 // Get largest component of normal
599 scalar magX = Foam::mag(n.x());
600 scalar magY = Foam::mag(n.y());
601 scalar magZ = Foam::mag(n.z());
604 if ((magX >= magY) && (magX >= magZ))
608 else if ((magY >= magX) && (magY >= magZ))
617 // Get other components
618 label i1 = (i0 + 1) % 3;
619 label i2 = (i1 + 1) % 3;
628 scalar det = v2*u1 - u2*v1;
630 scalar u0 = p[i1] - a_[i1];
631 scalar v0 = p[i2] - a_[i2];
638 if (Foam::mag(u1) < SMALL)
642 alpha = (v0 - beta*v2)/v1;
644 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
648 beta = (v0*u1 - u0*v1)/det;
650 alpha = (u0 - beta*u2)/u1;
652 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
656 // Now alpha, beta are the coordinates in the triangle local coordinate
663 if (Foam::mag(alpha+beta-1) <= tol)
665 // On edge between vert 1-2 (=edge 1)
667 if (Foam::mag(alpha) <= tol)
672 else if (Foam::mag(beta) <= tol)
677 else if ((alpha >= 0) && (alpha <= 1) && (beta >= 0) && (beta <= 1))
683 else if (Foam::mag(alpha) <= tol)
685 // On edge between vert 2-0 (=edge 2)
687 if (Foam::mag(beta) <= tol)
692 else if (Foam::mag(beta-1) <= tol)
697 else if ((beta >= 0) && (beta <= 1))
703 else if (Foam::mag(beta) <= tol)
705 // On edge between vert 0-1 (= edge 0)
707 if (Foam::mag(alpha) <= tol)
712 else if (Foam::mag(alpha-1) <= tol)
717 else if ((alpha >= 0) && (alpha <= 1))
731 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
733 template<class point, class pointRef>
734 inline Istream& operator>>(Istream& is, triangle<point, pointRef>& t)
736 // Read beginning of triangle point pair
737 is.readBegin("triangle");
739 is >> t.a_ >> t.b_ >> t.c_;
741 // Read end of triangle point pair
742 is.readEnd("triangle");
744 // Check state of Ostream
745 is.check("Istream& operator>>(Istream&, triangle&)");
751 template<class Point, class PointRef>
752 inline Ostream& operator<<(Ostream& os, const triangle<Point, PointRef>& t)
756 << t.a_ << token::SPACE << t.b_ << token::SPACE << t.c_
763 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
765 } // End namespace Foam
767 // ************************************************************************* //