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 \*---------------------------------------------------------------------------*/
28 #include "triPointRef.H"
29 #include "mathematicalConstants.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 const char* const Foam::face::typeName = "face";
35 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
37 Foam::tmp<Foam::vectorField>
38 Foam::face::calcEdges(const pointField& points) const
40 tmp<vectorField> tedges(new vectorField(size()));
41 vectorField& edges = tedges();
45 label ni = fcIndex(i);
47 point thisPt = points[operator[](i)];
48 point nextPt = points[operator[](ni)];
50 vector vec(nextPt - thisPt);
51 vec /= Foam::mag(vec) + VSMALL;
60 Foam::scalar Foam::face::edgeCos
62 const vectorField& edges,
66 label leftEdgeI = left(index);
67 label rightEdgeI = right(index);
69 // note negate on left edge to get correct left-pointing edge.
70 return -(edges[leftEdgeI] & edges[rightEdgeI]);
74 Foam::label Foam::face::mostConcaveAngle
76 const pointField& points,
77 const vectorField& edges,
81 vector n(normal(points));
88 label leftEdgeI = left(i);
89 label rightEdgeI = right(i);
91 vector edgeNormal = edges[rightEdgeI] ^ edges[leftEdgeI];
93 scalar edgeCos = edges[leftEdgeI] & edges[rightEdgeI];
94 scalar edgeAngle = acos(max(-1.0, min(1.0, edgeCos)));
98 if ((edgeNormal & n) > 0)
101 angle = mathematicalConstant::pi + edgeAngle;
105 // Convex angle. Note '-' to take into account that rightEdge
106 // and leftEdge are head-to-tail connected.
107 angle = mathematicalConstant::pi - edgeAngle;
110 if (angle > maxAngle)
121 void Foam::face::split
123 const face::splitMode mode,
124 const pointField& points,
136 "(const face::splitMode, const pointField&, label&, label&"
137 ", faceList&, faceList&)"
139 << "Serious problem: asked to split a face with < 3 vertices"
140 << abort(FatalError);
144 // Triangle. Just copy.
145 if ((mode == COUNTQUAD) || (mode == COUNTTRIANGLE))
151 triFaces[triI++] = *this;
154 else if (size() == 4)
156 if (mode == COUNTTRIANGLE)
160 if (mode == COUNTQUAD)
164 else if (mode == SPLITTRIANGLE)
166 // Start at point with largest internal angle.
167 const vectorField edges(calcEdges(points));
170 label startIndex = mostConcaveAngle(points, edges, minAngle);
172 label nextIndex = fcIndex(startIndex);
173 label splitIndex = fcIndex(nextIndex);
177 triFace[0] = operator[](startIndex);
178 triFace[1] = operator[](nextIndex);
179 triFace[2] = operator[](splitIndex);
181 triFaces[triI++] = triFace;
183 triFace[0] = operator[](splitIndex);
184 triFace[1] = operator[](fcIndex(splitIndex));
185 triFace[2] = operator[](startIndex);
187 triFaces[triI++] = triFace;
191 quadFaces[quadI++] = *this;
196 // General case. Like quad: search for largest internal angle.
198 const vectorField edges(calcEdges(points));
201 label startIndex = mostConcaveAngle(points, edges, minAngle);
203 scalar bisectAngle = minAngle/2;
204 vector rightEdge = edges[right(startIndex)];
207 // Look for opposite point which as close as possible bisects angle
210 // split candidate starts two points away.
211 label index = fcIndex(fcIndex(startIndex));
213 label minIndex = index;
214 scalar minDiff = Foam::mathematicalConstant::pi;
216 for(label i = 0; i < size() - 3; i++)
220 points[operator[](index)]
221 - points[operator[](startIndex)]
223 splitEdge /= Foam::mag(splitEdge) + VSMALL;
225 const scalar splitCos = splitEdge & rightEdge;
226 const scalar splitAngle = acos(max(-1.0, min(1.0, splitCos)));
227 const scalar angleDiff = fabs(splitAngle - bisectAngle);
229 if (angleDiff < minDiff)
235 // go to next candidate
236 index = fcIndex(index);
240 // Split into two subshapes.
241 // face1: startIndex to minIndex
242 // face2: minIndex to startIndex
244 // Get sizes of the two subshapes
246 if (minIndex > startIndex)
248 diff = minIndex - startIndex;
253 diff = minIndex + size() - startIndex;
256 label nPoints1 = diff + 1;
257 label nPoints2 = size() - diff + 1;
259 // Collect face1 points
260 face face1(nPoints1);
263 for (label i = 0; i < nPoints1; i++)
265 face1[i] = operator[](index);
266 index = fcIndex(index);
269 // Collect face2 points
270 face face2(nPoints2);
273 for (label i = 0; i < nPoints2; i++)
275 face2[i] = operator[](index);
276 index = fcIndex(index);
280 face1.split(mode, points, triI, quadI, triFaces, quadFaces);
281 face2.split(mode, points, triI, quadI, triFaces, quadFaces);
286 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
292 // -1: same face, but different orientation
293 int Foam::face::compare(const face& a, const face& b)
295 // Basic rule: we assume that the sequence of labels in each list
296 // will be circular in the same order (but not necessarily in the
297 // same direction or from the same starting point).
299 // Trivial reject: faces are different size
300 label sizeA = a.size();
301 label sizeB = b.size();
309 // Full list comparison
310 const label firstA = a[0];
317 Bptr = i; // 'found match' at element 'i'
322 // If no match was found, return 0
328 // Now we must look for the direction, if any
329 label secondA = a[1];
331 if (sizeA > 1 && (secondA == firstA || firstA == a[sizeA - 1]))
339 return face::compare(ca, cb);
344 // Check whether at top of list
346 if (Bptr == b.size())
351 // Test whether upward label matches second A label
352 if (b[Bptr] == secondA)
354 // Yes - direction is 'up'
359 // No - so look downwards, checking whether at bottom of list
368 // Test whether downward label matches second A label
369 if (b[Bptr] == secondA)
371 // Yes - direction is 'down'
376 // Check whether a match was made at all, and exit 0 if not
382 // Decrement size by 2 to account for first searches
385 // We now have both direction of search and next element
386 // to search, so we can continue search until no more points.
393 if (Aptr >= a.size())
399 if (Bptr >= b.size())
404 if (a[Aptr] != b[Bptr])
415 if (Aptr >= a.size())
426 if (a[Aptr] != b[Bptr])
433 // They must be equal - return direction
438 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
441 Foam::label Foam::face::collapse()
446 for (label i=1; i<size(); i++)
448 if (operator[](i) != operator[](ci))
450 operator[](++ci) = operator[](i);
454 if (operator[](ci) != operator[](0))
466 Foam::point Foam::face::centre(const pointField& meshPoints) const
468 // Calculate the centre by breaking the face into triangles and
469 // area-weighted averaging their centres
471 // If the face is a triangle, do a direct calculation
477 meshPoints[operator[](0)]
478 + meshPoints[operator[](1)]
479 + meshPoints[operator[](2)]
483 label nPoints = size();
485 point centrePoint = point::zero;
486 for (register label pI=0; pI<nPoints; pI++)
488 centrePoint += meshPoints[operator[](pI)];
490 centrePoint /= nPoints;
493 vector sumAc = vector::zero;
495 for (register label pI=0; pI<nPoints; pI++)
497 const point& nextPoint = meshPoints[operator[]((pI + 1) % nPoints)];
499 // Calculate 3*triangle centre
502 meshPoints[operator[](pI)]
507 // Calculate 2*triangle area
508 scalar ta = Foam::mag
510 (meshPoints[operator[](pI)] - centrePoint)
511 ^ (nextPoint - centrePoint)
520 return sumAc/(3*sumA);
529 Foam::vector Foam::face::normal(const pointField& meshPoints) const
531 // Calculate the normal by summing the face triangle normals.
532 // Changed to deal with small concavity by using a central decomposition
535 // If the face is a triangle, do a direct calculation to avoid round-off
536 // error-related problems
542 meshPoints[operator[](0)],
543 meshPoints[operator[](1)],
544 meshPoints[operator[](2)]
548 vector n = vector::zero;
550 point centrePoint = Foam::average(points(meshPoints));
552 label nPoints = size();
554 point nextPoint = centrePoint;
558 for (pI = 0; pI < nPoints; pI++)
560 if (pI < nPoints - 1)
562 nextPoint = meshPoints[operator[](pI + 1)];
566 nextPoint = meshPoints[operator[](0)];
569 // Note: for best accuracy, centre point always comes last
573 meshPoints[operator[](pI)],
583 Foam::face Foam::face::reverseFace() const
585 // reverse the label list and return
586 // Changed to make sure that the starting point of the original
587 // and the reverse face is identical.
590 const labelList& myList = *this;
592 labelList newList(size());
594 newList[0] = myList[0];
596 for (label pointI = 1; pointI < newList.size(); pointI++)
598 newList[pointI] = myList[size() - pointI];
601 return face(newList);
605 Foam::label Foam::face::which(const label globalIndex) const
607 label pointInFace = -1;
608 const labelList& f = *this;
612 if (f[i] == globalIndex)
623 Foam::scalar Foam::face::sweptVol
625 const pointField& oldPoints,
626 const pointField& newPoints
631 // Calculate the swept volume by breaking the face into triangles and
632 // summing their swept volumes.
633 // Changed to deal with small concavity by using a central decomposition
635 point centreOldPoint = centre(oldPoints);
636 point centreNewPoint = centre(newPoints);
638 label nPoints = size();
640 point nextOldPoint = centreOldPoint;
642 point nextNewPoint = centreNewPoint;
646 for (pI = 0; pI < nPoints; pI++)
648 if (pI < nPoints - 1)
650 nextOldPoint = oldPoints[operator[](pI + 1)];
651 nextNewPoint = newPoints[operator[](pI + 1)];
655 nextOldPoint = oldPoints[operator[](0)];
656 nextNewPoint = newPoints[operator[](0)];
659 // Note: for best accuracy, centre point always comes last
663 oldPoints[operator[](pI)],
670 newPoints[operator[](pI)],
680 Foam::edgeList Foam::face::edges() const
682 const labelList& points = *this;
684 edgeList e(points.size());
688 for (pointI = 0; pointI < points.size() - 1; pointI++)
690 e[pointI] = edge(points[pointI], points[pointI + 1]);
694 e[points.size() - 1] = edge(points[points.size() - 1], points[0]);
700 int Foam::face::edgeDirection(const edge& e) const
706 // find start/end points - this breaks down for degenerate faces
709 if (operator[](i) == e.start())
713 else if (operator[](i) == e.end())
719 label diff = found.end() - found.start();
720 if (!diff || found.start() < 0 || found.end() < 0)
726 if (diff == 1 || diff == 1 - size())
731 if (diff == -1 || diff == -1 + size())
741 // Number of triangles directly known from number of vertices
742 Foam::label Foam::face::nTriangles
751 void Foam::face::triangles
753 const pointField& points,
761 split(SPLITTRIANGLE, points, triI, quadI, triFaces, quadFaces);
765 void Foam::face::nTrianglesQuads
767 const pointField& points,
775 split(COUNTQUAD, points, triI, quadI, triFaces, quadFaces);
779 void Foam::face::trianglesQuads
781 const pointField& points,
788 split(SPLITQUAD, points, triI, quadI, triFaces, quadFaces);
792 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
795 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
797 // ************************************************************************* //