93 #include <CGAL/AABB_tree.h>
94 #include <CGAL/AABB_traits.h>
95 #include <CGAL/AABB_face_graph_triangle_primitive.h>
98 typedef CGAL::AABB_face_graph_triangle_primitive
102 typedef CGAL::AABB_traits<K, Primitive> Traits;
103 typedef CGAL::AABB_tree<Traits> Tree;
105 typedef boost::optional
107 Tree::Intersection_and_primitive_id<Segment>::Type
108 > Segment_intersection;
113 using namespace Foam;
117 bool intersectSurfaces
123 bool hasMoved =
false;
125 for (label iter = 0; iter < 10; iter++)
127 Info<<
"Determining intersections of surface edges with itself" <<
endl;
176 Info<<
"Surface has been moved. Writing to " << newFile <<
endl;
186 bool intersectSurfaces
194 bool hasMoved1 =
false;
195 bool hasMoved2 =
false;
197 for (label iter = 0; iter < 10; iter++)
199 Info<<
"Determining intersections of surf1 edges with surf2"
245 Info<<
"Determining intersections of surf2 edges with surf1"
288 if (nIters1 == 0 && nIters2 == 0)
290 Info<<
"** Resolved all intersections to be proper edge-face pierce"
299 Info<<
"Surface 1 has been moved. Writing to " << newFile
301 surf1.
write(newFile);
307 Info<<
"Surface 2 has been moved. Writing to " << newFile
309 surf2.
write(newFile);
312 return hasMoved1 || hasMoved2;
316 label calcNormalDirection
319 const vector& otherNormal,
329 label nDir = ((
cross & fC0tofE0) > 0.0 ? 1 : -1);
331 nDir *= ((otherNormal & fC0tofE0) > 0.0 ? -1 : 1);
360 Info<<
"Determining intersections of surf1 edges with surf2 faces"
372 Info<<
"Determining intersections of surf2 edges with surf1 faces"
389 void visitPointRegion
394 const label startEdgeI,
395 const label startFaceI,
399 const labelList& eFaces =
s.edgeFaces()[startEdgeI];
401 if (eFaces.size() == 2)
404 if (eFaces[0] == startFaceI)
406 nextFaceI = eFaces[1];
408 else if (eFaces[1] == startFaceI)
410 nextFaceI = eFaces[0];
422 label index =
s.pointFaces()[pointI].find(nextFaceI);
424 if (pFacesZone[index] == -1)
427 pFacesZone[index] = zoneI;
430 const labelList& fEdges =
s.faceEdges()[nextFaceI];
432 label nextEdgeI = -1;
436 label edgeI = fEdges[i];
437 const edge&
e =
s.edges()[edgeI];
439 if (edgeI != startEdgeI && (
e[0] == pointI ||
e[1] == pointI))
450 <<
"Problem: cannot find edge out of " << fEdges
451 <<
"on face " << nextFaceI <<
" that uses point " << pointI
481 label nNonManifold = 0;
492 for (; index < pFacesZone.size(); index++)
494 if (pFacesZone[index] == -1)
497 pFacesZone[index] = zoneI;
499 label faceI =
pFaces[index];
505 label edgeI = fEdges[fEdgeI];
506 const edge&
e = edges[edgeI];
508 if (
e[0] == pointI ||
e[1] == pointI)
528 for (label zoneI = 1; zoneI <
nZones; zoneI++)
530 label newPointI = newPoints.size();
531 newPointMap.append(
s.meshPoints()[pointI]);
532 newPoints.append(
s.points()[
s.meshPoints()[pointI]]);
536 if (pFacesZone[index] == zoneI)
538 label faceI =
pFaces[index];
542 if (localF[fp] == pointI)
544 newFaces[faceI][fp] = newPointI;
555 Info<<
"Duplicating " << nNonManifold <<
" points out of " <<
s.nPoints()
557 if (nNonManifold > 0)
559 triSurface dupSurf(newFaces,
s.patches(), newPoints,
true);
564 const labelList& dupMp = dupSurf.meshPoints();
569 label dupMeshPointI = dupMp[pointI];
570 label meshPointI = newPointMap[dupMeshPointI];
571 dupPointMap[pointI] = mpm[meshPointI];
575 forAll(dupPointMap, pointI)
577 const point& dupPt = dupSurf.points()[dupMp[pointI]];
578 label sLocalPointI = dupPointMap[pointI];
579 label sMeshPointI =
s.meshPoints()[sLocalPointI];
580 const point& sPt =
s.points()[sMeshPointI];
582 if (
mag(dupPt-sPt) > SMALL)
621 std::vector<Segment_intersection> segments;
624 const edge&
e = edges[edgeI];
629 K::Segment_3 segment_query
636 tree.all_intersections(segment_query, std::back_inserter(segments));
639 for (
const Segment_intersection& intersect : segments)
644 const Point* ptPtr = boost::get<Point>(&(intersect->first))
649 CGAL::to_double(ptPtr->x()),
650 CGAL::to_double(ptPtr->y()),
651 CGAL::to_double(ptPtr->z())
654 #if defined (CGAL_VERSION_NR) && (CGAL_VERSION_NR < 1041400000)
655 Polyhedron::Face_handle
f = (intersect->second);
658 Polyhedron::Face_handle
f = (intersect->second).first;
661 intersections[edgeI].
append
671 classifications[edgeI].append(-1);
676 const Segment* sPtr = boost::get<Segment>(&(intersect->first))
679 #if defined (CGAL_VERSION_NR) && (CGAL_VERSION_NR < 1041400000)
680 Polyhedron::Face_handle
f = (intersect->second);
683 Polyhedron::Face_handle
f = (intersect->second).first;
695 CGAL::to_double(sPtr->source().x()),
696 CGAL::to_double(sPtr->source().y()),
697 CGAL::to_double(sPtr->source().z())
702 CGAL::to_double(sPtr->target().x()),
703 CGAL::to_double(sPtr->target().y()),
704 CGAL::to_double(sPtr->target().z())
708 intersections[edgeI].append
718 classifications[edgeI].append(2);
732 labelPair edgeIntersectionsAndShuffleCGAL
747 const Tree tree(
p.facets_begin(),
p.facets_end(),
p);
755 for (label iter = 0; iter < 5; iter++)
758 Info<<
"Determining intersections of " << surf1.
nEdges()
759 <<
" edges with surface of " << label(tree.size()) <<
" triangles"
761 cuts = edgeIntersectionsCGAL
768 Info<<
"Determined intersections:" <<
nl
769 <<
" edges : " << surf1.
nEdges() <<
nl
770 <<
" non-degenerate cuts : " << cuts.first() <<
nl
771 <<
" degenerate cuts : " << cuts.second() <<
nl
774 if (cuts.second() == 0)
779 Info<<
"Shuffling conflicting points" <<
endl;
784 const point p05(0.5, 0.5, 0.5);
793 const edge&
e = edges[edgeI];
797 surf1Points[
mp[
e[eI]]] += surf1PointTol[
e[eI]]*d;
817 if (pointMap.size() != subSurf.
nPoints())
831 forAll(subEdges, subEdgeI)
833 const edge& subE = subEdges[subEdgeI];
836 label start = pointMap[subE[0]];
837 label
end = pointMap[subE[1]];
838 const labelList& pEdges = pointEdges[start];
841 label edgeI = pEdges[pEdgeI];
842 const edge&
e = edges[edgeI];
844 if (
e.otherVertex(start) ==
end)
846 if (edgeMap[subEdgeI] == -1)
848 edgeMap[subEdgeI] = edgeI;
850 else if (edgeMap[subEdgeI] != edgeI)
853 << subE <<
" points:"
855 <<
" matches to " << edgeI
857 <<
" but also " << edgeMap[subEdgeI]
859 << edges[edgeMap[subEdgeI]].line(surf.
localPoints())
866 if (edgeMap[subEdgeI] == -1)
869 << subE <<
" at:" << subSurf.
localPoints()[subE[0]]
879 void calcEdgeCutsCGAL
892 Info<<
"Constructing CGAL surface ..." <<
endl;
896 Info<<
"Constructing CGAL tree ..." <<
endl;
897 const Tree tree(
p.facets_begin(),
p.facets_end(),
p);
899 edgeIntersectionsCGAL
909 Info<<
"Constructing CGAL surface ..." <<
endl;
913 Info<<
"Constructing CGAL tree ..." <<
endl;
914 const Tree tree(
p.facets_begin(),
p.facets_end(),
p);
916 edgeIntersectionsCGAL
942 for (label iter = 0; iter < 10; iter++)
945 cuts1 = edgeIntersectionsAndShuffleCGAL
955 cuts2 = edgeIntersectionsAndShuffleCGAL
973 void calcEdgeCutsBitsCGAL
989 Info<<
"Surface triangles " << surf1.size()
990 <<
" number of zones (orientation or non-manifold):"
1001 Info<<
"Surface triangles " << surf2.size()
1002 <<
" number of zones (orientation or non-manifold):"
1007 if (nZones1 == 1 && nZones2 == 1)
1032 for (label zone1I = 0; zone1I < nZones1; zone1I++)
1035 boolList includeMap1(surf1.size(),
false);
1039 if (zone1[faceI] == zone1I)
1041 includeMap1[faceI] =
true;
1060 dupNonManifoldPoints(subSurf1, pointMap1);
1065 subSurf1.meshPoints(),
1080 for (label zone2I = 0; zone2I < nZones2; zone2I++)
1083 boolList includeMap2(surf2.size(),
false);
1087 if (zone2[faceI] == zone2I)
1089 includeMap2[faceI] =
true;
1109 subSurf2.meshPoints(),
1114 if (!subBb2.overlaps(subBb1))
1121 dupNonManifoldPoints(subSurf2, pointMap2);
1151 label subMeshPointI = subSurf2.meshPoints()[i];
1152 label meshPointI = surf2.
meshPoints()[pointMap2[i]];
1153 points2[meshPointI] = subSurf2.points()[subMeshPointI];
1159 edgeCuts1.
merge(subEdgeCuts1, edgeMap1, faceMap2);
1160 edgeCuts2.
merge(subEdgeCuts2, edgeMap2, faceMap1);
1169 label subMeshPointI = subSurf1.meshPoints()[i];
1170 label meshPointI = surf1.
meshPoints()[pointMap1[i]];
1171 points1[meshPointI] = subSurf1.points()[subMeshPointI];
1237 const bool surf1Baffle,
1238 const bool surf2Baffle,
1239 const bool invertedSpace,
1255 label nFeatEds = inter.cutEdges().size();
1273 const label cutEdgeI = iter.val();
1275 const edge& fE = inter.cutEdges()[cutEdgeI];
1283 edgeDirections[cutEdgeI] = fE.
vec(inter.cutPoints());
1285 normals.append(norm1);
1286 eNormals.
append(normals.size() - 1);
1303 edgeDirections[cutEdgeI],
1304 s1[facePair.first()].centre(s1.
points()),
1305 inter.cutPoints()[fE.
start()]
1310 normals.append(norm2);
1311 eNormals.
append(normals.size() - 1);
1329 edgeDirections[cutEdgeI],
1331 inter.cutPoints()[fE.
start()]
1339 normals.append(norm2);
1357 edgeDirections[cutEdgeI],
1359 inter.cutPoints()[fE.
start()]
1364 eNormals.
append(normals.size() - 1);
1369 normals.append(norm1);
1387 edgeDirections[cutEdgeI],
1388 s1[facePair.first()].centre(s1.
points()),
1389 inter.cutPoints()[fE.
start()]
1394 eNormals.
append(normals.size() - 1);
1399 label internalStart = -1;
1400 label nIntOrExt = 0;
1403 label nMultiple = 0;
1407 label nEdNorms = edgeNormals[eI].size();
1413 else if (nEdNorms == 2)
1415 const vector& n0(normals[edgeNormals[eI][0]]);
1416 const vector& n1(normals[edgeNormals[eI][1]]);
1427 else if (nEdNorms > 2)
1443 internalStart = nIntOrExt;
1451 internalStart = nIntOrExt;
1462 internalStart = nIntOrExt;
1467 <<
"Unsupported booleanSurface:booleanOpType and space "
1468 << action <<
" " << invertedSpace
1482 forAll(edgeNormalsTmp, i)
1484 edgeNormalsTmp[i] = edgeNormals[i];
1487 forAll(normalDirectionsTmp, i)
1489 normalDirectionsTmp[i] = normalDirections[i];
1507 nIntOrExt + nFlat + nOpen,
1510 normalVolumeTypesTmp,
1512 normalDirectionsTmp,
1521 int main(
int argc,
char *argv[])
1525 "Generates the extendedFeatureEdgeMesh for the interface created by"
1526 " a boolean operation on two surfaces."
1533 "One of (intersection | union | difference)"
1542 "Geometry scaling factor (both surfaces)"
1547 "Mark surface 1 as a baffle"
1553 "Mark surface 2 as a baffle"
1559 "Perturb surface points to escape degenerate intersections"
1565 "Do the surfaces have inverted space orientation, "
1566 "i.e. a point at infinity is considered inside. "
1567 "This is only sensible for union and intersection."
1573 "((surface1 volumeType) .. (surfaceN volumeType))",
1574 "Trim resulting intersection with additional surfaces;"
1575 " volumeType is 'inside' (keep (parts of) edges that are inside)"
1576 ", 'outside' (keep (parts of) edges that are outside) or"
1577 " 'mixed' (keep all)"
1592 if (!validActions.found(action))
1595 <<
"Unsupported action " << action <<
endl
1596 <<
"Supported actions:" << validActions <<
nl
1604 Info<<
"Trimming edges with " << surfaceAndSide <<
endl;
1612 Info<<
"Reading surface " << surf1Name <<
endl;
1623 if (scaleFactor > 0)
1625 Info<<
"Scaling : " << scaleFactor <<
nl;
1629 Info<< surf1Name <<
" statistics:" <<
endl;
1634 Info<<
"Reading surface " << surf2Name <<
endl;
1645 if (scaleFactor > 0)
1647 Info<<
"Scaling : " << scaleFactor <<
nl;
1651 Info<< surf2Name <<
" statistics:" <<
endl;
1655 const bool surf1Baffle =
args.
found(
"surf1Baffle");
1656 const bool surf2Baffle =
args.
found(
"surf2Baffle");
1661 const bool invertedSpace =
args.
found(
"invertedSpace");
1666 <<
"Inverted space only makes sense for union or intersection."
1683 calcEdgeCutsBitsCGAL
1698 +
fileName(surf2Name).nameLessExt()
1709 sFeatFileName +
".extendedFeatureEdgeMesh",
1711 "extendedFeatureEdgeMesh",
1729 forAll(surfaceAndSide, trimI)
1731 const word& trimName = surfaceAndSide[trimI].first();
1737 Info<<
"Reading trim surface " << trimName <<
endl;
1751 Info<< trimName <<
" statistics:" <<
endl;
1752 trimSurf.writeStats(
Info);
1779 sFeatFileName +
".eMesh",
1791 Info<<
nl <<
"Writing featureEdgeMesh to "
1792 << bfeMesh.objectPath() <<
endl;
1794 bfeMesh.regIOobject::write();