Go to the documentation of this file.
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]
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();
void writeStats(Ostream &os) const
Write some statistics.
const T & second() const noexcept
Return second element, which is also the last element.
static autoPtr< T > New(Args &&... args)
Construct autoPtr of T with forwarding arguments.
List< label > labelList
A List of labels.
triSurface subsetMesh(const UList< bool > &include, labelList &pointMap, labelList &faceMap) const
Return a new surface subsetted on the selected faces.
const labelListList & classification() const
For every intersection the classification status.
Defines the attributes of an object for which implicit objectRegistry management is supported,...
const dimensionedScalar mp
Proton mass.
const Cmpt & x() const
Access to the vector x component.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
A class for handling words, derived from Foam::string.
A class for handling file names.
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
static constexpr const zero Zero
Global zero (0)
Type sample01()
Return a sample whose components lie in the range [0,1].
label nEdges() const
Return number of edges in patch.
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
CGAL::Segment_3< K > Segment
static void addNote(const string ¬e)
Add extra notes for the usage information.
void append(const T &val)
Append an element at the end of the list.
IOoject and searching on triSurface.
Ostream & endl(Ostream &os)
Add newline and flush stream.
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Helper class to search on triSurface.
const Cmpt & z() const
Access to the vector z component.
booleanOpType
Enumeration listing the possible volume operator types.
#define forAll(list, i)
Loop across all elements in list.
Pair< label > labelPair
A pair of labels.
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
static const Enum< booleanOpType > booleanOpTypeNames
label start() const
Return start (first) vertex label.
virtual void scalePoints(const scalar scaleFactor)
Scale points. A non-positive factor is ignored.
label removeDegenerates(const label nIters, const triSurface &surf1, const triSurfaceSearch &query2, const scalarField &surf1PointTol, pointField &points1)
Resolve ties. Shuffles points so all edge - face intersections.
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
An enumeration wrapper for classification of a location as being inside/outside of a volume.
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
virtual void movePoints(const pointField &pts)
Move points.
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Basic surface-surface intersection description. Constructed from two surfaces it creates a descriptio...
void write(Ostream &os) const
Write to Ostream in simple OpenFOAM format.
Triangulated surface description with patch information.
messageStream Info
Information stream (uses stdout - output is on the master only)
static const Enum< volumeType::type > names
Names for the classification enumeration.
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
const labelListList & pointEdges() const
Return point-edge addressing.
const pointField & points() const
Return points.
static scalarField minEdgeLength(const triSurface &surf)
Calculate min edge length for every surface point.
static scalar cosNormalAngleTol_
Angular closeness tolerance for treating normals as the same.
CGAL data structures used for triSurface handling.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
const edgeList & edges() const
Return edges.
label nPoints() const
Return number of points supporting patch faces.
const Field< point_type > & points() const
Return reference to global points.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
errorManip< error > abort(error &err)
virtual bool write(const bool valid=true) const
Give precedence to the regIOobject write.
errorManipArg< error, int > exit(error &err, const int errNo=1)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
List< labelList > labelListList
A List of labelList.
const Cmpt & y() const
Access to the vector y component.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
forAllConstIters(mixture.phases(), phase)
vector vec(const UList< point > &pts) const
Return the vector (end - start)
virtual void writeStats(Ostream &os) const
Dump some information.
CGAL::Polyhedron_3< K, My_items > Polyhedron
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
static word meshSubDir
Return the mesh sub-directory name (usually "triSurface")
const dimensionedScalar e
Elementary charge.
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Triangle with additional region number.
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
A bounding box defined in terms of min/max extrema points.
void merge(const edgeIntersections &, const labelList &edgeMap, const labelList &faceMap, const bool merge=true)
Merge (or override) edge intersection for a subset.
Holder of intersections of edges of a surface with another surface. Optionally shuffles around points...
static void noParallel()
Remove the parallel options.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
const word & constant() const
Return constant name.
static void addOption(const word &optName, const string ¶m="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Foam::argList args(argc, argv)
void cross(FieldField< Field1, typename crossProduct< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
void writeObj(const fileName &prefix) const
Write all components of the extendedEdgeMesh as obj files.
fileName path() const
The complete path.
bool found(const word &optName) const
Return true if the named option is found.
UIndirectList< label > labelUIndList
UIndirectList of labels.