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"
45 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
50 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
52 template<class ListType>
53 inline bool isnan(const ListType& l)
62 template<class ListType>
63 bool isinf(const ListType& l)
66 if( (l[i] < -VGREAT) || (l[i] > VGREAT) )
72 template<class Face1, class Face2>
73 inline bool isSharedEdgeConvex
75 const pointField& points,
80 DynList<label, 3> triOwn(3);
81 DynList<label, 3> triNei(3);
87 if( f2[pJ] == f1[pI] )
97 triNei[1] = f2[f2.fcIndex(pos)];
98 triNei[2] = f2[f2.rcIndex(pos)];
101 triOwn[1] = f1[f1.fcIndex(pI)];
102 triOwn[2] = f1[f1.rcIndex(pI)];
108 if( !triNei.contains(triOwn[pJ]) )
110 tetrahedron<point, point> tet
130 template<class Face1, class Face2>
131 inline scalar angleBetweenFaces
133 const pointField& points,
138 DynList<label, 3> triOwn(3);
139 DynList<label, 3> triNei(3);
148 if( f2[pJ] == f1[pI] )
158 triNei[1] = f2[f2.fcIndex(pos)];
159 triNei[2] = f2[f2.rcIndex(pos)];
162 triOwn[1] = f1[f1.fcIndex(pI)];
163 triOwn[2] = f1[f1.rcIndex(pI)];
169 if( !triNei.contains(triOwn[pJ]) )
171 tetrahedron<point, point> tet
186 (points[triOwn[1]] - points[triOwn[0]]) ^
187 (points[triOwn[2]] - points[triOwn[0]])
189 nOwn /= (mag(nOwn) + VSMALL);
193 (points[triNei[1]] - points[triNei[0]]) ^
194 (points[triNei[2]] - points[triNei[0]])
196 nNei /= (mag(nNei) + VSMALL);
198 const scalar dot = Foam::max(-1.0, Foam::min(nOwn & nNei, 1.0));
202 //- the angle is in the interval [Pi, 2Pi>
203 const scalar ang = Foam::acos(dot);
210 //- the angle is in the interval [0, Pi>
211 const scalar ang = Foam::acos(-dot);
222 "scalar angleBetweenFaces"
223 "(const pointField&, const face&, const face&)"
224 ) << "Faces " << f1 << " and " << f2
225 << " do no share an edge" << abort(FatalError);
228 return angle / counter;
231 inline faceList mergePatchFaces
233 const List< DynList<label> >& pfcs,
234 const pointField& polyPoints
237 //- merge faces which share a common edge
238 faceList patchFaces(pfcs.size());
241 if( pfcs[faceI].size() > 2 )
243 const DynList<label>& f = pfcs[faceI];
248 patchFaces[counter++] = f_;
251 patchFaces.setSize(counter);
256 faceList mergedFaces(patchFaces.size());
257 boolList currentlyMerged(patchFaces.size(), false);
262 for(label nI=0;nI<(patchFaces.size()-1);nI++)
264 vector n0 = patchFaces[nI].normal(polyPoints);
267 for(label nJ=nI+1;nJ<patchFaces.size();nJ++)
269 vector n1 = patchFaces[nI].normal(polyPoints);
272 help::shareAnEdge(patchFaces[nI], patchFaces[nJ]) &&
277 currentlyMerged[nI] = currentlyMerged[nJ] = true;
278 mergedFaces[counter++] =
292 forAll(patchFaces, pfI)
293 if( !currentlyMerged[pfI] )
294 mergedFaces.newElmt(counter++) = patchFaces[pfI];
298 patchFaces.setSize(counter);
299 for(label k=0;k<counter;k++)
300 patchFaces[k] = mergedFaces[k];
308 inline bool vertexOnLine(const point& p, const edge& e, const pointField& ep)
310 vector v = e.vec(ep);
313 vector pv = p - ep[e.start()];
316 if( mag(pv & v) > (1.0-SMALL) )
322 inline bool vertexInPlane(const point& p, const plane& pl)
324 const vector& n = pl.normal();
325 const point& fp = pl.refPoint();
328 if( mag(d) > VSMALL )
331 if( mag(d & n) < SMALL )
337 inline bool planeIntersectsEdge
345 const vector v = end - start;
347 const vector& n = pl.normal();
348 const point& fp = pl.refPoint();
350 if( (n & (v/mag(v))) < SMALL )
353 const scalar t((n & (fp - start)) / (n & v));
355 if( (t > -SMALL) && (t < (1.0+SMALL)) )
357 intersection = start + v * t;
364 inline bool pointInTetrahedron
367 const tetrahedron<point, point>& tet
370 const vector v0 = tet.a() - tet.d();
371 const vector v1 = tet.b() - tet.d();
372 const vector v2 = tet.c() - tet.d();
373 const vector sp = p - tet.d();
376 FixedList<scalar, 3> source;
377 for(label i=0;i<3;++i)
385 //- check the determinant of the transformation
386 const scalar det = mat.determinant();
388 if( mag(det) < VSMALL )
391 //- get the coordinates of the point in the barycentric corrdinate system
392 const scalar u0 = mat.solveFirst(source);
394 if( (u0 < -SMALL) || (u0 > (1.0+SMALL)) )
397 const scalar u1 = mat.solveSecond(source);
399 if( (u1 < -SMALL) || ((u0+u1) > (1.0+SMALL)) )
402 const scalar u2 = mat.solveThird(source);
404 if( (u2 < -SMALL) || (u2 > (1.0+SMALL)) )
408 const scalar u3 = 1.0 - u0 - u1 - u2;
410 if( (u3 < -SMALL) || (u3 > (1.0+SMALL)) )
416 inline bool nearestEdgePointToTheLine
418 const point& edgePoint0,
419 const point& edgePoint1,
422 point& nearestOnEdge,
426 const vector v = lp1 - lp0;
427 const vector d = lp0 - edgePoint0;
428 const vector e = edgePoint1 - edgePoint0;
430 const scalar vMag = mag(v);
434 const scalar eMag = mag(e);
437 nearestOnEdge = edgePoint0;
438 nearestOnLine = nearestPointOnTheEdge(lp0, lp1, nearestOnEdge);
442 if( mag((v/vMag) & (e/eMag)) > (1.0 - SMALL) )
445 tensor mat(tensor::zero);
447 mat.xy() = mat.yx() = -1.0 * (v&e);
451 vector source(vector::zero);
452 source[0] = -1.0 * (d&v);
455 const vector sol = (inv(mat) & source);
457 nearestOnLine = lp0 + v * sol[0];
460 nearestOnEdge = edgePoint1;
462 else if( sol[1] < 0.0 )
464 nearestOnEdge = edgePoint0;
468 nearestOnEdge = edgePoint0 + e * sol[1];
474 inline point nearestPointOnTheTriangle
476 const triangle<point, point>& tri,
480 const vector v0 = tri.b() - tri.a();
481 const vector v1 = tri.c() - tri.a();
482 const vector v2 = p - tri.a();
484 const scalar dot00 = (v0 & v0);
485 const scalar dot01 = (v0 & v1);
486 const scalar dot02 = (v0 & v2);
487 const scalar dot11 = (v1 & v1);
488 const scalar dot12 = (v1 & v2);
490 // Compute barycentric coordinates
491 const scalar det = dot00 * dot11 - dot01 * dot01;
493 if( mag(det) < VSMALL )
498 FixedList<Pair<point>, 3> edges;
499 edges[0] = Pair<point>(tri.a(), tri.b());
500 edges[1] = Pair<point>(tri.b(), tri.c());
501 edges[2] = Pair<point>(tri.c(), tri.a());
505 const Pair<point>& e = edges[eI];
507 nearestPointOnTheEdge
514 if( magSqr(p - np) < dist )
517 dist = magSqr(p - np);
524 const scalar u = (dot11 * dot02 - dot01 * dot12) / det;
525 const scalar v = (dot00 * dot12 - dot01 * dot02) / det;
527 const point pProj = tri.a() + u * v0 + v * v1;
529 //- Check if point is in triangle
530 if( (u >= -SMALL) && (v >= -SMALL) && ((u + v) <= (1.0+SMALL)) )
538 const scalar ed = ((pProj - tri.a()) & v1) / (magSqr(v1) + VSMALL);
550 return (tri.a() + v1 * ed);
553 else if( v < -SMALL )
555 const scalar ed = ((pProj - tri.a()) & v0) / (magSqr(v0) + VSMALL);
567 return (tri.a() + v0 * ed);
572 const vector ev = tri.b() - tri.c();
573 const scalar ed = ((pProj - tri.c()) & ev) / (magSqr(ev) + VSMALL);
585 return (tri.c() + ev * ed);
593 inline point nearestPointOnTheTriangle
596 const triSurf& surface,
600 const labelledTri& ltri = surface[tI];
601 const pointField& points = surface.points();
603 const triangle<point, point> tri
610 return nearestPointOnTheTriangle(tri, p);
613 inline bool findMinimizerPoint
615 const DynList<point>& origins,
616 const DynList<vector>& normals,
620 if( origins.size() != normals.size() )
623 "inline bool findMinimizerPoint"
624 "(const DynList<point>&, const DynList<vector>&, point&)"
625 ) << "Size of normals and origins do not match" << abort(FatalError);
627 tensor mat(tensor::zero);
628 vector source(vector::zero);
632 //- use the normalized vector
633 vector n = normals[i];
634 n /= (mag(n) + VSMALL);
636 const tensor t = n * n;
640 source += (origins[i] & n) * n;
643 const scalar determinant = Foam::mag(Foam::det(mat));
644 if( determinant < SMALL )
647 pMin = (inv(mat, determinant) & source);
652 inline bool triLineIntersection
654 const triangle<point, point>& tria,
655 const point& lineStart,
656 const point& lineEnd,
660 const point& p0 = tria.a();
661 const vector v(lineStart - lineEnd);
662 const vector v0 = tria.b() - p0;
663 const vector v1 = tria.c() - p0;
664 const vector sp = lineStart - p0;
667 FixedList<scalar, 3> source;
668 for(label i=0;i<3;++i)
676 const scalar det = mat.determinant();
678 if( mag(det) < SMALL )
681 const scalar t = mat.solveThird(source);
683 if( (t < -SMALL) || (t > (1.0+SMALL)) )
686 const scalar u0 = mat.solveFirst(source);
691 const scalar u1 = mat.solveSecond(source);
693 if( (u1 < -SMALL) || ((u0+u1) > (1.0+SMALL)) )
696 intersection = lineStart - t * v;
700 inline bool triLineIntersection
702 const triSurf& surface,
709 const pointField& pts = surface.points();
710 const labelledTri& tri = surface[tI];
712 const triangle<point, point> tria
719 return triLineIntersection(tria, s, e, intersection);
722 inline bool boundBoxLineIntersection
729 scalar tMax(1.0+SMALL), tMin(-SMALL);
731 const vector v = e - s;
732 const scalar d = mag(v);
734 //- check if the vector has length
743 const point& pMin = bb.min();
744 const point& pMax = bb.max();
746 //- check coordinates
747 for(label dir=0;dir<3;++dir)
749 const scalar vd = v[dir];
750 const scalar sd = s[dir];
752 if( mag(vd) > (SMALL * d) )
756 tMin = Foam::max(tMin, (pMin[dir] - sd) / vd);
757 tMax = Foam::min(tMax, (pMax[dir] - sd) / vd);
761 tMin = Foam::max(tMin, (pMax[dir] - sd) / vd);
762 tMax = Foam::min(tMax, (pMin[dir] - sd) / vd);
765 else if( (sd < pMin[dir]) || (sd > pMax[dir]) )
771 if( (tMax - tMin) > -SMALL )
777 inline bool lineFaceIntersection
782 const pointField& fp,
786 const point c = f.centre(fp);
790 const triangle<point, point> tri
797 if( triLineIntersection(tri, sp, ep, intersection) )
804 inline bool doFaceAndTriangleIntersect
806 const triSurf& surface,
809 const pointField& facePoints
812 const pointField& triPoints = surface.points();
814 const point centre = f.centre(facePoints);
817 //- check if any triangle edge intersects the face
818 const labelledTri& tri = surface[triI];
822 const point& s = triPoints[tri[eI]];
823 const point& e = triPoints[tri[(eI+1)%3]];
827 const triangle<point, point> tria
830 facePoints[f.nextLabel(pI)],
834 const bool currIntersection =
835 help::triLineIntersection
843 if( currIntersection )
848 //- check if any face edges intersect the triangle
851 const point& s = facePoints[f[pI]];
852 const point& e = facePoints[f.nextLabel(pI)];
854 const bool intersected =
855 help::triLineIntersection
871 inline bool doEdgesOverlap
877 FixedList<point, 2>& overlappingPart,
878 const scalar distTol,
886 "inline bool doEdgesOverlap(const point, const point&,"
887 "const point&, const point&, const scalar, const scalar,"
888 "FixedList<point, 2>& overlappingPart)"
889 ) << "Distance is not specified" << endl;
894 vector e0 = e0p1 - e0p0;
895 const scalar de0 = mag(e0);
896 e0 /= (de0 + VSMALL);
898 vector e1 = e1p1 - e1p0;
899 const scalar de1 = mag(e1);
900 e1 /= (de1 + VSMALL);
902 //- check the angle deviation between the two vectors
903 if( mag(e0 & e1) < cosTol )
906 scalar t00 = (e1p0 - e0p0) & e0;
907 scalar t01 = (e1p1 - e0p0) & e0;
909 scalar t10 = (e0p0 - e1p0) & e1;
910 scalar t11 = (e0p1 - e1p0) & e1;
912 //- check if points are colinear within the tolerance
915 (magSqr(e0p0 + t00*e0 - e1p0) <= distTol*distTol) ||
916 (magSqr(e0p0 + t01*e0 - e1p1) <= distTol*distTol) ||
917 (magSqr(e1p0 + t10*e1 - e0p0) <= distTol*distTol) ||
918 (magSqr(e1p0 + t11*e1 - e0p1) <= distTol*distTol)
921 vector vec = e0 + (((e0 & e1) > 0.0) ? e1 : -e1);
922 vec /= (mag(vec) + VSMALL);
923 const point origin = 0.25 * (e0p0 + e0p1 + e1p0 + e1p1);
925 //- calculate parameters on the regression line
926 t00 = (e0p0 - origin) & vec;
927 t01 = (e0p1 - origin) & vec;
928 t10 = (e1p0 - origin) & vec;
929 t11 = (e1p1 - origin) & vec;
931 //- check interval overlapping over the line
932 const scalar t0Min = Foam::min(t00, t01);
933 const scalar t0Max = Foam::max(t00, t01);
934 const scalar t1Min = Foam::min(t10, t11);
935 const scalar t1Max = Foam::max(t10, t11);
939 overlappingPart[0] = origin + t1Min * vec;
940 overlappingPart[1] = origin + t0Max * vec;
944 else if( t0Min < t1Max )
946 overlappingPart[0] = origin + t0Min * vec;
947 overlappingPart[1] = origin + t1Max * vec;
956 inline bool doTrianglesOverlap
958 const triangle<point, point>& tri0,
959 const triangle<point, point>& tri1,
960 DynList<point>& overlappingPolygon,
961 const scalar distTol,
969 "inline bool doTrianglesOverlap(const triangle<point, point>&,"
970 " const triangle<point, point>&, DynList<point>&,"
971 " const scalar, const scalar)"
972 ) << "Distance is not specified" << endl;
977 vector n0 = tri0.normal();
978 const scalar dn0 = mag(n0);
979 n0 /= (dn0 + VSMALL);
984 vector n1 = tri1.normal();
985 const scalar dn1 = mag(n1);
986 n1 /= (dn1 + VSMALL);
991 //- check the angle deviation between the two vectors
992 if( (mag(n0 & n1) < cosTol) && (dn0 >= VSMALL) && (dn1 >= VSMALL) )
995 //- check if the two nearest points are within tolerance
998 (mag((tri1.a() - tri0.a()) & n0) < distTol) ||
999 (mag((tri1.b() - tri0.a()) & n0) < distTol) ||
1000 (mag((tri1.c() - tri0.a()) & n0) < distTol) ||
1001 (mag((tri0.a() - tri1.a()) & n1) < distTol) ||
1002 (mag((tri0.b() - tri1.a()) & n1) < distTol) ||
1003 (mag((tri0.c() - tri1.a()) & n1) < distTol)
1006 vector vec = n0 + ((n0 & n1) >= 0.0 ? n1 : -n1);
1007 vec /= (mag(vec) + VSMALL);
1008 const point origin = 0.5 * (tri0.centre() + tri1.centre());
1010 overlappingPolygon.clear();
1012 //- calculate max distance point from the origin
1013 point bestPoint = tri0.a();
1014 scalar distSq = magSqr(tri0.a() - origin);
1016 scalar dSq = magSqr(tri0.b() - origin);
1020 bestPoint = tri0.b();
1023 dSq = magSqr(tri0.c() - origin);
1027 bestPoint = tri0.c();
1030 dSq = magSqr(tri1.a() - origin);
1034 bestPoint = tri1.a();
1037 dSq = magSqr(tri1.b() - origin);
1041 bestPoint = tri1.b();
1044 dSq = magSqr(tri1.c() - origin);
1048 bestPoint = tri1.c();
1051 if( distSq < VSMALL )
1054 //- transform into planar coordinates
1055 vector x = (bestPoint - origin) - ((bestPoint - origin) & vec) * vec;
1056 x /= (mag(x) + VSMALL);
1059 DynList<point2D, 6> poly2D(3);
1060 poly2D[0] = point2D((tri0.a() - origin) & x, (tri0.a() - origin) & y);
1061 poly2D[1] = point2D((tri0.b() - origin) & x, (tri0.b() - origin) & y);
1062 poly2D[2] = point2D((tri0.c() - origin) & x, (tri0.c() - origin) & y);
1064 FixedList<point2D, 3> t1Proj;
1065 t1Proj[0] = point2D((tri1.a() - origin) & x, (tri1.a() - origin) & y);
1066 t1Proj[1] = point2D((tri1.b() - origin) & x, (tri1.b() - origin) & y);
1067 t1Proj[2] = point2D((tri1.c() - origin) & x, (tri1.c() - origin) & y);
1071 const vector2D vec = t1Proj[(eI+1)%3] - t1Proj[eI];
1073 DynList<scalar, 6> distance(poly2D.size());
1076 const vector2D pVec = poly2D[pI] - t1Proj[eI];
1077 distance[pI] = vec.y() * pVec.x() - vec.x() * pVec.y();
1080 DynList<point2D, 6> newPoly2D;
1082 forAll(distance, pI)
1084 if( distance[pI] >= 0.0 )
1086 newPoly2D.append(poly2D[pI]);
1088 if( distance.fcElement(pI) < 0.0 )
1090 //- this is very sensitive to floaing point tolerances
1091 const point2D newP =
1093 mag(distance[pI]) * poly2D.fcElement(pI) +
1094 mag(distance.fcElement(pI)) * poly2D[pI]
1098 mag(distance.fcElement(pI)) +
1102 newPoly2D.append(newP);
1105 else if( distance.fcElement(pI) >= 0.0 )
1107 //- this is very sensitive to floaing point tolerances
1108 const point2D newP =
1110 mag(distance[pI]) * poly2D.fcElement(pI) +
1111 mag(distance.fcElement(pI)) * poly2D[pI]
1115 mag(distance.fcElement(pI)) +
1119 newPoly2D.append(newP);
1126 //- check if the overlapping polygon exists
1127 if( poly2D.size() == 0 )
1129 overlappingPolygon.clear();
1133 //- fill the overlapping polygon
1134 overlappingPolygon.setSize(poly2D.size());
1137 const point2D& pp = poly2D[pI];
1138 overlappingPolygon[pI] = origin + x * pp.x() + y * pp.y();
1144 overlappingPolygon.clear();
1148 inline bool doTrianglesIntersect
1150 const triangle<point, point> &tri0,
1151 const triangle<point, point> &tri1,
1152 const scalar distTol
1159 "inline bool doTrianglesIntersect(const triangle<point, point>&,"
1160 " const triangle<point, point>&,"
1161 " const scalar, const scalar)"
1162 ) << "Distance is not specified" << endl;
1167 //- find distances of points from the second triangle
1168 point np = nearestPointOnTheTriangle(tri1, tri0.a());
1169 if( magSqr(np - tri0.a()) < distTol*distTol )
1171 np = nearestPointOnTheTriangle(tri1, tri0.b());
1172 if( magSqr(np - tri0.b()) < distTol*distTol )
1174 np = nearestPointOnTheTriangle(tri1, tri0.c());
1175 if( magSqr(np - tri0.c()) < distTol*distTol )
1178 //- find distances of points from the first triangle
1179 np = nearestPointOnTheTriangle(tri0, tri1.a());
1180 if( magSqr(np - tri1.a()) < distTol*distTol )
1182 np = nearestPointOnTheTriangle(tri0, tri1.b());
1183 if( magSqr(np - tri1.b()) < distTol*distTol )
1185 np = nearestPointOnTheTriangle(tri0, tri1.c());
1186 if( magSqr(np - tri1.c()) < distTol*distTol )
1189 //- find edge intersections
1191 if( triLineIntersection(tri0, tri1.a(), tri1.b(), intersection) )
1193 if( triLineIntersection(tri0, tri1.b(), tri1.c(), intersection) )
1195 if( triLineIntersection(tri0, tri1.c(), tri1.a(), intersection) )
1198 if( triLineIntersection(tri1, tri0.a(), tri0.b(), intersection) )
1200 if( triLineIntersection(tri1, tri0.b(), tri0.c(), intersection) )
1202 if( triLineIntersection(tri1, tri0.c(), tri0.a(), intersection) )
1208 inline bool doTrianglesIntersect
1210 const triangle<point, point>& tri0,
1211 const triangle<point, point>& tri1,
1212 DynList<point> &intersectionPoints,
1213 const scalar distTol
1220 "inline bool doTrianglesIntersect(const triangle<point, point>&,"
1221 " const triangle<point, point>&, DynList<point>&,"
1222 " const scalar, const scalar)"
1223 ) << "Distance is not specified" << endl;
1228 vector n0 = tri0.normal();
1229 const scalar dn0 = mag(n0);
1230 n0 /= (dn0 + VSMALL);
1232 vector n1 = tri1.normal();
1233 const scalar dn1 = mag(n1);
1234 n1 /= (dn1 + VSMALL);
1236 //- distance of the points of the first triangle from the plane
1237 //- of the second triangle
1238 FixedList<scalar, 3> distancesTri0;
1239 distancesTri0[0] = (tri0.a() - tri1.a()) & n1;
1240 distancesTri0[1] = (tri0.b() - tri1.a()) & n1;
1241 distancesTri0[2] = (tri0.c() - tri1.a()) & n1;
1243 forAll(distancesTri0, i)
1244 if( mag(distancesTri0[i]) < distTol )
1245 distancesTri0[i] = 0.0;
1247 bool hasPositive(false), hasNegative(false), hasZero(false);
1248 DynList<point, 2> intersectionLine0;
1249 forAll(distancesTri0, pI)
1251 if( distancesTri0[pI] >= distTol )
1255 else if( distancesTri0[pI] <= -distTol )
1265 //- find points on the intersection line
1268 (hasPositive && !hasNegative && !hasZero) ||
1269 (hasNegative && !hasPositive && !hasZero)
1272 //- there can be no intersection
1273 intersectionPoints.clear();
1278 (hasPositive && (hasNegative || hasZero)) ||
1279 (hasNegative && (hasPositive || hasZero))
1282 //- find points on the intersection line
1283 if( mag(distancesTri0[0]) < distTol)
1285 intersectionLine0.append(tri0.a());
1287 else if( distancesTri0[0] * distancesTri0[1] < 0.0 )
1289 intersectionLine0.append
1291 (tri0.a() * distancesTri0[1] - tri0.b() * distancesTri0[0]) /
1292 (distancesTri0[0] - distancesTri0[1])
1296 if( mag(distancesTri0[1]) < distTol )
1298 intersectionLine0.append(tri0.b());
1300 else if( distancesTri0[1] * distancesTri0[2] < 0.0 )
1302 intersectionLine0.append
1304 (tri0.b() * distancesTri0[2] - tri0.c() * distancesTri0[1]) /
1305 (distancesTri0[1] - distancesTri0[2])
1309 if( mag(distancesTri0[2]) < distTol )
1311 intersectionLine0.append(tri0.c());
1313 else if( distancesTri0[2] * distancesTri0[0] < 0.0 )
1315 intersectionLine0.append
1317 (tri0.c() * distancesTri0[0] - tri0.a() * distancesTri0[2]) /
1318 (distancesTri0[2] - distancesTri0[0])
1324 //- these triangles are in the same plane
1325 //- check if they overlap
1326 return doTrianglesOverlap(tri0, tri1, intersectionPoints, distTol);
1329 //- distance of the points of the second triangle from the plane
1330 //- of the first triangle
1331 FixedList<scalar, 3> distancesTri1;
1332 distancesTri1[0] = (tri1.a() - tri0.a()) & n0;
1333 distancesTri1[1] = (tri1.b() - tri0.a()) & n0;
1334 distancesTri1[2] = (tri1.c() - tri0.a()) & n0;
1336 forAll(distancesTri1, i)
1337 if( mag(distancesTri1[i]) < distTol )
1338 distancesTri1[i] = 0.0;
1340 hasPositive = false;
1341 hasNegative = false;
1344 DynList<point, 2> intersectionLine1;
1345 forAll(distancesTri1, pI)
1347 if( distancesTri1[pI] >= distTol )
1351 else if( distancesTri1[pI] <= -distTol )
1363 (hasPositive && !hasNegative && !hasZero) ||
1364 (hasNegative && !hasPositive && !hasZero)
1367 //- there can be no intersection
1368 intersectionPoints.clear();
1373 (hasPositive && (hasNegative || hasZero)) ||
1374 (hasNegative && (hasPositive || hasZero))
1377 //- find points on the intersection line
1378 if( mag(distancesTri1[0]) < distTol)
1380 intersectionLine1.append(tri1.a());
1382 else if( distancesTri1[0] * distancesTri1[1] < 0.0 )
1384 intersectionLine1.append
1386 (tri1.a() * distancesTri1[1] - tri1.b() * distancesTri1[0]) /
1387 (distancesTri1[0] - distancesTri1[1])
1391 if( mag(distancesTri1[1]) < distTol)
1393 intersectionLine1.append(tri1.b());
1395 else if( distancesTri1[1] * distancesTri1[2] < 0.0 )
1397 intersectionLine1.append
1399 (tri1.b() * distancesTri1[2] - tri1.c() * distancesTri1[1]) /
1400 (distancesTri1[1] - distancesTri1[2])
1404 if( mag(distancesTri1[2]) < distTol)
1406 intersectionLine1.append(tri1.c());
1408 else if( distancesTri1[2] * distancesTri1[0] < 0.0 )
1409 intersectionLine1.append
1411 (tri1.c() * distancesTri1[0] - tri1.a() * distancesTri1[2]) /
1412 (distancesTri1[2] - distancesTri1[0])
1417 //- these triangles are in the same plane
1418 //- check if they overlap
1419 return doTrianglesOverlap(tri0, tri1, intersectionPoints, distTol);
1422 //- calculate the direction of the intersection line
1423 vector vec = n0 ^ n1;
1425 //- n0 and n1 are nearly coplanar, try overlap intersection
1426 if( magSqr(vec) < SMALL )
1428 //- these triangles are in the same plane
1429 return doTrianglesOverlap(tri0, tri1, intersectionPoints, distTol);
1432 //- calculate intervals on the intersection line
1433 scalar t0Min(VGREAT), t0Max(-VGREAT);
1434 point p0Min(vector::zero), p0Max(vector::zero);
1435 forAll(intersectionLine0, i)
1437 const scalar t = intersectionLine0[i] & vec;
1442 p0Min = intersectionLine0[i];
1447 p0Max = intersectionLine0[i];
1451 scalar t1Min(VGREAT), t1Max(-VGREAT);
1452 point p1Min(vector::zero), p1Max(vector::zero);
1453 forAll(intersectionLine1, i)
1455 const scalar t = intersectionLine1[i] & vec;
1460 p1Min = intersectionLine1[i];
1465 p1Max = intersectionLine1[i];
1469 if( (t1Min <= t0Max) && (t1Max >= t0Min) )
1471 intersectionPoints.setSize(2);
1472 intersectionPoints[0] = p1Min;
1473 intersectionPoints[1] = p0Max;
1477 else if( (t0Min <= t1Max) && (t0Max >= t1Min) )
1479 intersectionPoints.setSize(2);
1480 intersectionPoints[0] = p0Min;
1481 intersectionPoints[1] = p1Max;
1486 intersectionPoints.setSize(0);
1490 inline bool pointInsideFace
1495 const pointField& fp,
1496 const scalar distTol
1499 const edgeList fe = f.edges();
1502 if( mag(p - fp[f[pI]]) < distTol )
1505 vector pv = p - fp[f[pI]];
1508 vector lv = n ^ fe[pI].vec(fp);
1511 const scalar d = pv & lv;
1521 inline bool pointInsideFace
1525 const pointField& fp,
1526 const scalar distTol
1529 const point c = f.centre(fp);
1530 const scalar tolSqr = sqr(distTol);
1534 const edge fe = f.faceEdge(eI);
1536 triangle<point, point> tri
1543 const point np = nearestPointOnTheTriangle(tri, p);
1545 if( magSqr(np - p) <= tolSqr )
1552 inline bool isFaceConvexAndOk
1555 const pointField& fp,
1556 DynList<bool>& OkPoints
1561 vector normal = f.normal(fp);
1562 const scalar magN = mag(normal);
1564 //- face has zero area. All points are inverted
1567 OkPoints.setSize(f.size());
1573 normal /= (magN + VSMALL);
1575 //- project points into the plane formed by the face centre
1576 //- and the face normal
1577 plane pl(f.centre(fp), normal);
1579 DynList<point> projFace(f.size());
1581 projFace[pI] = pl.nearestPoint(fp[f[pI]]);
1583 //- calculate normalised edge vectors
1584 DynList<vector> edgeVecs(f.size());
1587 vector& v = edgeVecs[eI];
1589 const edge e = f.faceEdge(eI);
1591 v /= (mag(v) + VSMALL);
1594 //- check if the face is convex
1595 OkPoints.setSize(f.size());
1598 const vector& pv = edgeVecs[f.rcIndex(pI)];
1599 const vector& nv = edgeVecs[pI];
1601 if( ((pv ^ nv) & normal) >= -0.05 )
1603 OkPoints[pI] = true;
1607 OkPoints[pI] = false;
1615 inline point nearestPointOnTheEdge
1617 const point& edgePoint0,
1618 const point& edgePoint1,
1622 const vector e = edgePoint1 - edgePoint0;
1623 const scalar d = mag(e);
1624 const vector k = p - edgePoint0;
1626 if( d < ROOTVSMALL )
1629 return edgePoint0 + ((e / (d*d)) * (e & k));
1632 inline point nearestPointOnTheEdgeExact
1634 const point& edgePoint0,
1635 const point& edgePoint1,
1639 const vector e = edgePoint1 - edgePoint0;
1640 const scalar dSq = magSqr(e);
1641 const vector k = p - edgePoint0;
1646 const scalar t = (e & k) / (dSq + VSMALL);
1656 return edgePoint0 + (e * t);
1659 inline scalar distanceOfPointFromTheEdge
1661 const point& edgePoint0,
1662 const point& edgePoint1,
1666 return mag(nearestPointOnTheEdge(edgePoint0, edgePoint1, p) - p);
1669 inline label numberOfFaceGroups
1671 const labelHashSet& containedElements,
1672 const point& centre,
1674 const triSurf& surface
1677 const pointField& points = surface.points();
1678 const edgeLongList& edges = surface.edges();
1679 const VRWGraph& faceEdges = surface.facetEdges();
1680 const VRWGraph& edgeFaces = surface.edgeFacets();
1682 labelHashSet triaInRange(containedElements.size());
1683 const scalar rangeSq = range * range;
1684 forAllConstIter(labelHashSet, containedElements, it)
1686 const point p = nearestPointOnTheTriangle(it.key(), surface, centre);
1687 if( magSqr(p - centre) < rangeSq )
1688 triaInRange.insert(it.key());
1691 Map<label> elGroup(triaInRange.size());
1692 Map<label> testEdge(triaInRange.size());
1696 DynList<label> front;
1698 forAllConstIter(labelHashSet, triaInRange, it)
1699 if( !elGroup.found(it.key()) )
1702 front.append(it.key());
1703 elGroup.insert(it.key(), nGroups);
1705 while( front.size() )
1707 const label fLabel = front.removeLastElement();
1709 forAllRow(faceEdges, fLabel, feI)
1711 const label edgeI = faceEdges(fLabel, feI);
1713 //- check if the edge intersects the bounding box
1714 if( testEdge.found(edgeI) )
1716 if( !testEdge[edgeI] )
1721 const point& s = points[edges[edgeI][0]];
1722 const point& e = points[edges[edgeI][1]];
1723 const point np = nearestPointOnTheEdge(s, e, centre);
1724 if( magSqr(np - centre) < rangeSq )
1726 testEdge.insert(edgeI, 1);
1730 testEdge.insert(edgeI, 0);
1735 forAllRow(edgeFaces, edgeI, efI)
1737 const label nei = edgeFaces(edgeI, efI);
1740 triaInRange.found(nei) &&
1744 elGroup.insert(nei, nGroups);
1757 inline label numberOfEdgeGroups
1759 const labelHashSet& containedEdges,
1760 const point& centre,
1762 const triSurf& surface
1765 const pointField& points = surface.points();
1766 const edgeLongList& edges = surface.edges();
1767 const VRWGraph& pointEdges = surface.pointEdges();
1769 const scalar rangeSq = range * range;
1770 labelHashSet edgesInRange(containedEdges.size());
1771 forAllConstIter(labelHashSet, containedEdges, it)
1773 const edge& e = edges[it.key()];
1774 const point& sp = points[e[0]];
1775 const point& ep = points[e[1]];
1777 const point p = nearestPointOnTheEdgeExact(sp, ep, centre);
1778 if( magSqr(p - centre) < rangeSq )
1779 edgesInRange.insert(it.key());
1782 Map<label> elGroup(edgesInRange.size());
1783 Map<label> pointTest(edgesInRange.size());
1787 DynList<label> front;
1789 forAllConstIter(labelHashSet, edgesInRange, it)
1790 if( !elGroup.found(it.key()) )
1793 front.append(it.key());
1794 elGroup.insert(it.key(), nGroups);
1796 while( front.size() )
1798 const label eLabel = front.removeLastElement();
1799 const edge& e = edges[eLabel];
1801 for(label i=0;i<2;++i)
1803 if( pointTest.found(e[i]) )
1805 if( !pointTest[e[i]] )
1810 if( magSqr(points[e[i]] - centre) < rangeSq )
1812 pointTest.insert(e[i], 1);
1816 pointTest.insert(e[i], 0);
1821 forAllRow(pointEdges, e[i], peI)
1823 const label nei = pointEdges(e[i], peI);
1825 if( edgesInRange.found(nei) && !elGroup.found(nei) )
1827 elGroup.insert(nei, nGroups);
1840 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
1842 } // End namespace help
1844 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
1846 } // End namespace Foam
1848 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //