Go to the documentation of this file.
70 #include "triSurface.H"
87 #include <CGAL/AABB_tree.h>
88 #include <CGAL/AABB_traits.h>
89 #include <CGAL/AABB_face_graph_triangle_primitive.h>
92 typedef CGAL::AABB_face_graph_triangle_primitive
96 typedef CGAL::AABB_traits<K, Primitive> Traits;
97 typedef CGAL::AABB_tree<Traits> Tree;
99 typedef boost::optional<Tree::Intersection_and_primitive_id<Segment>::Type >
100 Segment_intersection;
105 using namespace Foam;
109 bool intersectSurfaces
115 bool hasMoved =
false;
117 for (
label iter = 0; iter < 10; iter++)
119 Info<<
"Determining intersections of surface edges with itself" <<
endl;
168 Info<<
"Surface has been moved. Writing to " << newFile <<
endl;
178 bool intersectSurfaces
186 bool hasMoved1 =
false;
187 bool hasMoved2 =
false;
189 for (
label iter = 0; iter < 10; iter++)
191 Info<<
"Determining intersections of surf1 edges with surf2"
237 Info<<
"Determining intersections of surf2 edges with surf1"
280 if (nIters1 == 0 && nIters2 == 0)
282 Info<<
"** Resolved all intersections to be proper edge-face pierce"
291 Info<<
"Surface 1 has been moved. Writing to " << newFile
293 surf1.
write(newFile);
299 Info<<
"Surface 2 has been moved. Writing to " << newFile
301 surf2.
write(newFile);
304 return hasMoved1 || hasMoved2;
308 label calcNormalDirection
311 const vector& otherNormal,
320 vector fC0tofE0 = faceCentre - pointOnEdge;
321 fC0tofE0 /=
mag(fC0tofE0);
323 label nDir = ((
cross & fC0tofE0) > 0.0 ? 1 : -1);
325 nDir *= ((otherNormal & fC0tofE0) > 0.0 ? -1 : 1);
354 Info<<
"Determining intersections of surf1 edges with surf2 faces"
366 Info<<
"Determining intersections of surf2 edges with surf1 faces"
383 void visitPointRegion
388 const label startEdgeI,
389 const label startFaceI,
393 const labelList& eFaces =
s.edgeFaces()[startEdgeI];
395 if (eFaces.
size() == 2)
398 if (eFaces[0] == startFaceI)
400 nextFaceI = eFaces[1];
402 else if (eFaces[1] == startFaceI)
404 nextFaceI = eFaces[0];
418 if (pFacesZone[index] == -1)
421 pFacesZone[index] = zoneI;
424 const labelList& fEdges =
s.faceEdges()[nextFaceI];
426 label nextEdgeI = -1;
430 label edgeI = fEdges[i];
431 const edge&
e =
s.edges()[edgeI];
433 if (edgeI != startEdgeI && (
e[0] == pointI ||
e[1] == pointI))
444 <<
"Problem: cannot find edge out of " << fEdges
445 <<
"on face " << nextFaceI <<
" that uses point " << pointI
475 label nNonManifold = 0;
487 for (; index < pFacesZone.
size(); index++)
489 if (pFacesZone[index] == -1)
491 label zoneI = nZones++;
492 pFacesZone[index] = zoneI;
500 label edgeI = fEdges[fEdgeI];
501 const edge&
e = edges[edgeI];
503 if (
e[0] == pointI ||
e[1] == pointI)
523 for (
label zoneI = 1; zoneI < nZones; zoneI++)
525 label newPointI = newPoints.size();
526 newPointMap.append(
s.meshPoints()[pointI]);
527 newPoints.append(
s.points()[
s.meshPoints()[pointI]]);
531 if (pFacesZone[index] == zoneI)
537 if (localF[fp] == pointI)
539 newFaces[faceI][fp] = newPointI;
550 Info<<
"Duplicating " << nNonManifold <<
" points out of " <<
s.nPoints()
552 if (nNonManifold > 0)
554 triSurface dupSurf(newFaces,
s.patches(), newPoints,
true);
559 const labelList& dupMp = dupSurf.meshPoints();
564 label dupMeshPointI = dupMp[pointI];
565 label meshPointI = newPointMap[dupMeshPointI];
566 dupPointMap[pointI] = mpm[meshPointI];
570 forAll(dupPointMap, pointI)
572 const point& dupPt = dupSurf.points()[dupMp[pointI]];
573 label sLocalPointI = dupPointMap[pointI];
574 label sMeshPointI =
s.meshPoints()[sLocalPointI];
575 const point& sPt =
s.points()[sMeshPointI];
577 if (
mag(dupPt-sPt) > SMALL)
616 std::vector<Segment_intersection> segments;
619 const edge&
e = edges[edgeI];
624 K::Segment_3 segment_query
631 tree.all_intersections(segment_query, std::back_inserter(segments));
635 std::vector<Segment_intersection>::const_iterator iter =
637 end = segments.end();
643 if (
const Point* ptPtr = boost::get<Point>(&((*iter)->first)))
647 CGAL::to_double(ptPtr->x()),
648 CGAL::to_double(ptPtr->y()),
649 CGAL::to_double(ptPtr->z())
652 Polyhedron::Face_handle
f = (*iter)->second;
654 intersections[edgeI].
append
664 classifications[edgeI].append(-1);
669 const Segment* sPtr = boost::get<Segment>(&((*iter)->first))
676 Polyhedron::Face_handle
f = (*iter)->second;
682 CGAL::to_double(sPtr->source().x()),
683 CGAL::to_double(sPtr->source().y()),
684 CGAL::to_double(sPtr->source().z())
689 CGAL::to_double(sPtr->target().x()),
690 CGAL::to_double(sPtr->target().y()),
691 CGAL::to_double(sPtr->target().z())
695 intersections[edgeI].append
705 classifications[edgeI].append(2);
719 labelPair edgeIntersectionsAndShuffleCGAL
734 const Tree tree(
p.facets_begin(),
p.facets_end(),
p);
742 for (
label iter = 0; iter < 5; iter++)
745 Info<<
"Determining intersections of " << surf1.
nEdges()
746 <<
" edges with surface of " <<
label(tree.size()) <<
" triangles"
748 cuts = edgeIntersectionsCGAL
755 Info<<
"Determined intersections:" <<
nl
756 <<
" edges : " << surf1.
nEdges() <<
nl
757 <<
" non-degenerate cuts : " << cuts.first() <<
nl
758 <<
" degenerate cuts : " << cuts.second() <<
nl
761 if (cuts.second() == 0)
766 Info<<
"Shuffling conflicting points" <<
endl;
771 const point p05(0.5, 0.5, 0.5);
780 const edge&
e = edges[edgeI];
784 surf1Points[
mp[
e[eI]]] += surf1PointTol[
e[eI]]*d;
818 forAll(subEdges, subEdgeI)
820 const edge& subE = subEdges[subEdgeI];
823 label start = pointMap[subE[0]];
824 label end = pointMap[subE[1]];
825 const labelList& pEdges = pointEdges[start];
828 label edgeI = pEdges[pEdgeI];
829 const edge&
e = edges[edgeI];
831 if (
e.otherVertex(start) == end)
833 if (edgeMap[subEdgeI] == -1)
835 edgeMap[subEdgeI] = edgeI;
837 else if (edgeMap[subEdgeI] != edgeI)
840 << subE <<
" points:"
842 <<
" matches to " << edgeI
844 <<
" but also " << edgeMap[subEdgeI]
846 << edges[edgeMap[subEdgeI]].line(surf.
localPoints())
853 if (edgeMap[subEdgeI] == -1)
856 << subE <<
" at:" << subSurf.
localPoints()[subE[0]]
866 void calcEdgeCutsCGAL
879 Info<<
"Constructing CGAL surface ..." <<
endl;
883 Info<<
"Constructing CGAL tree ..." <<
endl;
884 const Tree tree(
p.facets_begin(),
p.facets_end(),
p);
886 edgeIntersectionsCGAL
896 Info<<
"Constructing CGAL surface ..." <<
endl;
900 Info<<
"Constructing CGAL tree ..." <<
endl;
901 const Tree tree(
p.facets_begin(),
p.facets_end(),
p);
903 edgeIntersectionsCGAL
929 for (
label iter = 0; iter < 10; iter++)
932 cuts1 = edgeIntersectionsAndShuffleCGAL
942 cuts2 = edgeIntersectionsAndShuffleCGAL
960 void calcEdgeCutsBitsCGAL
976 Info<<
"Surface triangles " << surf1.
size()
977 <<
" number of zones (orientation or non-manifold):"
988 Info<<
"Surface triangles " << surf2.
size()
989 <<
" number of zones (orientation or non-manifold):"
994 if (nZones1 == 1 && nZones2 == 1)
1019 for (
label zone1I = 0; zone1I < nZones1; zone1I++)
1026 if (zone1[faceI] == zone1I)
1028 includeMap1[faceI] =
true;
1047 dupNonManifoldPoints(subSurf1, pointMap1);
1052 subSurf1.meshPoints(),
1067 for (
label zone2I = 0; zone2I < nZones2; zone2I++)
1074 if (zone2[faceI] == zone2I)
1076 includeMap2[faceI] =
true;
1096 subSurf2.meshPoints(),
1101 if (!subBb2.overlaps(subBb1))
1108 dupNonManifoldPoints(subSurf2, pointMap2);
1138 label subMeshPointI = subSurf2.meshPoints()[i];
1140 points2[meshPointI] = subSurf2.points()[subMeshPointI];
1146 edgeCuts1.
merge(subEdgeCuts1, edgeMap1, faceMap2);
1147 edgeCuts2.
merge(subEdgeCuts2, edgeMap2, faceMap1);
1156 label subMeshPointI = subSurf1.meshPoints()[i];
1158 points1[meshPointI] = subSurf1.points()[subMeshPointI];
1224 const bool surf1Baffle,
1225 const bool surf2Baffle,
1226 const bool invertedSpace,
1242 label nFeatEds = inter.cutEdges().size();
1259 const label& cutEdgeI = iter();
1262 const edge& fE = inter.cutEdges()[cutEdgeI];
1270 edgeDirections[cutEdgeI] = fE.
vec(inter.cutPoints());
1272 normals.append(norm1);
1273 eNormals.
append(normals.size() - 1);
1290 edgeDirections[cutEdgeI],
1292 inter.cutPoints()[fE.
start()]
1297 normals.append(norm2);
1298 eNormals.
append(normals.size() - 1);
1316 edgeDirections[cutEdgeI],
1318 inter.cutPoints()[fE.
start()]
1326 normals.append(norm2);
1344 edgeDirections[cutEdgeI],
1346 inter.cutPoints()[fE.
start()]
1351 eNormals.
append(normals.size() - 1);
1356 normals.append(norm1);
1374 edgeDirections[cutEdgeI],
1376 inter.cutPoints()[fE.
start()]
1381 eNormals.
append(normals.size() - 1);
1386 label internalStart = -1;
1387 label nIntOrExt = 0;
1390 label nMultiple = 0;
1394 label nEdNorms = edgeNormals[eI].size();
1400 else if (nEdNorms == 2)
1402 const vector& n0(normals[edgeNormals[eI][0]]);
1403 const vector& n1(normals[edgeNormals[eI][1]]);
1414 else if (nEdNorms > 2)
1430 internalStart = nIntOrExt;
1438 internalStart = nIntOrExt;
1449 internalStart = nIntOrExt;
1454 <<
"Unsupported booleanSurface:booleanOpType and space "
1455 << action <<
" " << invertedSpace
1469 forAll(edgeNormalsTmp, i)
1471 edgeNormalsTmp[i] = edgeNormals[i];
1474 forAll(normalDirectionsTmp, i)
1476 normalDirectionsTmp[i] = normalDirections[i];
1496 nIntOrExt + nFlat + nOpen,
1499 normalVolumeTypesTmp,
1501 normalDirectionsTmp,
1511 int main(
int argc,
char *argv[])
1521 "Mark surface 1 as a baffle"
1527 "Mark surface 2 as a baffle"
1533 "Perturb surface points to escape degenerate intersections"
1539 "do the surfaces have inverted space orientation, "
1540 "i.e. a point at infinity is considered inside. "
1541 "This is only sensible for union and intersection."
1547 "((surface1 volumeType) .. (surfaceN volumeType))",
1548 "Trim resulting intersection with additional surfaces;"
1549 " volumeType is 'inside' (keep (parts of) edges that are inside)"
1550 ", 'outside' (keep (parts of) edges that are outside) or"
1551 " 'mixed' (keep all)"
1565 if (!validActions.
found(action))
1568 <<
"Unsupported action " << action <<
endl
1576 Info<<
"Trimming edges with " << surfaceAndSide <<
endl;
1581 Info<<
"Reading surface " << surf1Name <<
endl;
1593 Info<< surf1Name <<
" statistics:" <<
endl;
1598 Info<<
"Reading surface " << surf2Name <<
endl;
1610 Info<< surf2Name <<
" statistics:" <<
endl;
1625 <<
"Inverted space only makes sense for union or intersection."
1642 calcEdgeCutsBitsCGAL
1668 sFeatFileName +
".extendedFeatureEdgeMesh",
1670 "extendedFeatureEdgeMesh",
1688 forAll(surfaceAndSide, trimI)
1690 const word& trimName = surfaceAndSide[trimI].first();
1696 Info<<
"Reading trim surface " << trimName <<
endl;
1710 Info<< trimName <<
" statistics:" <<
endl;
1711 trimSurf.writeStats(
Info);
1740 sFeatFileName +
".eMesh",
1752 Info<<
nl <<
"Writing featureEdgeMesh to "
1753 << bfeMesh.objectPath() <<
endl;
1755 bfeMesh.regIOobject::write();
static SLList< string > validArgs
A list of valid (mandatory) arguments.
const labelListList & classification() const
For every intersection the classification status.
Simple random number generator.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
const dimensionedScalar mp
Proton mass.
const Field< PointType > & points() const
Return reference to global points.
void writeStats(Ostream &) const
Write some statistics.
A class for handling words, derived from string.
const stringList & args() const
Return arguments.
A class for handling file names.
List< label > labelList
A List of labels.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
List< Key > toc() const
Return the table of contents.
static void addOption(const word &opt, const string ¶m="", const string &usage="")
Add to an option to validOptions with usage information.
#define forAll(list, i)
Loop across all elements in list.
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
vector vec(const pointField &) const
Return the vector (end - start)
const Field< PointType > & localPoints() const
Return pointField of points in patch.
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 addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
const Type & first() const
Return first.
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
IOoject and searching on triSurface.
Ostream & endl(Ostream &os)
Add newline and flush stream.
dimensioned< scalar > mag(const dimensioned< Type > &)
Helper class to search on triSurface.
static word meshSubDir
Return the mesh sub-directory name (usually "triSurface")
booleanOpType
Enumeration listing the possible volume operator types.
static const NamedEnum< volumeType, 4 > names
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
virtual void movePoints(const pointField &)
Move points.
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=*(cellModeller::lookup("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]
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...
triSurface subsetMesh(const boolList &include, labelList &pointMap, labelList &faceMap) const
Return new surface. Returns pointMap, faceMap from.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Pre-declare SubField and related Field type.
Basic surface-surface intersection description. Constructed from two surfaces it creates a descriptio...
Triangulated surface description with patch information.
void append(const T &)
Append an element at the end of the 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.
const Type & second() const
Return second.
int main(int argc, char *argv[])
static scalar cosNormalAngleTol_
Angular closeness tolerance for treating normals as the same.
CGAL data structures used for triSurface handling.
const edgeList & edges() const
Return edges.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
label nPoints() const
Return number of points supporting patch faces.
bool found(const Key &) const
Return true if hashedEntry is found in table.
errorManip< error > abort(error &err)
const double e
Elementary charge.
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().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))
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
errorManipArg< error, int > exit(error &err, const int errNo=1)
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
List< labelList > labelListList
A List of labelList.
static const NamedEnum< booleanOpType, 4 > booleanOpTypeNames
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
label start() const
Return start vertex label.
An ordered pair of two objects of type <T> with first() and second() elements.
const Field< PointType > & faceNormals() const
Return face normals for patch.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
virtual void writeStats(Ostream &os) const
Dump some information.
CGAL::Polyhedron_3< K, My_items > Polyhedron
bool optionFound(const word &opt) const
Return true if the named option is found.
Triangle with additional region number.
A bounding box defined in terms of the points at its extremities.
A List with indirect addressing.
void merge(const edgeIntersections &, const labelList &edgeMap, const labelList &faceMap, const bool merge=true)
Merge (or override) edge intersection for a subset.
void size(const label)
Override size to be inconsistent with allocated storage.
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.
void write(const fileName &, const word &ext, const bool sort) const
Generic write routine. Chooses writer based on extension.
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
Return complete path.
virtual bool write() const
Give precedence to the regIOobject write.
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Pair< label > labelPair
Label pair.
cachedRandom rndGen(label(0), -1)
word name(const complex &)
Return a string representation of a complex.
A normal distribution model.