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 "faceTriangulation.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 const Foam::scalar Foam::faceTriangulation::edgeRelTol = 1E-6;
35 // Edge to the right of face vertex i
36 Foam::label Foam::faceTriangulation::right(const label, label i)
42 // Edge to the left of face vertex i
43 Foam::label Foam::faceTriangulation::left(const label size, label i)
45 return i ? i-1 : size-1;
49 // Calculate (normalized) edge vectors.
50 // edges[i] gives edge between point i+1 and i.
51 Foam::tmp<Foam::vectorField> Foam::faceTriangulation::calcEdges
54 const pointField& points
57 tmp<vectorField> tedges(new vectorField(f.size()));
58 vectorField& edges = tedges();
62 point thisPt = points[f[i]];
63 point nextPt = points[f[f.fcIndex(i)]];
65 vector vec(nextPt - thisPt);
66 vec /= mag(vec) + VSMALL;
75 // Calculates half angle components of angle from e0 to e1
76 void Foam::faceTriangulation::calcHalfAngle
85 // truncate cos to +-1 to prevent negative numbers
86 scalar cos = max(-1, min(1, e0 & e1));
88 scalar sin = (e0 ^ e1) & normal;
90 if (sin < -ROOTVSMALL)
92 // 3rd or 4th quadrant
93 cosHalfAngle = - Foam::sqrt(0.5*(1 + cos));
94 sinHalfAngle = Foam::sqrt(0.5*(1 - cos));
98 // 1st or 2nd quadrant
99 cosHalfAngle = Foam::sqrt(0.5*(1 + cos));
100 sinHalfAngle = Foam::sqrt(0.5*(1 - cos));
105 // Calculate intersection point between edge p1-p2 and ray (in 2D).
106 // Return true and intersection point if intersection between p1 and p2.
107 Foam::pointHit Foam::faceTriangulation::rayEdgeIntersect
109 const vector& normal,
110 const point& rayOrigin,
111 const vector& rayDir,
117 // Start off from miss
120 // Construct plane normal to rayDir and intersect
121 const vector y = normal ^ rayDir;
123 posOnEdge = plane(rayOrigin, y).normalIntersect(p1, (p2-p1));
125 // Check intersection to left of p1 or right of p2
126 if ((posOnEdge < 0) || (posOnEdge > 1))
132 // Check intersection behind rayOrigin
133 point intersectPt = p1 + posOnEdge * (p2 - p1);
135 if (((intersectPt - rayOrigin) & rayDir) < 0)
143 result.setPoint(intersectPt);
144 result.setDistance(mag(intersectPt - rayOrigin));
151 // Return true if triangle given its three points (anticlockwise ordered)
153 bool Foam::faceTriangulation::triangleContainsPoint
162 scalar area01Pt = triPointRef(p0, p1, pt).normal() & n;
163 scalar area12Pt = triPointRef(p1, p2, pt).normal() & n;
164 scalar area20Pt = triPointRef(p2, p0, pt).normal() & n;
166 if ((area01Pt > 0) && (area12Pt > 0) && (area20Pt > 0))
170 else if ((area01Pt < 0) && (area12Pt < 0) && (area20Pt < 0))
172 FatalErrorIn("triangleContainsPoint") << abort(FatalError);
182 // Starting from startIndex find diagonal. Return in index1, index2.
183 // Index1 always startIndex except when convex polygon
184 void Foam::faceTriangulation::findDiagonal
186 const pointField& points,
188 const vectorField& edges,
189 const vector& normal,
190 const label startIndex,
195 const point& startPt = points[f[startIndex]];
197 // Calculate angle at startIndex
198 const vector& rightE = edges[right(f.size(), startIndex)];
199 const vector leftE = -edges[left(f.size(), startIndex)];
201 // Construct ray which bisects angle
202 scalar cosHalfAngle = GREAT;
203 scalar sinHalfAngle = GREAT;
204 calcHalfAngle(normal, rightE, leftE, cosHalfAngle, sinHalfAngle);
208 + sinHalfAngle*(normal ^ rightE)
210 // rayDir should be normalized already but is not due to rounding errors
212 rayDir /= mag(rayDir) + VSMALL;
216 // Check all edges (apart from rightE and leftE) for nearest intersection
219 label faceVertI = f.fcIndex(startIndex);
221 pointHit minInter(false, vector::zero, GREAT, true);
223 scalar minPosOnEdge = GREAT;
225 for (label i = 0; i < f.size() - 2; i++)
234 points[f[faceVertI]],
235 points[f[f.fcIndex(faceVertI)]],
239 if (inter.hit() && inter.distance() < minInter.distance())
242 minIndex = faceVertI;
243 minPosOnEdge = posOnEdge;
246 faceVertI = f.fcIndex(faceVertI);
252 //WarningIn("faceTriangulation::findDiagonal")
253 // << "Could not find intersection starting from " << f[startIndex]
254 // << " for face " << f << endl;
261 const label leftIndex = minIndex;
262 const label rightIndex = f.fcIndex(minIndex);
264 // Now ray intersects edge from leftIndex to rightIndex.
265 // Check for intersection being one of the edge points. Make sure never
266 // to return two consecutive points.
268 if (mag(minPosOnEdge) < edgeRelTol && f.fcIndex(startIndex) != leftIndex)
277 mag(minPosOnEdge - 1) < edgeRelTol
278 && f.fcIndex(rightIndex) != startIndex
287 // Select visible vertex that minimizes
288 // angle to bisection. Visibility checking by checking if inside triangle
289 // formed by startIndex, leftIndex, rightIndex
291 const point& leftPt = points[f[leftIndex]];
292 const point& rightPt = points[f[rightIndex]];
295 scalar maxCos = -GREAT;
297 // all vertices except for startIndex and ones to left and right of it.
298 faceVertI = f.fcIndex(f.fcIndex(startIndex));
299 for (label i = 0; i < f.size() - 3; i++)
301 const point& pt = points[f[faceVertI]];
305 (faceVertI == leftIndex)
306 || (faceVertI == rightIndex)
307 || (triangleContainsPoint(normal, startPt, leftPt, rightPt, pt))
310 // pt inside triangle (so perhaps visible)
311 // Select based on minimal angle (so guaranteed visible).
312 vector edgePt0 = pt - startPt;
313 edgePt0 /= mag(edgePt0);
315 scalar cos = rayDir & edgePt0;
319 minIndex = faceVertI;
322 faceVertI = f.fcIndex(faceVertI);
327 // no vertex found. Return startIndex and one of the intersected edge
331 if (f.fcIndex(startIndex) != leftIndex)
348 // Find label of vertex to start splitting from. Is:
349 // 1] flattest concave angle
350 // 2] flattest convex angle if no concave angles.
351 Foam::label Foam::faceTriangulation::findStart
354 const vectorField& edges,
358 const label size = f.size();
360 scalar minCos = GREAT;
365 const vector& rightEdge = edges[right(size, fp)];
366 const vector leftEdge = -edges[left(size, fp)];
368 if (((rightEdge ^ leftEdge) & normal) < ROOTVSMALL)
370 scalar cos = rightEdge & leftEdge;
381 // No concave angle found. Get flattest convex angle
386 const vector& rightEdge = edges[right(size, fp)];
387 const vector leftEdge = -edges[left(size, fp)];
389 scalar cos = rightEdge & leftEdge;
402 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
404 // Split face f into triangles. Handles all simple (convex & concave)
406 bool Foam::faceTriangulation::split
409 const pointField& points,
411 const vector& normal,
415 const label size = f.size();
421 "split(const bool, const pointField&, const face&"
422 ", const vector&, label&)"
423 ) << "Illegal face:" << f
424 << " with points " << UIndirectList<point>(points, f)()
431 // Triangle. Just copy.
432 triFace& tri = operator[](triI++);
441 // General case. Start splitting for -flattest concave angle
442 // -or flattest convex angle if no concave angles.
444 tmp<vectorField> tedges(calcEdges(f, points));
445 const vectorField& edges = tedges();
447 label startIndex = findStart(f, edges, normal);
449 // Find diagonal to split face across
466 if (index1 != -1 && index2 != -1)
468 // Found correct diagonal
472 // Try splitting from next startingIndex.
473 startIndex = f.fcIndex(startIndex);
476 if (index1 == -1 || index2 == -1)
480 // Do naive triangulation. Find smallest angle to start
481 // triangulating from.
483 scalar maxCos = -GREAT;
487 const vector& rightEdge = edges[right(size, fp)];
488 const vector leftEdge = -edges[left(size, fp)];
490 scalar cos = rightEdge & leftEdge;
500 "split(const bool, const pointField&, const face&"
501 ", const vector&, label&)"
502 ) << "Cannot find valid diagonal on face " << f
503 << " with points " << UIndirectList<point>(points, f)()
505 << "Returning naive triangulation starting from "
506 << f[maxIndex] << " which might not be correct for a"
507 << " concave or warped face" << endl;
510 label fp = f.fcIndex(maxIndex);
512 for (label i = 0; i < size-2; i++)
514 label nextFp = f.fcIndex(fp);
516 triFace& tri = operator[](triI++);
517 tri[0] = f[maxIndex];
530 "split(const bool, const pointField&, const face&"
531 ", const vector&, label&)"
532 ) << "Cannot find valid diagonal on face " << f
533 << " with points " << UIndirectList<point>(points, f)()
535 << "Returning empty triFaceList" << endl;
542 // Split into two subshapes.
543 // face1: index1 to index2
544 // face2: index2 to index1
546 // Get sizes of the two subshapes
550 diff = index2 - index1;
555 diff = index2 + size - index1;
558 label nPoints1 = diff + 1;
559 label nPoints2 = size - diff + 1;
561 if (nPoints1 == size || nPoints2 == size)
565 "split(const bool, const pointField&, const face&"
566 ", const vector&, label&)"
567 ) << "Illegal split of face:" << f
568 << " with points " << UIndirectList<point>(points, f)()
569 << " at indices " << index1 << " and " << index2
570 << abort(FatalError);
574 // Collect face1 points
575 face face1(nPoints1);
577 label faceVertI = index1;
578 for (int i = 0; i < nPoints1; i++)
580 face1[i] = f[faceVertI];
581 faceVertI = f.fcIndex(faceVertI);
584 // Collect face2 points
585 face face2(nPoints2);
588 for (int i = 0; i < nPoints2; i++)
590 face2[i] = f[faceVertI];
591 faceVertI = f.fcIndex(faceVertI);
594 // Decompose the split faces
595 //Pout<< "Split face:" << f << " into " << face1 << " and " << face2
597 //string oldPrefix(Pout.prefix());
598 //Pout.prefix() = " " + oldPrefix;
601 split(fallBack, points, face1, normal, triI)
602 && split(fallBack, points, face2, normal, triI);
604 //Pout.prefix() = oldPrefix;
611 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
614 Foam::faceTriangulation::faceTriangulation()
620 // Construct from components
621 Foam::faceTriangulation::faceTriangulation
623 const pointField& points,
628 triFaceList(f.size()-2)
630 vector avgNormal = f.normal(points);
631 avgNormal /= mag(avgNormal) + VSMALL;
635 bool valid = split(fallBack, points, f, avgNormal, triI);
644 // Construct from components
645 Foam::faceTriangulation::faceTriangulation
647 const pointField& points,
653 triFaceList(f.size()-2)
657 bool valid = split(fallBack, points, f, n, triI);
666 // Construct from Istream
667 Foam::faceTriangulation::faceTriangulation(Istream& is)
673 // ************************************************************************* //