1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh 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 3 of the License, or (at your
14 option) any later version.
16 cfMesh 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 cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
29 #include "helperFunctionsGeometryQueries.H"
30 #include "helperFunctionsTopologyManipulation.H"
32 #include "pointField.H"
37 #include "tetrahedron.H"
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
53 template<class ListType>
54 inline bool isnan(const ListType& l)
63 template<class ListType>
64 bool isinf(const ListType& l)
67 if( (l[i] < -VGREAT) || (l[i] > VGREAT) )
73 inline bool isSharedEdgeConvex
75 const pointField& points,
85 label pos = f2.which(f1[pI]);
90 triNei[1] = f2.nextLabel(pos);
91 triNei[2] = f2.prevLabel(pos);
94 triOwn[1] = f1.nextLabel(pI);
95 triOwn[2] = f1.prevLabel(pI);
101 if( triNei.which(triOwn[pJ]) == -1 )
103 tetrahedron<point, point> tet
123 inline faceList mergePatchFaces
125 const List< DynList<label> >& pfcs,
126 const pointField& polyPoints
129 //- merge faces which share a common edge
130 faceList patchFaces(pfcs.size());
133 if( pfcs[faceI].size() > 2 )
135 const DynList<label>& f = pfcs[faceI];
140 patchFaces[counter++] = f_;
143 patchFaces.setSize(counter);
148 faceList mergedFaces(patchFaces.size());
149 boolList currentlyMerged(patchFaces.size(), false);
154 for(label nI=0;nI<(patchFaces.size()-1);nI++)
156 vector n0 = patchFaces[nI].normal(polyPoints);
159 for(label nJ=nI+1;nJ<patchFaces.size();nJ++)
161 vector n1 = patchFaces[nI].normal(polyPoints);
164 help::shareAnEdge(patchFaces[nI], patchFaces[nJ]) &&
169 currentlyMerged[nI] = currentlyMerged[nJ] = true;
170 mergedFaces[counter++] =
184 forAll(patchFaces, pfI)
185 if( !currentlyMerged[pfI] )
186 mergedFaces.newElmt(counter++) = patchFaces[pfI];
190 patchFaces.setSize(counter);
191 for(label k=0;k<counter;k++)
192 patchFaces[k] = mergedFaces[k];
200 inline bool vertexOnLine(const point& p, const edge& e, const pointField& ep)
202 vector v = e.vec(ep);
205 vector pv = p - ep[e.start()];
208 if( mag(pv & v) > (1.0-SMALL) )
214 inline bool vertexInPlane(const point& p, const plane& pl)
216 const vector& n = pl.normal();
217 const point& fp = pl.refPoint();
220 if( mag(d) > VSMALL )
223 if( mag(d & n) < SMALL )
229 inline bool planeIntersectsEdge
237 const vector v = end - start;
239 const vector& n = pl.normal();
240 const point& fp = pl.refPoint();
242 if( (n & (v/mag(v))) < SMALL )
245 const scalar t((n & (fp - start)) / (n & v));
247 if( (t > -SMALL) && (t < (1.0+SMALL)) )
249 intersection = start + v * t;
256 inline bool pointInTetrahedron
259 const tetrahedron<point, point>& tet
262 const vector v0 = tet.a() - tet.d();
263 const vector v1 = tet.b() - tet.d();
264 const vector v2 = tet.c() - tet.d();
265 const vector sp = p - tet.d();
268 FixedList<scalar, 3> source;
269 for(label i=0;i<3;++i)
277 //- check the determinant of the transformation
278 const scalar det = mat.determinant();
280 if( mag(det) < VSMALL )
283 //- get the coordinates of the point in the barycentric corrdinate system
284 const scalar u0 = mat.solveFirst(source);
286 if( (u0 < -SMALL) || (u0 > (1.0+SMALL)) )
289 const scalar u1 = mat.solveSecond(source);
291 if( (u1 < -SMALL) || ((u0+u1) > (1.0+SMALL)) )
294 const scalar u2 = mat.solveThird(source);
296 if( (u2 < -SMALL) || (u2 > (1.0+SMALL)) )
300 const scalar u3 = 1.0 - u0 - u1 - u2;
302 if( (u3 < -SMALL) || (u3 > (1.0+SMALL)) )
308 inline bool nearestEdgePointToTheLine
310 const point& edgePoint0,
311 const point& edgePoint1,
314 point& nearestOnEdge,
318 const vector v = lp1 - lp0;
319 const vector d = lp0 - edgePoint0;
320 const vector e = edgePoint1 - edgePoint0;
322 const scalar vMag = mag(v);
326 const scalar eMag = mag(e);
329 nearestOnEdge = edgePoint0;
330 nearestOnLine = nearestPointOnTheEdge(lp0, lp1, nearestOnEdge);
334 if( mag((v/vMag) & (e/eMag)) > (1.0 - SMALL) )
337 tensor mat(tensor::zero);
339 mat.xy() = mat.yx() = -1.0 * (v&e);
343 vector source(vector::zero);
344 source[0] = -1.0 * (d&v);
347 const vector sol = (inv(mat) & source);
349 nearestOnLine = lp0 + v * sol[0];
352 nearestOnEdge = edgePoint1;
354 else if( sol[1] < 0.0 )
356 nearestOnEdge = edgePoint0;
360 nearestOnEdge = edgePoint0 + e * sol[1];
366 inline point nearestPointOnTheTriangle
369 const triSurf& surface,
373 const labelledTri& ltri = surface[tI];
374 const pointField& points = surface.points();
376 const vector v0 = points[ltri[1]] - points[ltri[0]];
377 const vector v1 = points[ltri[2]] - points[ltri[0]];
378 const vector v2 = p - points[ltri[0]];
380 const scalar dot00 = (v0 & v0);
381 const scalar dot01 = (v0 & v1);
382 const scalar dot02 = (v0 & v2);
383 const scalar dot11 = (v1 & v1);
384 const scalar dot12 = (v1 & v2);
386 // Compute barycentric coordinates
387 const scalar det = dot00 * dot11 - dot01 * dot01;
389 if( mag(det) < VSMALL )
393 const edgeList edges = ltri.edges();
396 const edge& e = edges[eI];
398 nearestPointOnTheEdge
405 if( magSqr(p - np) < dist )
408 dist = magSqr(p - np);
415 const scalar u = (dot11 * dot02 - dot01 * dot12) / det;
416 const scalar v = (dot00 * dot12 - dot01 * dot02) / det;
418 const point pProj = points[ltri[0]] + u * v0 + v * v1;
420 //- Check if point is in triangle
421 if( (u >= -SMALL) && (v >= -SMALL) && ((u + v) <= (1.0+SMALL)) )
429 const edge e(ltri[0], ltri[2]);
430 const scalar ed = ((pProj - points[e.start()]) & v1) / magSqr(v1);
434 return points[e.end()];
438 return points[e.start()];
442 return (points[e.start()] + v1 * ed);
445 else if( v < -SMALL )
447 const edge e(ltri[0], ltri[1]);
448 const scalar ed = ((pProj - points[e.start()]) & v0) / magSqr(v0);
452 return points[e.end()];
456 return points[e.start()];
460 return (points[e.start()] + v0 * ed);
465 const edge e(ltri[2], ltri[1]);
466 const vector ev = e.vec(points);
467 const scalar ed = ((pProj - points[e.start()]) & ev) / magSqr(ev);
471 return points[e.end()];
475 return points[e.start()];
479 return (points[e.start()] + ev * ed);
487 inline bool triLineIntersection
489 const triangle<point, point>& tria,
490 const point& lineStart,
491 const point& lineEnd,
495 const point& p0 = tria.a();
496 const vector v(lineStart - lineEnd);
497 const vector v0 = tria.b() - p0;
498 const vector v1 = tria.c() - p0;
499 const vector sp = lineStart - p0;
502 FixedList<scalar, 3> source;
503 for(label i=0;i<3;++i)
511 const scalar det = mat.determinant();
513 if( mag(det) < SMALL )
516 const scalar t = mat.solveThird(source);
518 if( (t < -SMALL) || (t > (1.0+SMALL)) )
521 const scalar u0 = mat.solveFirst(source);
526 const scalar u1 = mat.solveSecond(source);
528 if( (u1 < -SMALL) || ((u0+u1) > (1.0+SMALL)) )
531 intersection = lineStart - t * v;
535 inline bool triLineIntersection
537 const triSurf& surface,
544 const pointField& pts = surface.points();
545 const labelledTri& tri = surface[tI];
547 const triangle<point, point> tria
554 return triLineIntersection(tria, s, e, intersection);
557 inline bool boundBoxLineIntersection
564 scalar tMax(1.0+SMALL), tMin(-SMALL);
566 const vector v = e - s;
567 const scalar d = mag(v);
569 //- check if the vector has length
578 const point& pMin = bb.min();
579 const point& pMax = bb.max();
581 //- check coordinates
582 for(label dir=0;dir<3;++dir)
584 const scalar vd = v[dir];
585 const scalar sd = s[dir];
587 if( mag(vd) > (SMALL * d) )
591 tMin = Foam::max(tMin, (pMin[dir] - sd) / vd);
592 tMax = Foam::min(tMax, (pMax[dir] - sd) / vd);
596 tMin = Foam::max(tMin, (pMax[dir] - sd) / vd);
597 tMax = Foam::min(tMax, (pMin[dir] - sd) / vd);
600 else if( (sd < pMin[dir]) || (sd > pMax[dir]) )
606 if( (tMax - tMin) > -SMALL )
612 inline bool doFaceAndTriangleIntersect
614 const triSurf& surface,
617 const pointField& facePoints
620 const pointField& triPoints = surface.points();
622 const point centre = f.centre(facePoints);
625 //- check if any triangle edge intersects the face
626 const labelledTri& tri = surface[triI];
630 const point& s = triPoints[tri[eI]];
631 const point& e = triPoints[tri[(eI+1)%3]];
635 const triangle<point, point> tria
638 facePoints[f.nextLabel(pI)],
642 const bool currIntersection =
643 help::triLineIntersection
651 if( currIntersection )
656 //- check if any face edges intersect the triangle
659 const point& s = facePoints[f[pI]];
660 const point& e = facePoints[f.nextLabel(pI)];
662 const bool intersected =
663 help::triLineIntersection
679 inline bool pointInsideFace
687 const edgeList fe = f.edges();
690 if( mag(p - fp[f[pI]]) < SMALL )
693 vector pv = p - fp[f[pI]];
696 vector lv = n ^ fe[pI].vec(fp);
699 const scalar d = pv & lv;
709 inline bool pointInsideFace
716 vector n = f.normal(fp);
719 const edgeList fe = f.edges();
722 if( mag(p - fp[f[pI]]) < SMALL )
725 vector pv = p - fp[f[pI]];
728 vector lv = n ^ fe[pI].vec(fp);
731 const scalar d = pv & lv;
741 inline point nearestPointOnTheEdge
743 const point& edgePoint0,
744 const point& edgePoint1,
748 const vector e = edgePoint1 - edgePoint0;
749 const scalar d = mag(e);
750 const vector k = p - edgePoint0;
755 return edgePoint0 + ((e / (d*d)) * (e & k));
758 inline point nearestPointOnTheEdgeExact
760 const point& edgePoint0,
761 const point& edgePoint1,
765 const vector e = edgePoint1 - edgePoint0;
766 const scalar d = mag(e);
767 const vector k = p - edgePoint0;
772 const scalar t = (e & k) / (d * d);
782 return edgePoint0 + (e * t);
785 inline scalar distanceOfPointFromTheEdge
787 const point& edgePoint0,
788 const point& edgePoint1,
792 return mag(nearestPointOnTheEdge(edgePoint0, edgePoint1, p) - p);
795 inline label numberOfFaceGroups
797 const labelHashSet& containedElements,
800 const triSurf& surface
803 const pointField& points = surface.points();
804 const edgeLongList& edges = surface.edges();
805 const VRWGraph& faceEdges = surface.facetEdges();
806 const VRWGraph& edgeFaces = surface.edgeFacets();
808 labelHashSet triaInRange(containedElements.size());
809 const scalar rangeSq = range * range;
810 forAllConstIter(labelHashSet, containedElements, it)
812 const point p = nearestPointOnTheTriangle(it.key(), surface, centre);
813 if( magSqr(p - centre) < rangeSq )
814 triaInRange.insert(it.key());
817 Map<label> elGroup(triaInRange.size());
818 Map<label> testEdge(triaInRange.size());
822 DynList<label> front;
824 forAllConstIter(labelHashSet, triaInRange, it)
825 if( !elGroup.found(it.key()) )
828 front.append(it.key());
829 elGroup.insert(it.key(), nGroups);
831 while( front.size() )
833 const label fLabel = front.removeLastElement();
835 forAllRow(faceEdges, fLabel, feI)
837 const label edgeI = faceEdges(fLabel, feI);
839 //- check if the edge intersects the bounding box
840 if( testEdge.found(edgeI) )
842 if( !testEdge[edgeI] )
847 const point& s = points[edges[edgeI][0]];
848 const point& e = points[edges[edgeI][1]];
849 const point np = nearestPointOnTheEdge(s, e, centre);
850 if( magSqr(np - centre) < rangeSq )
852 testEdge.insert(edgeI, 1);
856 testEdge.insert(edgeI, 0);
861 forAllRow(edgeFaces, edgeI, efI)
863 const label nei = edgeFaces(edgeI, efI);
866 triaInRange.found(nei) &&
870 elGroup.insert(nei, nGroups);
883 inline label numberOfEdgeGroups
885 const labelHashSet& containedEdges,
888 const triSurf& surface
891 const pointField& points = surface.points();
892 const edgeLongList& edges = surface.edges();
893 const VRWGraph& pointEdges = surface.pointEdges();
895 const scalar rangeSq = range * range;
896 labelHashSet edgesInRange(containedEdges.size());
897 forAllConstIter(labelHashSet, containedEdges, it)
899 const edge& e = edges[it.key()];
900 const point& sp = points[e[0]];
901 const point& ep = points[e[1]];
903 const point p = nearestPointOnTheEdgeExact(sp, ep, centre);
904 if( magSqr(p - centre) < rangeSq )
905 edgesInRange.insert(it.key());
908 Map<label> elGroup(edgesInRange.size());
909 Map<label> pointTest(edgesInRange.size());
913 DynList<label> front;
915 forAllConstIter(labelHashSet, edgesInRange, it)
916 if( !elGroup.found(it.key()) )
919 front.append(it.key());
920 elGroup.insert(it.key(), nGroups);
922 while( front.size() )
924 const label eLabel = front.removeLastElement();
925 const edge& e = edges[eLabel];
927 for(label i=0;i<2;++i)
929 if( pointTest.found(e[i]) )
931 if( !pointTest[e[i]] )
936 if( magSqr(points[e[i]] - centre) < rangeSq )
938 pointTest.insert(e[i], 1);
942 pointTest.insert(e[i], 0);
947 forAllRow(pointEdges, e[i], peI)
949 const label nei = pointEdges(e[i], peI);
951 if( edgesInRange.found(nei) && !elGroup.found(nei) )
953 elGroup.insert(nei, nGroups);
966 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
968 } // End namespace help
970 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
972 } // End namespace Foam
974 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //