From ce651255742b9f4d2fb9305cad2126a44dd7ecd5 Mon Sep 17 00:00:00 2001 From: graham <g.macpherson@opencfd.co.uk> Date: Fri, 10 Apr 2009 17:31:59 +0100 Subject: [PATCH] Surface conformation point pair insertions and polyMesh output (without patching) included. --- .../utilities/mesh/generation/cvMesh/cvMesh.C | 1 - .../conformalVoronoiMesh.C | 817 +++++++++++++++++- .../conformalVoronoiMesh.H | 42 + .../conformalVoronoiMeshIO.C | 119 +++ .../conformationSurfaces.C | 38 + .../conformationSurfaces.H | 11 + 6 files changed, 993 insertions(+), 35 deletions(-) diff --git a/applications/utilities/mesh/generation/cvMesh/cvMesh.C b/applications/utilities/mesh/generation/cvMesh/cvMesh.C index 4fc80a526d5..8cf41aed2c8 100644 --- a/applications/utilities/mesh/generation/cvMesh/cvMesh.C +++ b/applications/utilities/mesh/generation/cvMesh/cvMesh.C @@ -64,7 +64,6 @@ int main(int argc, char *argv[]) Info<< nl << "Time = " << runTime.timeName() << endl; - Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" << nl << endl; diff --git a/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C b/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C index 94054bf4d79..f03249f78ae 100644 --- a/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C +++ b/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C @@ -66,7 +66,7 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceIntersection point dE1 = topoint(dual(fit->first->neighbor(fit->second))); // If other edge end is outside bounding box then edge cuts boundary - if (!!geometryToConformTo_.bounds().contains(dE1)) + if (!geometryToConformTo_.bounds().contains(dE1)) { return true; } @@ -82,6 +82,655 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceIntersection } +void Foam::conformalVoronoiMesh::calcDualMesh +( + pointField& points, + faceList& faces, + labelList& owner, + labelList& neighbour, + wordList& patchNames, + labelList& patchSizes, + labelList& patchStarts +) +{ + // ~~~~~~~~~~~ removing short edges by indexing dual vertices ~~~~~~~~~~~~~~ + + for + ( + Triangulation::Finite_cells_iterator cit = finite_cells_begin(); + cit != finite_cells_end(); + ++cit + ) + { + cit->cellIndex() = -1; + } + + points.setSize(number_of_cells()); + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Looking up details from a dictionary, in future the will be available + // from a controls class. + + const dictionary& cvMeshDict( cvMeshControls_.cvMeshDict()); + + scalar defaultCellSize + ( + readScalar + ( + cvMeshDict.subDict("motionControl").lookup("defaultCellSize") + ) + ); + + scalar minimumEdgeLengthCoeff + ( + readScalar + ( + cvMeshDict.subDict("polyMeshFiltering").lookup + ( + "minimumEdgeLengthCoeff" + ) + ) + ); + + scalar minEdgeLenSqr = Foam::sqr(defaultCellSize*minimumEdgeLengthCoeff); + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + label dualVerti = 0; + + // Scanning by number of short (dual) edges (nSE) attached to the + // circumcentre of each Delaunay tet. A Delaunay tet may only have four + // dual edges emanating from its circumcentre, assigning positions and + // indices to those with 4 short edges attached first, then >= 3, then >= 2 + // etc. + for (label nSE = 4; nSE >= 0; nSE--) + { + Info<< nl << "Scanning for dual vertices with >= " + << nSE + << " short edges attached." << endl; + + for + ( + Triangulation::Finite_cells_iterator cit = finite_cells_begin(); + cit != finite_cells_end(); + ++cit + ) + { + // If the Delaunay tet has an index already then it has either + // evaluated itself and taken action or has had its index dictated + // by a neighbouring tet with more short edges attached. + + if (cit->cellIndex() == -1) + { + point dualVertex = topoint(dual(cit)); + + label shortEdges = 0; + + List<bool> edgeIsShort(4, false); + + List<bool> neighbourAlreadyIndexed(4, false); + + // Loop over the four facets of the Delaunay tet + for (label f = 0; f < 4; f++) + { + // Check that at least one of the vertices of the facet is + // an internal or boundary point + if + ( + cit->vertex(vertex_triple_index(f, 0))-> + internalOrBoundaryPoint() + || cit->vertex(vertex_triple_index(f, 1))-> + internalOrBoundaryPoint() + || cit->vertex(vertex_triple_index(f, 2))-> + internalOrBoundaryPoint() + ) + { + point neighDualVertex; + + label cNI = cit->neighbor(f)->cellIndex(); + + if (cNI == -1) + { + neighDualVertex = topoint(dual(cit->neighbor(f))); + } + else + { + neighDualVertex = points[cNI]; + } + + if + ( + magSqr(dualVertex - neighDualVertex) < minEdgeLenSqr + ) + { + edgeIsShort[f] = true; + + if (cNI > -1) + { + neighbourAlreadyIndexed[f] = true; + } + + shortEdges++; + } + } + } + + if (nSE == 0 && shortEdges == 0) + { + // Final iteration and no short edges are found, index + // remaining dual vertices. + + if + ( + cit->vertex(0)->internalOrBoundaryPoint() + || cit->vertex(1)->internalOrBoundaryPoint() + || cit->vertex(2)->internalOrBoundaryPoint() + || cit->vertex(3)->internalOrBoundaryPoint() + ) + { + cit->cellIndex() = dualVerti; + points[dualVerti] = dualVertex; + dualVerti++; + } + } + else if + ( + shortEdges >= nSE + ) + { + // Info<< neighbourAlreadyIndexed << ' ' + // << edgeIsShort << endl; + + label numUnindexedNeighbours = 1; + + for (label f = 0; f < 4; f++) + { + if (edgeIsShort[f] && !neighbourAlreadyIndexed[f]) + { + dualVertex += topoint(dual(cit->neighbor(f))); + + numUnindexedNeighbours++; + } + } + + dualVertex /= numUnindexedNeighbours; + + label nearestExistingIndex = -1; + + point nearestIndexedNeighbourPos = vector::zero; + + scalar minDistSqrToNearestIndexedNeighbour = VGREAT; + + for (label f = 0; f < 4; f++) + { + if (edgeIsShort[f] && neighbourAlreadyIndexed[f]) + { + label cNI = cit->neighbor(f)->cellIndex(); + + point indexedNeighbourPos = points[cNI]; + + if + ( + magSqr(indexedNeighbourPos - dualVertex) + < minDistSqrToNearestIndexedNeighbour + ) + { + nearestExistingIndex = cNI; + + nearestIndexedNeighbourPos = + indexedNeighbourPos; + + minDistSqrToNearestIndexedNeighbour = + magSqr(indexedNeighbourPos - dualVertex); + } + } + } + + if + ( + nearestExistingIndex > -1 + && minDistSqrToNearestIndexedNeighbour < minEdgeLenSqr + ) + { + points[nearestExistingIndex] = + 0.5*(dualVertex + nearestIndexedNeighbourPos); + + for (label f = 0; f < 4; f++) + { + if (edgeIsShort[f] && !neighbourAlreadyIndexed[f]) + { + cit->neighbor(f)->cellIndex() = + nearestExistingIndex; + } + } + + cit->cellIndex() = nearestExistingIndex; + } + else + { + for (label f = 0; f < 4; f++) + { + if (edgeIsShort[f] && !neighbourAlreadyIndexed[f]) + { + cit->neighbor(f)->cellIndex() = dualVerti; + } + } + + cit->cellIndex() = dualVerti; + + points[dualVerti] = dualVertex; + + dualVerti++; + } + } + } + } + } + + points.setSize(dualVerti); + + // ~~~~~~~~~~~~~~~~~~~~~~~~~ dual cell indexing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // assigns an index to the Delaunay vertices which will be the dual cell + // index used for owner neighbour assignment. + + // The indices of the points are reset which destroys the point-pair + // matching, so the type of each vertex are reset to avoid any ambiguity. + + label dualCelli = 0; + + for + ( + Triangulation::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (vit->internalOrBoundaryPoint()) + { + vit->type() = Vb::INTERNAL_POINT; + vit->index() = dualCelli; + dualCelli++; + } + else + { + vit->type() = Vb::FAR_POINT; + vit->index() = -1; + } + } + + // ~~~~~~~~~~~~ dual face and owner neighbour construction ~~~~~~~~~~~~~~~~~ + + //label nPatches = qSurf_.patches().size() + 1; + + //label defaultPatchIndex = qSurf_.patches().size(); + + label nPatches = 1; + + label defaultPatchIndex = 0; + + patchNames.setSize(nPatches); + + //const geometricSurfacePatchList& surfacePatches = qSurf_.patches(); + + // forAll(surfacePatches, sP) + // { + // patchNames[sP] = surfacePatches[sP].name(); + // } + + patchNames[defaultPatchIndex] = "cvMesh_defaultPatch"; + + patchSizes.setSize(nPatches); + + patchStarts.setSize(nPatches); + + List<DynamicList<face> > patchFaces(nPatches, DynamicList<face>(0)); + + List<DynamicList<label> > patchOwners(nPatches, DynamicList<label>(0)); + + faces.setSize(number_of_edges()); + + owner.setSize(number_of_edges()); + + neighbour.setSize(number_of_edges()); + + label dualFacei = 0; + + for + ( + Triangulation::Finite_edges_iterator eit = finite_edges_begin(); + eit != finite_edges_end(); + ++eit + ) + { + Cell_handle c = eit->first; + Vertex_handle vA = c->vertex(eit->second); + Vertex_handle vB = c->vertex(eit->third); + + if + ( + vA->internalOrBoundaryPoint() + || vB->internalOrBoundaryPoint() + ) + { + Cell_circulator ccStart = incident_cells(*eit); + Cell_circulator cc1 = ccStart; + Cell_circulator cc2 = cc1; + + // Advance the second circulator so that it always stays on the next + // cell around the edge; + cc2++; + + DynamicList<label> verticesOnFace; + + do + { + label cc1I = cc1->cellIndex(); + + label cc2I = cc2->cellIndex(); + + + if (cc1I < 0 || cc2I < 0) + { + FatalErrorIn("Foam::conformalVoronoiMesh::calcDualMesh") + << "Dual face uses circumcenter defined by a " + << "Delaunay tetrahedron with no internal " + << "or boundary points. Defining Delaunay edge ends: " + << topoint(vA->point()) << " " + << topoint(vB->point()) << nl + << exit(FatalError); + } + + if (cc1I != cc2I) + { + verticesOnFace.append(cc1I); + } + + cc1++; + + cc2++; + } while (cc1 != ccStart); + + verticesOnFace.shrink(); + + if (verticesOnFace.size() >= 3) + { + face newDualFace(verticesOnFace); + + label dcA = vA->index(); + + if (!vA->internalOrBoundaryPoint()) + { + dcA = -1; + } + + label dcB = vB->index(); + + if (!vB->internalOrBoundaryPoint()) + { + dcB = -1; + } + + label dcOwn = -1; + label dcNei = -1; + + if (dcA == -1 && dcB == -1) + { + FatalErrorIn("calcDualMesh") + << "Attempting to create a face joining " + << "two external dual cells " + << exit(FatalError); + } + else if (dcA == -1 || dcB == -1) + { + // boundary face, find which is the owner + + if (dcA == -1) + { + dcOwn = dcB; + + // reverse face order to correctly orientate normal + reverse(newDualFace); + } + else + { + dcOwn = dcA; + } + + // Find which patch this face is on by finding the + // intersection with the surface of the Delaunay edge + // generating the face and identify the region of the + // intersection. + + point ptA = topoint(vA->point()); + + point ptB = topoint(vB->point()); + + //pointIndexHit pHit = qSurf_.tree().findLineAny(ptA, ptB); + + //label patchIndex = qSurf_[pHit.index()].region(); + + label patchIndex = defaultPatchIndex; + + if (patchIndex == -1) + { + patchIndex = defaultPatchIndex; + + WarningIn("Foam::conformalVoronoiMesh::calcDualMesh") + << "Dual face found that is not on a surface " + << "patch. Adding to " + << patchNames[defaultPatchIndex] + << endl; + } + + patchFaces[patchIndex].append(newDualFace); + patchOwners[patchIndex].append(dcOwn); + } + else + { + // internal face, find the lower cell to be the owner + + if (dcB > dcA) + { + dcOwn = dcA; + dcNei = dcB; + } + else + { + dcOwn = dcB; + dcNei = dcA; + + // reverse face order to correctly orientate normal + reverse(newDualFace); + } + + faces[dualFacei] = newDualFace; + + owner[dualFacei] = dcOwn; + + neighbour[dualFacei] = dcNei; + + dualFacei++; + } + } + // else + // { + // Info<< verticesOnFace.size() + // << " size face not created." << endl; + // } + } + } + + label nInternalFaces = dualFacei; + + faces.setSize(nInternalFaces); + + owner.setSize(nInternalFaces); + + neighbour.setSize(nInternalFaces); + + // ~~~~~~~~ sort owner, reordinging neighbour and faces to match ~~~~~~~~~~~ + // two stage sort for upper triangular order: sort by owner first, then for + // each block of owners sort by neighbour + + labelList sortingIndices; + + // Stage 1 + + { + SortableList<label> sortedOwner(owner); + + sortingIndices = sortedOwner.indices(); + } + + { + labelList copyOwner(owner.size()); + + forAll(sortingIndices, sI) + { + copyOwner[sI] = owner[sortingIndices[sI]]; + } + + owner = copyOwner; + } + + { + labelList copyNeighbour(neighbour.size()); + + forAll(sortingIndices, sI) + { + copyNeighbour[sI] = neighbour[sortingIndices[sI]]; + } + + neighbour = copyNeighbour; + } + + { + faceList copyFaces(faces.size()); + + forAll(sortingIndices, sI) + { + copyFaces[sI] = faces[sortingIndices[sI]]; + } + + faces = copyFaces; + } + + // Stage 2 + + sortingIndices = -1; + + DynamicList<label> ownerCellJumps; + + // Force first owner entry to be a jump + ownerCellJumps.append(0); + + for (label o = 1; o < owner.size(); o++) + { + if (owner[o] > owner[o-1]) + { + ownerCellJumps.append(o); + } + } + + ownerCellJumps.shrink(); + + forAll(ownerCellJumps, oCJ) + { + label start = ownerCellJumps[oCJ]; + + label length; + + if (oCJ == ownerCellJumps.size() - 1) + { + length = owner.size() - start; + } + else + { + length = ownerCellJumps[oCJ + 1] - start; + } + + SubList<label> neighbourBlock(neighbour, length, start); + + SortableList<label> sortedNeighbourBlock(neighbourBlock); + + forAll(sortedNeighbourBlock, sNB) + { + sortingIndices[start + sNB] = + sortedNeighbourBlock.indices()[sNB] + start; + } + } + + // Perform sort + + { + labelList copyOwner(owner.size()); + + forAll(sortingIndices, sI) + { + copyOwner[sI] = owner[sortingIndices[sI]]; + } + + owner = copyOwner; + } + + { + labelList copyNeighbour(neighbour.size()); + + forAll(sortingIndices, sI) + { + copyNeighbour[sI] = neighbour[sortingIndices[sI]]; + } + + neighbour = copyNeighbour; + } + + { + faceList copyFaces(faces.size()); + + forAll(sortingIndices, sI) + { + copyFaces[sI] = faces[sortingIndices[sI]]; + } + + faces = copyFaces; + } + + // ~~~~~~~~ add patch information ~~~~~~~~~~~ + + label nBoundaryFaces = 0; + + forAll(patchFaces, p) + { + patchFaces[p].shrink(); + + patchOwners[p].shrink(); + + patchSizes[p] = patchFaces[p].size(); + + patchStarts[p] = nInternalFaces + nBoundaryFaces; + + nBoundaryFaces += patchSizes[p]; + } + + faces.setSize(nInternalFaces + nBoundaryFaces); + + owner.setSize(nInternalFaces + nBoundaryFaces); + + forAll(patchFaces, p) + { + forAll(patchFaces[p], f) + { + faces[dualFacei] = patchFaces[p][f]; + + owner[dualFacei] = patchOwners[p][f]; + + dualFacei++; + } + } +} + + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::conformalVoronoiMesh::conformalVoronoiMesh @@ -126,11 +775,18 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh timeCheck(); insertFeaturePoints(); - timeCheck(); insertInitialPoints(); + timeCheck(); + + conformToSurface(); + timeCheck(); + writePoints("allPoints.obj", false); + timeCheck(); + + writeMesh(); timeCheck(); } @@ -145,7 +801,48 @@ Foam::conformalVoronoiMesh::~conformalVoronoiMesh() void Foam::conformalVoronoiMesh::timeCheck() const { - Info<< nl << "--- [ " << runTime_.elapsedCpuTime() << "s ] --- " << endl; + Info<< nl << "--- [ " << runTime_.elapsedCpuTime() << "s, delta " + << runTime_.cpuTimeIncrement()<< "s ] --- " << endl; +} + + +void Foam::conformalVoronoiMesh::insertSurfacePointPairs +( + const List<scalar>& surfacePpDist, + const List<point>& surfacePoints, + const List<vector>& surfaceNormals, + const fileName fName +) +{ + if + ( + surfacePpDist.size() != surfacePoints.size() + || surfacePpDist.size() != surfaceNormals.size() + ) + { + FatalErrorIn("Foam::conformalVoronoiMesh::insertPointPairs") + << "surfacePpDist, surfacePoints and surfaceNormals are not " + << "the same size. Sizes" + << surfacePpDist.size() << ' ' + << surfacePoints.size() << ' ' + << surfaceNormals.size() + << exit(FatalError); + } + + forAll(surfacePoints, p) + { + insertPointPair + ( + surfacePpDist[p], + surfacePoints[p], + surfaceNormals[p] + ); + } + + if (fName != fileName::null) + { + writePoints(fName, surfacePoints); + } } @@ -203,60 +900,112 @@ void Foam::conformalVoronoiMesh::insertInitialPoints() void Foam::conformalVoronoiMesh::conformToSurface() { + Info<< nl << "Conforming to surfaces" << endl; + startOfSurfacePointPairs_ = number_of_vertices(); + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Looking up details from a dictionary, in future the will be available + // from a controls class. + const dictionary& cvMeshDict( cvMeshControls_.cvMeshDict()); scalar defaultCellSize ( - cvMeshDict.subDict("motionControl").lookup("defaultCellSize") + readScalar + ( + cvMeshDict.subDict("motionControl").lookup("defaultCellSize") + ) ); scalar surfDepthCoeff ( - cvMeshDict.subDict("surfaceConformation").lookup + readScalar ( - "surfacePointSearchDepthCoeff" + cvMeshDict.subDict("surfaceConformation").lookup + ( + "surfacePointSearchDepthCoeff" + ) ) ); - DynamicList<point> surfacePoints; - DynamicList<point> surfaceNormals; - - for + scalar ppDistCoeff ( - Triangulation::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - vit++ - ) - { - if (vit->internalPoint()) - { - point vert(topoint(vit->point())); - - // TODO Need to have a function to recover the local cell size, use - // the defaultCellSize for the moment + readScalar + ( + cvMeshDict.subDict("surfaceConformation").lookup + ( + "pointPairDistanceCoeff" + ) + ) + ); - scalar searchDistanceSqr = sqr(defaultCellSize*surfDepthCoeff); + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - pointIndexHit pHit = geometryToConformTo_.findNearest - ( - vert, - searchDistanceSqr - ); + for(label iterationNo = 0; iterationNo < 1; iterationNo++) + { + DynamicList<scalar> surfacePpDist; + DynamicList<point> surfacePoints; + DynamicList<vector> surfaceNormals; - if (pHit.hit()) + for + ( + Triangulation::Finite_vertices_iterator vit = + finite_vertices_begin(); + vit != finite_vertices_end(); + vit++ + ) + { + if (vit->internalPoint()) { - vit->setNearBoundary(); - - if (dualCellSurfaceIntersection(vit)) + point vert(topoint(vit->point())); + + // TODO Need to have a function to recover the local cell size, + // use the defaultCellSize for the moment + + scalar searchDistanceSqr = Foam::sqr + ( + defaultCellSize*surfDepthCoeff + ); + pointIndexHit pHit; + vector normal; + + geometryToConformTo_.findNearestAndNormal + ( + vert, + searchDistanceSqr, + pHit, + normal + ); + + if (pHit.hit()) { - allNearSurfacePoints.append(vert); - allSurfacePoints.append(pHit.hitPoint()); - allSurfaceTris.append(pHit.index()); + vit->setNearBoundary(); + + if (dualCellSurfaceIntersection(vit)) + { + surfacePpDist.append(defaultCellSize*ppDistCoeff); + surfacePoints.append(pHit.hitPoint()); + surfaceNormals.append(normal); + } } } } + + Info<< nl <<iterationNo << ": " + << number_of_vertices() << ": " + << surfacePoints.size() << endl; + + insertSurfacePointPairs + ( + surfacePpDist, + surfacePoints, + surfaceNormals, + fileName + ( + "surfaceConformationLocations_" + name(iterationNo) + ".obj" + ) + ); } } diff --git a/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H b/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H index 249adabe288..571e1d0e619 100644 --- a/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H +++ b/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H @@ -48,6 +48,7 @@ SourceFiles #include "DynamicList.H" #include "Time.H" #include "polyMesh.H" +#include "SortableList.H" #include "meshTools.H" #include "triSurfaceTools.H" #include "mathematicalConstants.H" @@ -122,6 +123,16 @@ class conformalVoronoiMesh //- Insert a Vb (a typedef of CGAL::indexedVertex<K>) inline void insertVb(const Vb& v); + //- Insert pairs of points on the surface with the given normals, at the + // specified spacing + void insertSurfacePointPairs + ( + const List<scalar>& surfacePpDist, + const List<point>& surfacePoints, + const List<vector>& surfaceNormals, + const fileName fName = fileName::null + ); + //- Insert point groups at the feature points. void insertFeaturePoints(); @@ -139,6 +150,18 @@ class conformalVoronoiMesh const Triangulation::Finite_vertices_iterator& vit ) const; + //- Dual calculation + void calcDualMesh + ( + pointField& points, + faceList& faces, + labelList& owner, + labelList& neighbour, + wordList& patchNames, + labelList& patchSizes, + labelList& patchStarts + ); + //- Disallow default bitwise copy construct conformalVoronoiMesh(const conformalVoronoiMesh&); @@ -201,6 +224,25 @@ public: //- Write Delaunay points to .obj file void writePoints(const fileName& fName, bool internalOnly) const; + + //- Write list of points to file + void writePoints + ( + const fileName& fName, + const List<point>& points + ) const; + + //- Write polyMesh + void writeMesh(); + + //- Write dual points and faces as .obj file + void writeDual + ( + const pointField& points, + const faceList& faces, + const fileName& fName + ) const; + }; diff --git a/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C b/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C index 3c81334eae5..ea741b1d634 100644 --- a/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C +++ b/src/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C @@ -55,4 +55,123 @@ void Foam::conformalVoronoiMesh::writePoints } +void Foam::conformalVoronoiMesh::writePoints +( + const fileName& fName, + const List<point>& points +) const +{ + Info<< nl << "Writing " << points.size() << " points from pointList to " + << fName << endl; + + OFstream str(fName); + + forAll(points, p) + { + meshTools::writeOBJ(str, points[p]); + } +} + + +void Foam::conformalVoronoiMesh::writeMesh() +{ + pointField points(0); + faceList faces(0); + labelList owner(0); + labelList neighbour(0); + wordList patchNames(0); + labelList patchSizes(0); + labelList patchStarts(0); + + calcDualMesh + ( + points, + faces, + owner, + neighbour, + patchNames, + patchSizes, + patchStarts + ); + + writeDual(points, faces, "dualMesh.obj"); + + IOobject io + ( + Foam::polyMesh::defaultRegion, + runTime_.constant(), + runTime_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ); + + Info<< nl << "Writing polyMesh to constant." << endl; + + + polyMesh pMesh + ( + io, + xferMove(points), + xferMove(faces), + xferMove(owner), + xferMove(neighbour) + ); + + List<polyPatch*> patches(patchStarts.size()); + + forAll (patches, p) + { + patches[p] = new polyPatch + ( + patchNames[p], + patchSizes[p], + patchStarts[p], + p, + pMesh.boundaryMesh() + ); + } + + pMesh.addPatches(patches); + + if (!pMesh.write()) + { + FatalErrorIn("Foam::conformalVoronoiMesh::writeMesh()") + << "Failed writing polyMesh." + << exit(FatalError); + } +} + + +void Foam::conformalVoronoiMesh::writeDual +( + const pointField& points, + const faceList& faces, + const fileName& fName +) const +{ + Info<< nl << "Writing dual points and faces to " << fName << endl; + + OFstream str(fName); + + forAll(points, p) + { + meshTools::writeOBJ(str, points[p]); + } + + forAll (faces, f) + { + str<< 'f'; + + const face& fP = faces[f]; + + forAll(fP, p) + { + str<< ' ' << fP[p] + 1; + } + + str<< nl; + } +} + + // ************************************************************************* // diff --git a/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C b/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C index 759810229e0..abde13e3f16 100644 --- a/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C +++ b/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C @@ -256,4 +256,42 @@ bool Foam::conformationSurfaces::findAnyIntersection } +void Foam::conformationSurfaces::findNearestAndNormal +( + const point& sample, + scalar nearestDistSqr, + pointIndexHit& pHit, + vector& normal +) const +{ + labelList hitSurfaces; + List<pointIndexHit> hitInfo; + + searchableSurfacesQueries::findNearest + ( + allGeometry_, + surfaces_, + pointField(1, sample), + scalarField(1, nearestDistSqr), + hitSurfaces, + hitInfo + ); + + pHit = hitInfo[0]; + + if (pHit.hit()) + { + vectorField normals; + + // hitSurfaces has returned the index of the entry in surfaces_ that was + // found, not the index of the surface in allGeometry_, translating this + // on access to allGeometry_ for the normal lookup. + + allGeometry_[surfaces_[hitSurfaces[0]]].getNormal(hitInfo, normals); + + normal = normals[0]; + } +} + + // ************************************************************************* // diff --git a/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H b/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H index cd75b1f29ff..1ec6734fd9e 100644 --- a/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H +++ b/src/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H @@ -40,6 +40,7 @@ SourceFiles #include "searchableSurfaces.H" #include "searchableSurfacesQueries.H" #include "featureEdgeMesh.H" +#include "triSurface.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -146,6 +147,16 @@ public: // Finding if the line joining start and end intersects the surface bool findAnyIntersection(point start, point end) const; + //- Find the nearest point to the sample and return it to the + // pointIndexHit, and the normal at the hit location, if found. + void findNearestAndNormal + ( + const point& sample, + scalar nearestDistSqr, + pointIndexHit& pHit, + vector& normal + ) const; + // Member Operators -- GitLab