1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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);
382 // Reuse the fast ray intersection routine below in FULL_RAY
383 // mode since the original intersection routine has rounding problems.
384 pointHit fastInter = intersection(p, q1, intersection::FULL_RAY);
385 pInter = fastInter.rawPoint();
386 hit = fastInter.hit();
389 scalar dist = q1 & (pInter - p);
391 const scalar planarPointTol =
400 )*intersection::planarTol();
403 alg == intersection::FULL_RAY
404 || (alg == intersection::HALF_RAY && dist > -planarPointTol)
406 alg == intersection::VISIBLE
407 && ((q1 & normal()) < -VSMALL)
412 // Hit. Set distance to intersection.
414 inter.setPoint(pInter);
415 inter.setDistance(dist);
419 // Miss or ineligible hit.
420 inter.setMiss(eligible);
422 // The miss point is the nearest point on the triangle
423 inter.setPoint(nearestPoint(a_, E0, E1, p).rawPoint());
425 // The distance to the miss is the distance between the
426 // original point and plane of intersection
427 inter.setDistance(Foam::mag(pInter - p));
435 // From "Fast, Minimum Storage Ray/Triangle Intersection"
437 template<class Point, class PointRef>
438 inline pointHit triangle<Point, PointRef>::intersection
442 const intersection::algorithm alg
445 const vector edge1 = b_ - a_;
446 const vector edge2 = c_ - a_;
448 // begin calculating determinant - also used to calculate U parameter
449 const vector pVec = dir ^ edge2;
451 // if determinant is near zero, ray lies in plane of triangle
452 const scalar det = edge1 & pVec;
454 // Initialise to miss
455 pointHit intersection(false, vector::zero, GREAT, false);
457 if (alg == intersection::VISIBLE)
465 /* calculate distance from a_ to ray origin */
466 const vector tVec = orig-a_;
468 /* calculate U parameter and test bounds */
469 scalar u = tVec & pVec;
471 if (u < 0.0 || u > det)
477 /* prepare to test V parameter */
478 const vector qVec = tVec ^ edge1;
480 /* calculate V parameter and test bounds */
481 scalar v = dir & qVec;
483 if (v < 0.0 || u + v > det)
489 /* calculate t, scale parameters, ray intersects triangle */
490 scalar t = edge2 & qVec;
491 scalar inv_det = 1.0 / det;
496 intersection.setHit();
497 intersection.setPoint(a_ + u*edge1 + v*edge2);
498 intersection.setDistance(t);
500 else if (alg == intersection::HALF_RAY || alg == intersection::FULL_RAY)
502 // Non-culling branch
503 if (det > -SMALL && det < SMALL)
508 const scalar inv_det = 1.0 / det;
510 /* calculate distance from a_ to ray origin */
511 const vector tVec = orig - a_;
512 /* calculate U parameter and test bounds */
513 const scalar u = (tVec & pVec)*inv_det;
515 if (u < 0.0 || u > 1.0)
520 /* prepare to test V parameter */
521 const vector qVec = tVec ^ edge1;
522 /* calculate V parameter and test bounds */
523 const scalar v = (dir & qVec) * inv_det;
525 if (v < 0.0 || u + v > 1.0)
530 /* calculate t, ray intersects triangle */
531 const scalar t = (edge2 & qVec) * inv_det;
533 if (alg == intersection::HALF_RAY && t < 0)
539 intersection.setHit();
540 intersection.setPoint(a_ + u*edge1 + v*edge2);
541 intersection.setDistance(t);
547 "triangle<Point, PointRef>::intersection(const point&"
548 ", const vector&, const intersection::algorithm)"
549 ) << "intersection only defined for VISIBLE, FULL_RAY or HALF_RAY"
550 << abort(FatalError);
557 template<class Point, class PointRef>
558 inline pointHit triangle<Point, PointRef>::nearestPoint
563 // Express triangle in terms of baseVertex (point a_) and
568 return nearestPoint(a_, E0, E1, p);
572 template<class Point, class PointRef>
573 inline bool triangle<Point, PointRef>::classify
581 const vector E0 = b_ - a_;
582 const vector E1 = c_ - a_;
583 const vector n = 0.5*(E0 ^ E1);
585 // Get largest component of normal
586 scalar magX = Foam::mag(n.x());
587 scalar magY = Foam::mag(n.y());
588 scalar magZ = Foam::mag(n.z());
591 if ((magX >= magY) && (magX >= magZ))
595 else if ((magY >= magX) && (magY >= magZ))
604 // Get other components
605 label i1 = (i0 + 1) % 3;
606 label i2 = (i1 + 1) % 3;
615 scalar det = v2*u1 - u2*v1;
617 scalar u0 = p[i1] - a_[i1];
618 scalar v0 = p[i2] - a_[i2];
625 if (Foam::mag(u1) < SMALL)
629 alpha = (v0 - beta*v2)/v1;
631 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
635 beta = (v0*u1 - u0*v1)/det;
637 alpha = (u0 - beta*u2)/u1;
639 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
643 // Now alpha, beta are the coordinates in the triangle local coordinate
650 if (Foam::mag(alpha+beta-1) <= tol)
652 // On edge between vert 1-2 (=edge 1)
654 if (Foam::mag(alpha) <= tol)
659 else if (Foam::mag(beta) <= tol)
664 else if ((alpha >= 0) && (alpha <= 1) && (beta >= 0) && (beta <= 1))
670 else if (Foam::mag(alpha) <= tol)
672 // On edge between vert 2-0 (=edge 2)
674 if (Foam::mag(beta) <= tol)
679 else if (Foam::mag(beta-1) <= tol)
684 else if ((beta >= 0) && (beta <= 1))
690 else if (Foam::mag(beta) <= tol)
692 // On edge between vert 0-1 (= edge 0)
694 if (Foam::mag(alpha) <= tol)
699 else if (Foam::mag(alpha-1) <= tol)
704 else if ((alpha >= 0) && (alpha <= 1))
718 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
720 template<class point, class pointRef>
721 inline Istream& operator>>(Istream& is, triangle<point, pointRef>& t)
723 // Read beginning of triangle point pair
724 is.readBegin("triangle");
726 is >> t.a_ >> t.b_ >> t.c_;
728 // Read end of triangle point pair
729 is.readEnd("triangle");
731 // Check state of Ostream
732 is.check("Istream& operator>>(Istream&, triangle&)");
738 template<class Point, class PointRef>
739 inline Ostream& operator<<(Ostream& os, const triangle<Point, PointRef>& t)
743 << t.a_ << token::SPACE << t.b_ << token::SPACE << t.c_
750 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
752 } // End namespace Foam
754 // ************************************************************************* //