1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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/>.
24 \*---------------------------------------------------------------------------*/
26 #include "IOstreams.H"
28 #include "mathematicalConstants.H"
30 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
32 template<class Point, class PointRef>
33 inline Foam::triangle<Point, PointRef>::triangle
46 template<class Point, class PointRef>
47 inline Foam::triangle<Point, PointRef>::triangle
49 const UList<Point>& points,
50 const FixedList<label, 3>& indices
53 a_(points[indices[0]]),
54 b_(points[indices[1]]),
55 c_(points[indices[2]])
60 template<class Point, class PointRef>
61 inline Foam::triangle<Point, PointRef>::triangle(Istream& is)
67 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
69 template<class Point, class PointRef>
70 inline const Point& Foam::triangle<Point, PointRef>::a() const
75 template<class Point, class PointRef>
76 inline const Point& Foam::triangle<Point, PointRef>::b() const
81 template<class Point, class PointRef>
82 inline const Point& Foam::triangle<Point, PointRef>::c() const
88 template<class Point, class PointRef>
89 inline Point Foam::triangle<Point, PointRef>::centre() const
91 return (1.0/3.0)*(a_ + b_ + c_);
95 template<class Point, class PointRef>
96 inline Foam::scalar Foam::triangle<Point, PointRef>::mag() const
98 return Foam::mag(normal());
102 template<class Point, class PointRef>
103 inline Foam::vector Foam::triangle<Point, PointRef>::normal() const
105 return 0.5*((b_ - a_)^(c_ - a_));
109 template<class Point, class PointRef>
110 inline Point Foam::triangle<Point, PointRef>::circumCentre() const
112 scalar d1 = (c_ - a_) & (b_ - a_);
113 scalar d2 = -(c_ - b_) & (b_ - a_);
114 scalar d3 = (c_ - a_) & (c_ - b_);
120 scalar c = c1 + c2 + c3;
122 if (Foam::mag(c) < ROOTVSMALL)
124 // Degenerate triangle, returning centre instead of circumCentre.
131 ((c2 + c3)*a_ + (c3 + c1)*b_ + (c1 + c2)*c_)/(2*c)
136 template<class Point, class PointRef>
137 inline Foam::scalar Foam::triangle<Point, PointRef>::circumRadius() const
139 scalar d1 = (c_ - a_) & (b_ - a_);
140 scalar d2 = -(c_ - b_) & (b_ - a_);
141 scalar d3 = (c_ - a_) & (c_ - b_);
143 scalar denom = d2*d3 + d3*d1 + d1*d2;
145 if (Foam::mag(denom) < VSMALL)
147 // Degenerate triangle, returning GREAT for circumRadius.
153 scalar a = (d1 + d2)*(d2 + d3)*(d3 + d1) / denom;
155 return 0.5*Foam::sqrt(min(GREAT, max(0, a)));
160 template<class Point, class PointRef>
161 inline Foam::scalar Foam::triangle<Point, PointRef>::quality() const
163 return mag()/(Foam::sqr(circumRadius())*3.0*sqrt(3.0)/4.0 + VSMALL);
167 template<class Point, class PointRef>
168 inline Foam::scalar Foam::triangle<Point, PointRef>::sweptVol
175 ((t.a_ - a_) & ((b_ - a_)^(c_ - a_)))
176 + ((t.b_ - b_) & ((c_ - b_)^(t.a_ - b_)))
177 + ((c_ - t.c_) & ((t.b_ - t.c_)^(t.a_ - t.c_)))
179 + ((t.a_ - a_) & ((b_ - a_)^(c_ - a_)))
180 + ((b_ - t.b_) & ((t.a_ - t.b_)^(t.c_ - t.b_)))
181 + ((c_ - t.c_) & ((b_ - t.c_)^(t.a_ - t.c_)))
186 template<class Point, class PointRef>
187 inline Foam::tensor Foam::triangle<Point, PointRef>::inertia
193 Point aRel = a_ - refPt;
194 Point bRel = b_ - refPt;
195 Point cRel = c_ - refPt;
199 aRel.x(), aRel.y(), aRel.z(),
200 bRel.x(), bRel.y(), bRel.z(),
201 cRel.x(), cRel.y(), cRel.z()
204 scalar a = Foam::mag((b_ - a_)^(c_ - a_));
206 tensor S = 1/24.0*(tensor::one + I);
215 + ((aRel + bRel + cRel) & (aRel + bRel + cRel))
223 template<class Point, class PointRef>
224 inline Point Foam::triangle<Point, PointRef>::randomPoint(Random& rndGen) const
226 // Generating Random Points in Triangles
228 // from "Graphics Gems", Academic Press, 1990
229 // http://tog.acm.org/GraphicsGems/gems/TriPoints.c
231 scalar s = rndGen.scalar01();
233 scalar t = sqrt(rndGen.scalar01());
235 return (1 - t)*a_ + (1 - s)*t*b_ + s*t*c_;
239 template<class Point, class PointRef>
240 Foam::scalar Foam::triangle<Point, PointRef>::barycentric
247 // Real-time collision detection, Christer Ericson, 2005, p47-48
253 scalar d00 = v0 & v0;
254 scalar d01 = v0 & v1;
255 scalar d11 = v1 & v1;
256 scalar d20 = v2 & v0;
257 scalar d21 = v2 & v1;
259 scalar denom = d00*d11 - d01*d01;
261 if (Foam::mag(denom) < SMALL)
263 // Degenerate triangle, returning 1/3 barycentric coordinates.
265 bary = List<scalar>(3, 1.0/3.0);
272 bary[1] = (d11*d20 - d01*d21)/denom;
273 bary[2] = (d00*d21 - d01*d20)/denom;
274 bary[0] = 1.0 - bary[1] - bary[2];
280 template<class Point, class PointRef>
281 inline Foam::pointHit Foam::triangle<Point, PointRef>::ray
285 const intersection::algorithm alg,
286 const intersection::direction dir
289 // Express triangle in terms of baseVertex (point a_) and
294 // Initialize intersection to miss.
297 vector n(0.5*(E0 ^ E1));
298 scalar area = Foam::mag(n);
303 inter.setMiss(false);
305 // The miss point is the nearest point on the triangle. Take any one.
308 // The distance to the miss is the distance between the
309 // original point and plane of intersection. No normal so use
310 // distance from p to a_
311 inter.setDistance(Foam::mag(a_ - p));
316 vector q1 = q/Foam::mag(q);
318 if (dir == intersection::CONTACT_SPHERE)
322 return ray(p, q1 - n, alg, intersection::VECTOR);
325 // Intersection point with triangle plane
327 // Is intersection point inside triangle
330 // Reuse the fast ray intersection routine below in FULL_RAY
331 // mode since the original intersection routine has rounding problems.
332 pointHit fastInter = intersection(p, q1, intersection::FULL_RAY);
333 hit = fastInter.hit();
337 pInter = fastInter.rawPoint();
341 // Calculate intersection of ray with triangle plane
343 pInter = p + (q1&v)*q1;
347 // Distance to intersection point
348 scalar dist = q1 & (pInter - p);
350 const scalar planarPointTol =
359 )*intersection::planarTol();
362 alg == intersection::FULL_RAY
363 || (alg == intersection::HALF_RAY && dist > -planarPointTol)
365 alg == intersection::VISIBLE
366 && ((q1 & normal()) < -VSMALL)
371 // Hit. Set distance to intersection.
373 inter.setPoint(pInter);
374 inter.setDistance(dist);
378 // Miss or ineligible hit.
379 inter.setMiss(eligible);
381 // The miss point is the nearest point on the triangle
382 inter.setPoint(nearestPoint(p).rawPoint());
384 // The distance to the miss is the distance between the
385 // original point and plane of intersection
386 inter.setDistance(Foam::mag(pInter - p));
394 // From "Fast, Minimum Storage Ray/Triangle Intersection"
396 template<class Point, class PointRef>
397 inline Foam::pointHit Foam::triangle<Point, PointRef>::intersection
401 const intersection::algorithm alg,
405 const vector edge1 = b_ - a_;
406 const vector edge2 = c_ - a_;
408 // begin calculating determinant - also used to calculate U parameter
409 const vector pVec = dir ^ edge2;
411 // if determinant is near zero, ray lies in plane of triangle
412 const scalar det = edge1 & pVec;
414 // Initialise to miss
415 pointHit intersection(false, vector::zero, GREAT, false);
417 if (alg == intersection::VISIBLE)
420 if (det < ROOTVSMALL)
422 // Ray on wrong side of triangle. Return miss
426 else if (alg == intersection::HALF_RAY || alg == intersection::FULL_RAY)
428 // Non-culling branch
429 if (det > -ROOTVSMALL && det < ROOTVSMALL)
431 // Ray parallel to triangle. Return miss
436 const scalar inv_det = 1.0 / det;
438 /* calculate distance from a_ to ray origin */
439 const vector tVec = orig-a_;
441 /* calculate U parameter and test bounds */
442 const scalar u = (tVec & pVec)*inv_det;
444 if (u < -tol || u > 1.0+tol)
450 /* prepare to test V parameter */
451 const vector qVec = tVec ^ edge1;
453 /* calculate V parameter and test bounds */
454 const scalar v = (dir & qVec) * inv_det;
456 if (v < -tol || u + v > 1.0+tol)
462 /* calculate t, scale parameters, ray intersects triangle */
463 const scalar t = (edge2 & qVec) * inv_det;
465 if (alg == intersection::HALF_RAY && t < -tol)
467 // Wrong side of orig. Return miss
471 intersection.setHit();
472 intersection.setPoint(a_ + u*edge1 + v*edge2);
473 intersection.setDistance(t);
479 template<class Point, class PointRef>
480 Foam::pointHit Foam::triangle<Point, PointRef>::nearestPointClassify
488 // Real-time collision detection, Christer Ericson, 2005, p136-142
490 // Check if P in vertex region outside A
498 if (d1 <= 0.0 && d2 <= 0.0)
500 // barycentric coordinates (1, 0, 0)
504 return pointHit(false, a_, Foam::mag(a_ - p), true);
507 // Check if P in vertex region outside B
512 if (d3 >= 0.0 && d4 <= d3)
514 // barycentric coordinates (0, 1, 0)
518 return pointHit(false, b_, Foam::mag(b_ - p), true);
521 // Check if P in edge region of AB, if so return projection of P onto AB
522 scalar vc = d1*d4 - d3*d2;
524 if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0)
526 if ((d1 - d3) < ROOTVSMALL)
528 // Degenerate triangle, for d1 = d3, a_ and b_ are likely coincident
531 return pointHit(false, a_, Foam::mag(a_ - p), true);
534 // barycentric coordinates (1-v, v, 0)
535 scalar v = d1/(d1 - d3);
537 point nearPt = a_ + v*ab;
540 return pointHit(false, nearPt, Foam::mag(nearPt - p), true);
543 // Check if P in vertex region outside C
548 if (d6 >= 0.0 && d5 <= d6)
550 // barycentric coordinates (0, 0, 1)
554 return pointHit(false, c_, Foam::mag(c_ - p), true);
557 // Check if P in edge region of AC, if so return projection of P onto AC
558 scalar vb = d5*d2 - d1*d6;
560 if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0)
562 if ((d2 - d6) < ROOTVSMALL)
564 // Degenerate triangle, for d2 = d6, a_ and c_ are likely coincident
567 return pointHit(false, a_, Foam::mag(a_ - p), true);
570 // barycentric coordinates (1-w, 0, w)
571 scalar w = d2/(d2 - d6);
573 point nearPt = a_ + w*ac;
576 return pointHit(false, nearPt, Foam::mag(nearPt - p), true);
579 // Check if P in edge region of BC, if so return projection of P onto BC
580 scalar va = d3*d6 - d5*d4;
582 if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0)
584 if (((d4 - d3) + (d5 - d6)) < ROOTVSMALL)
586 // Degenerate triangle, for (d4 - d3) = (d6 - d5), b_ and c_ are
590 return pointHit(false, b_, Foam::mag(b_ - p), true);
593 // barycentric coordinates (0, 1-w, w)
594 scalar w = (d4 - d3)/((d4 - d3) + (d5 - d6));
596 point nearPt = b_ + w*(c_ - b_);
599 return pointHit(false, nearPt, Foam::mag(nearPt - p), true);
602 // P inside face region. Compute Q through its barycentric
603 // coordinates (u, v, w)
605 if ((va + vb + vc) < ROOTVSMALL)
607 // Degenerate triangle, return the centre because no edge or points are
609 point nearPt = centre();
612 return pointHit(true, nearPt, Foam::mag(nearPt - p), false);
615 scalar denom = 1.0/(va + vb + vc);
616 scalar v = vb * denom;
617 scalar w = vc * denom;
619 // = u*a + v*b + w*c, u = va*denom = 1.0 - v - w
621 point nearPt = a_ + ab*v + ac*w;
624 return pointHit(true, nearPt, Foam::mag(nearPt - p), false);
628 template<class Point, class PointRef>
629 inline Foam::pointHit Foam::triangle<Point, PointRef>::nearestPoint
636 label nearLabel = -1;
638 return nearestPointClassify(p, nearType, nearLabel);
642 template<class Point, class PointRef>
643 inline bool Foam::triangle<Point, PointRef>::classify
650 return nearestPointClassify(p, nearType, nearLabel).hit();
654 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
656 template<class Point, class PointRef>
657 inline Foam::Istream& Foam::operator>>
660 triangle<Point, PointRef>& t
663 is.readBegin("triangle");
664 is >> t.a_ >> t.b_ >> t.c_;
665 is.readEnd("triangle");
667 is.check("Istream& operator>>(Istream&, triangle&)");
672 template<class Point, class PointRef>
673 inline Foam::Ostream& Foam::operator<<
676 const triangle<Point, PointRef>& t
681 << t.a_ << token::SPACE
682 << t.b_ << token::SPACE
690 // ************************************************************************* //