1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2011 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
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 \*---------------------------------------------------------------------------*/
28 #include "triPointRef.H"
29 #include "mathematicalConstants.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 const char* const Foam::face::typeName = "face";
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 Foam::tmp<Foam::vectorField>
40 Foam::face::calcEdges(const pointField& points) const
42 tmp<vectorField> tedges(new vectorField(size()));
43 vectorField& edges = tedges();
47 label ni = fcIndex(i);
49 point thisPt = points[operator[](i)];
50 point nextPt = points[operator[](ni)];
52 vector vec(nextPt - thisPt);
53 vec /= Foam::mag(vec) + VSMALL;
62 Foam::scalar Foam::face::edgeCos
64 const vectorField& edges,
68 label leftEdgeI = left(index);
69 label rightEdgeI = right(index);
71 // note negate on left edge to get correct left-pointing edge.
72 return -(edges[leftEdgeI] & edges[rightEdgeI]);
76 Foam::label Foam::face::mostConcaveAngle
78 const pointField& points,
79 const vectorField& edges,
83 vector n(normal(points));
90 label leftEdgeI = left(i);
91 label rightEdgeI = right(i);
93 vector edgeNormal = edges[rightEdgeI] ^ edges[leftEdgeI];
95 scalar edgeCos = edges[leftEdgeI] & edges[rightEdgeI];
96 scalar edgeAngle = acos(max(-1.0, min(1.0, edgeCos)));
100 if ((edgeNormal & n) > 0)
103 angle = constant::mathematical::pi + edgeAngle;
107 // Convex angle. Note '-' to take into account that rightEdge
108 // and leftEdge are head-to-tail connected.
109 angle = constant::mathematical::pi - edgeAngle;
112 if (angle > maxAngle)
123 Foam::label Foam::face::split
125 const face::splitMode mode,
126 const pointField& points,
133 label oldIndices = (triI + quadI);
140 "(const face::splitMode, const pointField&, label&, label&"
141 ", faceList&, faceList&)"
143 << "Serious problem: asked to split a face with < 3 vertices"
144 << abort(FatalError);
148 // Triangle. Just copy.
149 if (mode == COUNTTRIANGLE || mode == COUNTQUAD)
155 triFaces[triI++] = *this;
158 else if (size() == 4)
160 if (mode == COUNTTRIANGLE)
164 if (mode == COUNTQUAD)
168 else if (mode == SPLITTRIANGLE)
170 // Start at point with largest internal angle.
171 const vectorField edges(calcEdges(points));
174 label startIndex = mostConcaveAngle(points, edges, minAngle);
176 label nextIndex = fcIndex(startIndex);
177 label splitIndex = fcIndex(nextIndex);
181 triFace[0] = operator[](startIndex);
182 triFace[1] = operator[](nextIndex);
183 triFace[2] = operator[](splitIndex);
185 triFaces[triI++] = triFace;
187 triFace[0] = operator[](splitIndex);
188 triFace[1] = operator[](fcIndex(splitIndex));
189 triFace[2] = operator[](startIndex);
191 triFaces[triI++] = triFace;
195 quadFaces[quadI++] = *this;
200 // General case. Like quad: search for largest internal angle.
202 const vectorField edges(calcEdges(points));
205 label startIndex = mostConcaveAngle(points, edges, minAngle);
207 scalar bisectAngle = minAngle/2;
208 vector rightEdge = edges[right(startIndex)];
211 // Look for opposite point which as close as possible bisects angle
214 // split candidate starts two points away.
215 label index = fcIndex(fcIndex(startIndex));
217 label minIndex = index;
218 scalar minDiff = constant::mathematical::pi;
220 for (label i = 0; i < size() - 3; i++)
224 points[operator[](index)]
225 - points[operator[](startIndex)]
227 splitEdge /= Foam::mag(splitEdge) + VSMALL;
229 const scalar splitCos = splitEdge & rightEdge;
230 const scalar splitAngle = acos(max(-1.0, min(1.0, splitCos)));
231 const scalar angleDiff = fabs(splitAngle - bisectAngle);
233 if (angleDiff < minDiff)
239 // go to next candidate
240 index = fcIndex(index);
244 // Split into two subshapes.
245 // face1: startIndex to minIndex
246 // face2: minIndex to startIndex
248 // Get sizes of the two subshapes
250 if (minIndex > startIndex)
252 diff = minIndex - startIndex;
257 diff = minIndex + size() - startIndex;
260 label nPoints1 = diff + 1;
261 label nPoints2 = size() - diff + 1;
263 // Collect face1 points
264 face face1(nPoints1);
267 for (label i = 0; i < nPoints1; i++)
269 face1[i] = operator[](index);
270 index = fcIndex(index);
273 // Collect face2 points
274 face face2(nPoints2);
277 for (label i = 0; i < nPoints2; i++)
279 face2[i] = operator[](index);
280 index = fcIndex(index);
284 face1.split(mode, points, triI, quadI, triFaces, quadFaces);
285 face2.split(mode, points, triI, quadI, triFaces, quadFaces);
288 return (triI + quadI - oldIndices);
292 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
294 Foam::face::face(const triFace& f)
300 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
306 // -1: same face, but different orientation
307 int Foam::face::compare(const face& a, const face& b)
309 // Basic rule: we assume that the sequence of labels in each list
310 // will be circular in the same order (but not necessarily in the
311 // same direction or from the same starting point).
313 // Trivial reject: faces are different size
314 label sizeA = a.size();
315 label sizeB = b.size();
323 // Full list comparison
324 const label firstA = a[0];
331 Bptr = i; // 'found match' at element 'i'
336 // If no match was found, return 0
342 // Now we must look for the direction, if any
343 label secondA = a[1];
345 if (sizeA > 1 && (secondA == firstA || firstA == a[sizeA - 1]))
353 return face::compare(ca, cb);
358 // Check whether at top of list
360 if (Bptr == b.size())
365 // Test whether upward label matches second A label
366 if (b[Bptr] == secondA)
368 // Yes - direction is 'up'
373 // No - so look downwards, checking whether at bottom of list
382 // Test whether downward label matches second A label
383 if (b[Bptr] == secondA)
385 // Yes - direction is 'down'
390 // Check whether a match was made at all, and exit 0 if not
396 // Decrement size by 2 to account for first searches
399 // We now have both direction of search and next element
400 // to search, so we can continue search until no more points.
407 if (Aptr >= a.size())
413 if (Bptr >= b.size())
418 if (a[Aptr] != b[Bptr])
429 if (Aptr >= a.size())
440 if (a[Aptr] != b[Bptr])
447 // They must be equal - return direction
452 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
455 Foam::label Foam::face::collapse()
460 for (label i=1; i<size(); i++)
462 if (operator[](i) != operator[](ci))
464 operator[](++ci) = operator[](i);
468 if (operator[](ci) != operator[](0))
480 void Foam::face::flip()
482 const label n = size();
486 for (label i=1; i < (n+1)/2; ++i)
488 Swap(operator[](i), operator[](n-i));
494 Foam::point Foam::face::centre(const pointField& points) const
496 // Calculate the centre by breaking the face into triangles and
497 // area-weighted averaging their centres
499 const label nPoints = size();
501 // If the face is a triangle, do a direct calculation
507 points[operator[](0)]
508 + points[operator[](1)]
509 + points[operator[](2)]
514 point centrePoint = point::zero;
515 for (register label pI=0; pI<nPoints; ++pI)
517 centrePoint += points[operator[](pI)];
519 centrePoint /= nPoints;
522 vector sumAc = vector::zero;
524 for (register label pI=0; pI<nPoints; ++pI)
526 const point& nextPoint = points[operator[]((pI + 1) % nPoints)];
528 // Calculate 3*triangle centre
531 points[operator[](pI)]
536 // Calculate 2*triangle area
537 const scalar ta = Foam::mag
539 (points[operator[](pI)] - centrePoint)
540 ^ (nextPoint - centrePoint)
549 return sumAc/(3.0*sumA);
558 Foam::vector Foam::face::normal(const pointField& p) const
560 const label nPoints = size();
562 // Calculate the normal by summing the face triangle normals.
563 // Changed to deal with small concavity by using a central decomposition
566 // If the face is a triangle, do a direct calculation to avoid round-off
567 // error-related problems
581 point centrePoint = vector::zero;
582 for (pI = 0; pI < nPoints; ++pI)
584 centrePoint += p[operator[](pI)];
586 centrePoint /= nPoints;
588 vector n = vector::zero;
590 point nextPoint = centrePoint;
592 for (pI = 0; pI < nPoints; ++pI)
594 if (pI < nPoints - 1)
596 nextPoint = p[operator[](pI + 1)];
600 nextPoint = p[operator[](0)];
603 // Note: for best accuracy, centre point always comes last
617 Foam::face Foam::face::reverseFace() const
619 // reverse the label list and return
620 // The starting points of the original and reverse face are identical.
622 const labelList& f = *this;
623 labelList newList(size());
627 for (label pointI = 1; pointI < newList.size(); pointI++)
629 newList[pointI] = f[size() - pointI];
632 return face(xferMove(newList));
636 Foam::label Foam::face::which(const label globalIndex) const
638 const labelList& f = *this;
642 if (f[localIdx] == globalIndex)
652 Foam::scalar Foam::face::sweptVol
654 const pointField& oldPoints,
655 const pointField& newPoints
660 // Calculate the swept volume by breaking the face into triangles and
661 // summing their swept volumes.
662 // Changed to deal with small concavity by using a central decomposition
664 point centreOldPoint = centre(oldPoints);
665 point centreNewPoint = centre(newPoints);
667 label nPoints = size();
669 point nextOldPoint = centreOldPoint;
670 point nextNewPoint = centreNewPoint;
672 for (register label pI = 0; pI < nPoints; ++pI)
674 if (pI < nPoints - 1)
676 nextOldPoint = oldPoints[operator[](pI + 1)];
677 nextNewPoint = newPoints[operator[](pI + 1)];
681 nextOldPoint = oldPoints[operator[](0)];
682 nextNewPoint = newPoints[operator[](0)];
685 // Note: for best accuracy, centre point always comes last
689 oldPoints[operator[](pI)],
696 newPoints[operator[](pI)],
706 Foam::tensor Foam::face::inertia
713 // If the face is a triangle, do a direct calculation
721 ).inertia(refPt, density);
724 const point ctr = centre(p);
726 tensor J = tensor::zero;
733 p[operator[](fcIndex(i))],
735 ).inertia(refPt, density);
742 Foam::edgeList Foam::face::edges() const
744 const labelList& points = *this;
746 edgeList e(points.size());
748 for (label pointI = 0; pointI < points.size() - 1; ++pointI)
750 e[pointI] = edge(points[pointI], points[pointI + 1]);
754 e.last() = edge(points.last(), points[0]);
760 int Foam::face::edgeDirection(const edge& e) const
764 if (operator[](i) == e.start())
766 if (operator[](rcIndex(i)) == e.end())
771 else if (operator[](fcIndex(i)) == e.end())
780 else if (operator[](i) == e.end())
782 if (operator[](rcIndex(i)) == e.start())
787 else if (operator[](fcIndex(i)) == e.start())
803 // Number of triangles directly known from number of vertices
804 Foam::label Foam::face::nTriangles(const pointField&) const
810 Foam::label Foam::face::triangles
812 const pointField& points,
820 return split(SPLITTRIANGLE, points, triI, quadI, triFaces, quadFaces);
824 Foam::label Foam::face::nTrianglesQuads
826 const pointField& points,
834 return split(COUNTQUAD, points, triI, quadI, triFaces, quadFaces);
838 Foam::label Foam::face::trianglesQuads
840 const pointField& points,
847 return split(SPLITQUAD, points, triI, quadI, triFaces, quadFaces);
851 // ************************************************************************* //