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 "geomCellLooper.H"
28 #include "DynamicList.H"
30 #include "meshTools.H"
31 #include "SortableList.H"
32 #include "triSurfaceTools.H"
35 #include "transform.H"
37 #include "addToRunTimeSelectionTable.H"
40 // Extension factor of edges to make sure we catch intersections through
42 const Foam::scalar Foam::geomCellLooper::pointEqualTol_ = 1E-3;
45 // Snap cuts through edges onto edge endpoints. Fraction of edge length.
46 Foam::scalar Foam::geomCellLooper::snapTol_ = 0.1;
49 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
54 defineTypeNameAndDebug(geomCellLooper, 0);
55 addToRunTimeSelectionTable(cellLooper, geomCellLooper, word);
60 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
62 Foam::scalar Foam::geomCellLooper::minEdgeLen(const label vertI) const
64 scalar minLen = GREAT;
66 const labelList& pEdges = mesh().pointEdges()[vertI];
68 forAll(pEdges, pEdgeI)
70 const edge& e = mesh().edges()[pEdges[pEdgeI]];
72 minLen = min(minLen, e.mag(mesh().points()));
78 // Cut edge with plane. Return true and set weight to fraction between
79 // edge-start and edge-end
80 bool Foam::geomCellLooper::cutEdge
82 const plane& cutPlane,
87 const pointField& pts = mesh().points();
89 const edge& e = mesh().edges()[edgeI];
91 scalar s = cutPlane.normalIntersect(pts[e.start()], e.vec(pts));
93 if ((s > -pointEqualTol_) && (s < 1 + pointEqualTol_))
101 // Make sure we don't use this value
109 // If edge close enough to endpoint snap to endpoint.
110 Foam::label Foam::geomCellLooper::snapToVert
117 const edge& e = mesh().edges()[edgeI];
123 else if (weight > (1-tol))
134 void Foam::geomCellLooper::getBase(const vector& n, vector& e0, vector& e1)
137 // Guess for vector normal to n.
140 scalar nComp = n & base;
142 if (mag(nComp) > 0.8)
144 // Was bad guess. Try with different vector.
151 if (mag(nComp) > 0.8)
161 // Use component normal to n as base vector.
164 e0 /= mag(e0) + VSMALL;
168 //Pout<< "Coord system:" << endl
169 // << " n : " << n << ' ' << mag(n) << endl
170 // << " e0 : " << e0 << ' ' << mag(e0) << endl
171 // << " e1 : " << e1 << ' ' << mag(e1) << endl
176 // Return true if the cut edge at loop[index] is preceded by cuts through
177 // the edge end points.
178 bool Foam::geomCellLooper::edgeEndsCut
180 const labelList& loop,
184 label edgeI = getEdge(loop[index]);
186 const edge& e = mesh().edges()[edgeI];
188 const label prevCut = loop[loop.rcIndex(index)];
189 const label nextCut = loop[loop.fcIndex(index)];
191 if (!isEdge(prevCut) && !isEdge(nextCut))
193 // Cuts before and after are both vertices. Check if both
194 // the edge endpoints
195 label v0 = getVertex(prevCut);
196 label v1 = getVertex(nextCut);
200 (v0 == e[0] && v1 == e[1])
201 || (v0 == e[1] && v1 == e[0])
211 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
213 // Construct from components
214 Foam::geomCellLooper::geomCellLooper(const polyMesh& mesh)
220 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
222 Foam::geomCellLooper::~geomCellLooper()
226 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
228 bool Foam::geomCellLooper::cut
230 const vector& refDir,
232 const boolList& vertIsCut,
233 const boolList& edgeIsCut,
234 const scalarField& edgeWeight,
237 scalarField& loopWeights
240 // Cut through cell centre normal to refDir.
243 plane(mesh().cellCentres()[cellI], refDir),
254 bool Foam::geomCellLooper::cut
256 const plane& cutPlane,
263 scalarField& loopWeights
266 const pointField& points = mesh().points();
267 const edgeList& edges = mesh().edges();
269 // Find all cuts through edges.
271 // - edge cut close to endpoint. Snap to endpoint.
272 // - edge endpoint close to plane (but edge not cut). Snap to endpoint.
273 // - both endpoints close to plane. Edge parallel to plane. No need to
275 // Note: any snap-to-point check must be based on all edges using a point
276 // since otherwise cut through close to point but on neighbouring edge
277 // might not be snapped.
280 label nEstCuts = 2*mesh().cells()[cellI].size();
282 DynamicList<label> localLoop(nEstCuts);
283 DynamicList<scalar> localLoopWeights(nEstCuts);
285 // Points checked. Used to make sure we don't cut edge and edge endpoints
287 labelHashSet checkedPoints(nEstCuts);
289 const labelList& cellEdges = mesh().cellEdges()[cellI];
293 label edgeI = cellEdges[i];
295 const edge& e = edges[edgeI];
297 bool useStart = false;
302 // Check distance of endpoints to cutPlane
305 if (!checkedPoints.found(e.start()))
307 checkedPoints.insert(e.start());
309 scalar typStartLen = pointEqualTol_ * minEdgeLen(e.start());
311 // Check distance of startPt to plane.
312 if (cutPlane.distance(points[e.start()]) < typStartLen)
315 localLoop.append(vertToEVert(e.start()));
316 localLoopWeights.append(-GREAT);
321 if (!checkedPoints.found(e.end()))
323 checkedPoints.insert(e.end());
325 scalar typEndLen = pointEqualTol_ * minEdgeLen(e.end());
327 // Check distance of endPt to plane.
328 if (cutPlane.distance(points[e.end()]) < typEndLen)
331 localLoop.append(vertToEVert(e.end()));
332 localLoopWeights.append(-GREAT);
342 if (!useEnd && !useStart)
344 // Edge end points not close to plane so edge not close to
348 if (cutEdge(cutPlane, edgeI, cutWeight))
350 // Snap edge cut to vertex.
351 label cutVertI = snapToVert(snapTol_, edgeI, cutWeight);
355 // Proper cut of edge
356 localLoop.append(edgeToEVert(edgeI));
357 localLoopWeights.append(cutWeight);
361 // Cut through edge end point. Might be duplicate
362 // since connected edge might also be snapped to same
363 // endpoint so only insert if unique.
364 label cut = vertToEVert(cutVertI);
366 if (findIndex(localLoop, cut) == -1)
368 localLoop.append(vertToEVert(cutVertI));
369 localLoopWeights.append(-GREAT);
376 if (localLoop.size() <= 2)
382 localLoopWeights.shrink();
385 // Get points on loop and centre of loop
386 pointField loopPoints(localLoop.size());
387 point ctr(vector::zero);
391 loopPoints[i] = coord(localLoop[i], localLoopWeights[i]);
392 ctr += loopPoints[i];
394 ctr /= localLoop.size();
397 // Get base vectors of coordinate system normal to refDir
399 getBase(cutPlane.normal(), e0, e1);
402 // Get sorted angles from point on loop to centre of loop.
403 SortableList<scalar> sortedAngles(localLoop.size());
405 forAll(sortedAngles, i)
407 vector toCtr(loopPoints[i] - ctr);
410 sortedAngles[i] = pseudoAngle(e0, e1, toCtr);
414 loop.setSize(localLoop.size());
415 loopWeights.setSize(loop.size());
418 // Fill loop and loopweights according to sorted angles
420 const labelList& indices = sortedAngles.indices();
424 loop[i] = localLoop[indices[i]];
425 loopWeights[i] = localLoopWeights[indices[i]];
429 // Check for cut edges along already cut vertices.
430 bool filterLoop = false;
436 if (isEdge(cut) && edgeEndsCut(loop, i))
444 // Found edges in loop where both end points are also in loop. This
445 // is superfluous information so we can remove it.
447 labelList filteredLoop(loop.size());
448 scalarField filteredLoopWeights(loopWeights.size());
455 if (isEdge(cut) && edgeEndsCut(loop, i))
457 // Superfluous cut. Edge end points cut and edge itself as well.
461 filteredLoop[filterI] = loop[i];
462 filteredLoopWeights[filterI] = loopWeights[i];
466 filteredLoop.setSize(filterI);
467 filteredLoopWeights.setSize(filterI);
469 loop.transfer(filteredLoop);
470 loopWeights.transfer(filteredLoopWeights);
475 Pout<< "cell:" << cellI << endl;
478 Pout<< "At angle:" << sortedAngles[i] << endl
481 writeCut(Pout, loop[i], loopWeights[i]);
483 Pout<< " coord:" << coord(loop[i], loopWeights[i]);
493 // ************************************************************************* //