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
25 \*---------------------------------------------------------------------------*/
27 #include "geomCellLooper.H"
29 #include "DynamicList.H"
31 #include "meshTools.H"
32 #include "SortableList.H"
33 #include "triSurfaceTools.H"
36 #include "transform.H"
38 #include "addToRunTimeSelectionTable.H"
41 // Extension factor of edges to make sure we catch intersections through
43 const Foam::scalar Foam::geomCellLooper::pointEqualTol_ = 1E-3;
46 // Snap cuts through edges onto edge endpoints. Fraction of edge length.
47 Foam::scalar Foam::geomCellLooper::snapTol_ = 0.1;
50 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
55 defineTypeNameAndDebug(geomCellLooper, 0);
56 addToRunTimeSelectionTable(cellLooper, geomCellLooper, word);
61 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
63 Foam::scalar Foam::geomCellLooper::minEdgeLen(const label vertI) const
65 scalar minLen = GREAT;
67 const labelList& pEdges = mesh().pointEdges()[vertI];
69 forAll(pEdges, pEdgeI)
71 const edge& e = mesh().edges()[pEdges[pEdgeI]];
73 minLen = min(minLen, e.mag(mesh().points()));
79 // Cut edge with plane. Return true and set weight to fraction between
80 // edge-start and edge-end
81 bool Foam::geomCellLooper::cutEdge
83 const plane& cutPlane,
88 const pointField& pts = mesh().points();
90 const edge& e = mesh().edges()[edgeI];
92 scalar s = cutPlane.normalIntersect(pts[e.start()], e.vec(pts));
94 if ((s > -pointEqualTol_) && (s < 1 + pointEqualTol_))
102 // Make sure we don't use this value
110 // If edge close enough to endpoint snap to endpoint.
111 Foam::label Foam::geomCellLooper::snapToVert
118 const edge& e = mesh().edges()[edgeI];
124 else if (weight > (1-tol))
135 void Foam::geomCellLooper::getBase(const vector& n, vector& e0, vector& e1)
138 // Guess for vector normal to n.
141 scalar nComp = n & base;
143 if (mag(nComp) > 0.8)
145 // Was bad guess. Try with different vector.
152 if (mag(nComp) > 0.8)
162 // Use component normal to n as base vector.
165 e0 /= mag(e0) + VSMALL;
169 //Pout<< "Coord system:" << endl
170 // << " n : " << n << ' ' << mag(n) << endl
171 // << " e0 : " << e0 << ' ' << mag(e0) << endl
172 // << " e1 : " << e1 << ' ' << mag(e1) << endl
177 // Return true if the cut edge at loop[index] is preceded by cuts through
178 // the edge end points.
179 bool Foam::geomCellLooper::edgeEndsCut
181 const labelList& loop,
185 label edgeI = getEdge(loop[index]);
187 const edge& e = mesh().edges()[edgeI];
189 const label prevCut = loop[loop.rcIndex(index)];
190 const label nextCut = loop[loop.fcIndex(index)];
192 if (!isEdge(prevCut) && !isEdge(nextCut))
194 // Cuts before and after are both vertices. Check if both
195 // the edge endpoints
196 label v0 = getVertex(prevCut);
197 label v1 = getVertex(nextCut);
201 (v0 == e[0] && v1 == e[1])
202 || (v0 == e[1] && v1 == e[0])
212 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
214 // Construct from components
215 Foam::geomCellLooper::geomCellLooper(const polyMesh& mesh)
221 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
223 Foam::geomCellLooper::~geomCellLooper()
227 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
229 bool Foam::geomCellLooper::cut
231 const vector& refDir,
233 const boolList& vertIsCut,
234 const boolList& edgeIsCut,
235 const scalarField& edgeWeight,
238 scalarField& loopWeights
241 // Cut through cell centre normal to refDir.
244 plane(mesh().cellCentres()[cellI], refDir),
255 bool Foam::geomCellLooper::cut
257 const plane& cutPlane,
264 scalarField& loopWeights
267 const pointField& points = mesh().points();
268 const edgeList& edges = mesh().edges();
270 // Find all cuts through edges.
272 // - edge cut close to endpoint. Snap to endpoint.
273 // - edge endpoint close to plane (but edge not cut). Snap to endpoint.
274 // - both endpoints close to plane. Edge parallel to plane. No need to
276 // Note: any snap-to-point check must be based on all edges using a point
277 // since otherwise cut through close to point but on neighbouring edge
278 // might not be snapped.
281 label nEstCuts = 2*mesh().cells()[cellI].size();
283 DynamicList<label> localLoop(nEstCuts);
284 DynamicList<scalar> localLoopWeights(nEstCuts);
286 // Points checked. Used to make sure we don't cut edge and edge endpoints
288 labelHashSet checkedPoints(nEstCuts);
290 const labelList& cellEdges = mesh().cellEdges()[cellI];
294 label edgeI = cellEdges[i];
296 const edge& e = edges[edgeI];
298 bool useStart = false;
303 // Check distance of endpoints to cutPlane
306 if (!checkedPoints.found(e.start()))
308 checkedPoints.insert(e.start());
310 scalar typStartLen = pointEqualTol_ * minEdgeLen(e.start());
312 // Check distance of startPt to plane.
313 if (cutPlane.distance(points[e.start()]) < typStartLen)
316 localLoop.append(vertToEVert(e.start()));
317 localLoopWeights.append(-GREAT);
322 if (!checkedPoints.found(e.end()))
324 checkedPoints.insert(e.end());
326 scalar typEndLen = pointEqualTol_ * minEdgeLen(e.end());
328 // Check distance of endPt to plane.
329 if (cutPlane.distance(points[e.end()]) < typEndLen)
332 localLoop.append(vertToEVert(e.end()));
333 localLoopWeights.append(-GREAT);
343 if (!useEnd && !useStart)
345 // Edge end points not close to plane so edge not close to
349 if (cutEdge(cutPlane, edgeI, cutWeight))
351 // Snap edge cut to vertex.
352 label cutVertI = snapToVert(snapTol_, edgeI, cutWeight);
356 // Proper cut of edge
357 localLoop.append(edgeToEVert(edgeI));
358 localLoopWeights.append(cutWeight);
362 // Cut through edge end point. Might be duplicate
363 // since connected edge might also be snapped to same
364 // endpoint so only insert if unique.
365 label cut = vertToEVert(cutVertI);
367 if (findIndex(localLoop, cut) == -1)
369 localLoop.append(vertToEVert(cutVertI));
370 localLoopWeights.append(-GREAT);
377 if (localLoop.size() <= 2)
383 localLoopWeights.shrink();
386 // Get points on loop and centre of loop
387 pointField loopPoints(localLoop.size());
388 point ctr(vector::zero);
392 loopPoints[i] = coord(localLoop[i], localLoopWeights[i]);
393 ctr += loopPoints[i];
395 ctr /= localLoop.size();
398 // Get base vectors of coordinate system normal to refDir
400 getBase(cutPlane.normal(), e0, e1);
403 // Get sorted angles from point on loop to centre of loop.
404 SortableList<scalar> sortedAngles(localLoop.size());
406 forAll(sortedAngles, i)
408 vector toCtr(loopPoints[i] - ctr);
411 sortedAngles[i] = pseudoAngle(e0, e1, toCtr);
415 loop.setSize(localLoop.size());
416 loopWeights.setSize(loop.size());
419 // Fill loop and loopweights according to sorted angles
421 const labelList& indices = sortedAngles.indices();
425 loop[i] = localLoop[indices[i]];
426 loopWeights[i] = localLoopWeights[indices[i]];
430 // Check for cut edges along already cut vertices.
431 bool filterLoop = false;
437 if (isEdge(cut) && edgeEndsCut(loop, i))
445 // Found edges in loop where both end points are also in loop. This
446 // is superfluous information so we can remove it.
448 labelList filteredLoop(loop.size());
449 scalarField filteredLoopWeights(loopWeights.size());
456 if (isEdge(cut) && edgeEndsCut(loop, i))
458 // Superfluous cut. Edge end points cut and edge itself as well.
462 filteredLoop[filterI] = loop[i];
463 filteredLoopWeights[filterI] = loopWeights[i];
467 filteredLoop.setSize(filterI);
468 filteredLoopWeights.setSize(filterI);
470 loop.transfer(filteredLoop);
471 loopWeights.transfer(filteredLoopWeights);
476 Pout<< "cell:" << cellI << endl;
479 Pout<< "At angle:" << sortedAngles[i] << endl
482 writeCut(Pout, loop[i], loopWeights[i]);
484 Pout<< " coord:" << coord(loop[i], loopWeights[i]);
494 // ************************************************************************* //