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 "orientedSurface.H"
27 #include "triSurfaceTools.H"
28 #include "treeBoundBox.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 defineTypeNameAndDebug(Foam::orientedSurface, 0);
35 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
37 // Return true if edge is used in opposite order in faces
38 bool Foam::orientedSurface::consistentEdge
41 const triSurface::FaceType& f0,
42 const triSurface::FaceType& f1
45 return (f0.edgeDirection(e) > 0) ^ (f1.edgeDirection(e) > 0);
49 Foam::labelList Foam::orientedSurface::faceToEdge
52 const labelList& changedFaces
55 labelList changedEdges(3*changedFaces.size());
58 forAll(changedFaces, i)
60 const labelList& fEdges = s.faceEdges()[changedFaces[i]];
64 changedEdges[changedI++] = fEdges[j];
67 changedEdges.setSize(changedI);
73 Foam::labelList Foam::orientedSurface::edgeToFace
76 const labelList& changedEdges,
80 labelList changedFaces(2*changedEdges.size());
83 forAll(changedEdges, i)
85 label edgeI = changedEdges[i];
87 const labelList& eFaces = s.edgeFaces()[edgeI];
89 if (eFaces.size() < 2)
91 // Do nothing, faces was already visited.
93 else if (eFaces.size() == 2)
95 label face0 = eFaces[0];
96 label face1 = eFaces[1];
98 const triSurface::FaceType& f0 = s.localFaces()[face0];
99 const triSurface::FaceType& f1 = s.localFaces()[face1];
101 if (flip[face0] == UNVISITED)
103 if (flip[face1] == UNVISITED)
105 FatalErrorIn("orientedSurface::edgeToFace") << "Problem"
106 << abort(FatalError);
110 // Face1 has a flip state, face0 hasn't
111 if (consistentEdge(s.edges()[edgeI], f0, f1))
113 // Take over flip status
114 flip[face0] = (flip[face1] == FLIP ? FLIP : NOFLIP);
119 flip[face0] = (flip[face1] == FLIP ? NOFLIP : FLIP);
121 changedFaces[changedI++] = face0;
126 if (flip[face1] == UNVISITED)
128 // Face0 has a flip state, face1 hasn't
129 if (consistentEdge(s.edges()[edgeI], f0, f1))
131 flip[face1] = (flip[face0] == FLIP ? FLIP : NOFLIP);
135 flip[face1] = (flip[face0] == FLIP ? NOFLIP : FLIP);
137 changedFaces[changedI++] = face1;
143 // Multiply connected. Do what?
146 changedFaces.setSize(changedI);
152 void Foam::orientedSurface::walkSurface
155 const label startFaceI,
159 // List of faces that were changed in the last iteration.
160 labelList changedFaces(1, startFaceI);
161 // List of edges that were changed in the last iteration.
162 labelList changedEdges;
166 changedEdges = faceToEdge(s, changedFaces);
170 Pout<< "From changedFaces:" << changedFaces.size()
171 << " to changedEdges:" << changedEdges.size()
175 if (changedEdges.empty())
180 changedFaces = edgeToFace(s, changedEdges, flipState);
184 Pout<< "From changedEdges:" << changedEdges.size()
185 << " to changedFaces:" << changedFaces.size()
189 if (changedFaces.empty())
197 void Foam::orientedSurface::propagateOrientation
200 const point& samplePoint,
201 const bool orientOutside,
202 const label nearestFaceI,
203 const point& nearestPt,
208 // Determine orientation to normal on nearest face
210 triSurfaceTools::sideType side = triSurfaceTools::surfaceSide
217 if (side == triSurfaceTools::UNKNOWN)
219 // Non-closed surface. Do what? For now behave as if no flipping
221 flipState[nearestFaceI] = NOFLIP;
223 else if ((side == triSurfaceTools::OUTSIDE) == orientOutside)
225 // outside & orientOutside or inside & !orientOutside
226 // Normals on surface pointing correctly. No need to flip normals
227 flipState[nearestFaceI] = NOFLIP;
231 // Need to flip normals.
232 flipState[nearestFaceI] = FLIP;
237 vector n = triSurfaceTools::surfaceNormal(s, nearestFaceI, nearestPt);
239 Pout<< "orientedSurface::propagateOrientation : starting face"
240 << " orientation:" << nl
241 << " for samplePoint:" << samplePoint << nl
242 << " starting from point:" << nearestPt << nl
243 << " on face:" << nearestFaceI << nl
244 << " with normal:" << n << nl
245 << " decided side:" << label(side)
249 // Walk the surface from nearestFaceI, changing the flipstate.
250 walkSurface(s, nearestFaceI, flipState);
254 bool Foam::orientedSurface::flipSurface
257 const labelList& flipState
260 bool hasFlipped = false;
263 forAll(flipState, faceI)
265 if (flipState[faceI] == UNVISITED)
269 "orientSurface(const point&, const label, const point&)"
270 ) << "unvisited face " << faceI
271 << abort(FatalError);
273 else if (flipState[faceI] == FLIP)
275 labelledTri& tri = s[faceI];
285 // Recalculate normals
292 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
295 Foam::orientedSurface::orientedSurface()
301 // Construct from surface and point which defines outside
302 Foam::orientedSurface::orientedSurface
304 const triSurface& surf,
305 const point& samplePoint,
306 const bool orientOutside
311 orient(*this, samplePoint, orientOutside);
315 // Construct from surface. Calculate outside point.
316 Foam::orientedSurface::orientedSurface
318 const triSurface& surf,
319 const bool orientOutside
324 // BoundBox calculation without localPoints
325 treeBoundBox bb(surf.points(), surf.meshPoints());
327 point outsidePoint = bb.max() + bb.span();
329 orient(*this, outsidePoint, orientOutside);
333 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
335 bool Foam::orientedSurface::orient
338 const point& samplePoint,
339 const bool orientOutside
342 bool anyFlipped = false;
344 // Do initial flipping to make triangles consistent. Otherwise if the
345 // nearest is e.g. on an edge inbetween inconsistent triangles it might
346 // make the wrong decision.
349 // Whether face has to be flipped.
350 // UNVISITED: unvisited
351 // NOFLIP: no need to flip
352 // FLIP: need to flip
353 labelList flipState(s.size(), UNVISITED);
355 flipState[0] = NOFLIP;
356 walkSurface(s, 0, flipState);
358 anyFlipped = flipSurface(s, flipState);
362 // Whether face has to be flipped.
363 // UNVISITED: unvisited
364 // NOFLIP: no need to flip
365 // FLIP: need to flip
366 labelList flipState(s.size(), UNVISITED);
371 // Linear search for nearest unvisited point on surface.
373 scalar minDist = GREAT;
379 if (flipState[faceI] == UNVISITED)
382 s[faceI].nearestPoint(samplePoint, s.points());
384 if (curHit.distance() < minDist)
386 minDist = curHit.distance();
387 minPoint = curHit.rawPoint();
393 // Did we find anything?
399 // From this nearest face see if needs to be flipped and then
412 // Now finally flip triangles according to flipState.
413 bool geomFlipped = flipSurface(s, flipState);
415 return anyFlipped || geomFlipped;
419 // ************************************************************************* //