1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 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
27 \*---------------------------------------------------------------------------*/
29 #include "orientedSurface.H"
30 #include "triSurfaceTools.H"
31 #include "treeBoundBox.H"
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 defineTypeNameAndDebug(Foam::orientedSurface, 0);
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 // Return true if face uses edge from start to end.
41 bool Foam::orientedSurface::edgeOrder
49 (f[0] == e[0] && f[1] == e[1])
50 || (f[1] == e[0] && f[2] == e[1])
51 || (f[2] == e[0] && f[0] == e[1])
63 // Return true if edge is used in opposite order in faces
64 bool Foam::orientedSurface::consistentEdge
67 const labelledTri& f0,
71 return edgeOrder(f0, e) ^ edgeOrder(f1, e);
75 Foam::labelList Foam::orientedSurface::faceToEdge
78 const labelList& changedFaces
81 labelList changedEdges(3*changedFaces.size());
84 forAll(changedFaces, i)
86 const labelList& fEdges = s.faceEdges()[changedFaces[i]];
90 changedEdges[changedI++] = fEdges[j];
93 changedEdges.setSize(changedI);
99 Foam::labelList Foam::orientedSurface::edgeToFace
102 const labelList& changedEdges,
106 labelList changedFaces(2*changedEdges.size());
109 forAll(changedEdges, i)
111 label edgeI = changedEdges[i];
113 const labelList& eFaces = s.edgeFaces()[edgeI];
115 if (eFaces.size() < 2)
117 // Do nothing, faces was already visited.
119 else if (eFaces.size() == 2)
121 label face0 = eFaces[0];
122 label face1 = eFaces[1];
124 const labelledTri& f0 = s.localFaces()[face0];
125 const labelledTri& f1 = s.localFaces()[face1];
127 if (flip[face0] == UNVISITED)
129 if (flip[face1] == UNVISITED)
131 FatalErrorIn("orientedSurface::edgeToFace") << "Problem"
132 << abort(FatalError);
136 // Face1 has a flip state, face0 hasn't
137 if (consistentEdge(s.edges()[edgeI], f0, f1))
139 // Take over flip status
140 flip[face0] = (flip[face1] == FLIP ? FLIP : NOFLIP);
145 flip[face0] = (flip[face1] == FLIP ? NOFLIP : FLIP);
147 changedFaces[changedI++] = face0;
152 if (flip[face1] == UNVISITED)
154 // Face0 has a flip state, face1 hasn't
155 if (consistentEdge(s.edges()[edgeI], f0, f1))
157 flip[face1] = (flip[face0] == FLIP ? FLIP : NOFLIP);
161 flip[face1] = (flip[face0] == FLIP ? NOFLIP : FLIP);
163 changedFaces[changedI++] = face1;
169 // Multiply connected. Do what?
172 changedFaces.setSize(changedI);
178 void Foam::orientedSurface::walkSurface
181 const label startFaceI,
185 // List of faces that were changed in the last iteration.
186 labelList changedFaces(1, startFaceI);
187 // List of edges that were changed in the last iteration.
188 labelList changedEdges;
192 changedEdges = faceToEdge(s, changedFaces);
196 Pout<< "From changedFaces:" << changedFaces.size()
197 << " to changedEdges:" << changedEdges.size()
201 if (changedEdges.empty())
206 changedFaces = edgeToFace(s, changedEdges, flipState);
210 Pout<< "From changedEdges:" << changedEdges.size()
211 << " to changedFaces:" << changedFaces.size()
215 if (changedFaces.empty())
223 void Foam::orientedSurface::propagateOrientation
226 const point& samplePoint,
227 const bool orientOutside,
228 const label nearestFaceI,
229 const point& nearestPt,
234 // Determine orientation to normal on nearest face
236 triSurfaceTools::sideType side = triSurfaceTools::surfaceSide
245 if (side == triSurfaceTools::UNKNOWN)
247 // Non-closed surface. Do what? For now behave as if no flipping
249 flipState[nearestFaceI] = NOFLIP;
251 else if ((side == triSurfaceTools::OUTSIDE) == orientOutside)
253 // outside & orientOutside or inside & !orientOutside
254 // Normals on surface pointing correctly. No need to flip normals
255 flipState[nearestFaceI] = NOFLIP;
259 // Need to flip normals.
260 flipState[nearestFaceI] = FLIP;
265 vector n = triSurfaceTools::surfaceNormal(s, nearestFaceI, nearestPt);
267 Pout<< "orientedSurface::propagateOrientation : starting face"
268 << " orientation:" << nl
269 << " for samplePoint:" << samplePoint << nl
270 << " starting from point:" << nearestPt << nl
271 << " on face:" << nearestFaceI << nl
272 << " with normal:" << n << nl
273 << " decided side:" << label(side)
277 // Walk the surface from nearestFaceI, changing the flipstate.
278 walkSurface(s, nearestFaceI, flipState);
282 bool Foam::orientedSurface::flipSurface
285 const labelList& flipState
288 bool hasFlipped = false;
291 forAll(flipState, faceI)
293 if (flipState[faceI] == UNVISITED)
297 "orientSurface(const point&, const label, const point&)"
298 ) << "unvisited face " << faceI
299 << abort(FatalError);
301 else if (flipState[faceI] == FLIP)
303 labelledTri& tri = s[faceI];
313 // Recalculate normals
320 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
323 Foam::orientedSurface::orientedSurface()
329 // Construct from surface and point which defines outside
330 Foam::orientedSurface::orientedSurface
332 const triSurface& surf,
333 const point& samplePoint,
334 const bool orientOutside
339 orient(*this, samplePoint, orientOutside);
343 // Construct from surface. Calculate outside point.
344 Foam::orientedSurface::orientedSurface
346 const triSurface& surf,
347 const bool orientOutside
352 // BoundBox calculation without localPoints
353 treeBoundBox bb(surf.points(), surf.meshPoints());
355 point outsidePoint = bb.max() + bb.span();
357 orient(*this, outsidePoint, orientOutside);
361 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
363 bool Foam::orientedSurface::orient
366 const point& samplePoint,
367 const bool orientOutside
370 bool anyFlipped = false;
372 // Do initial flipping to make triangles consistent. Otherwise if the
373 // nearest is e.g. on an edge inbetween inconsistent triangles it might
374 // make the wrong decision.
377 // Whether face has to be flipped.
378 // UNVISITED: unvisited
379 // NOFLIP: no need to flip
380 // FLIP: need to flip
381 labelList flipState(s.size(), UNVISITED);
383 flipState[0] = NOFLIP;
384 walkSurface(s, 0, flipState);
386 anyFlipped = flipSurface(s, flipState);
390 // Whether face has to be flipped.
391 // UNVISITED: unvisited
392 // NOFLIP: no need to flip
393 // FLIP: need to flip
394 labelList flipState(s.size(), UNVISITED);
399 // Linear search for nearest unvisited point on surface.
401 scalar minDist = GREAT;
407 if (flipState[faceI] == UNVISITED)
409 const labelledTri& f = s[faceI];
417 ).nearestPoint(samplePoint);
419 if (curHit.distance() < minDist)
421 minDist = curHit.distance();
422 minPoint = curHit.rawPoint();
428 // Did we find anything?
434 // From this nearest face see if needs to be flipped and then
447 // Now finally flip triangles according to flipState.
448 bool geomFlipped = flipSurface(s, flipState);
450 return anyFlipped || geomFlipped;
454 // ************************************************************************* //