mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: Add surfaceHookUp utility
Matches boundary edges between surfaces by retriangulating edges.
This commit is contained in:
3
applications/utilities/surface/surfaceHookUp/Make/files
Normal file
3
applications/utilities/surface/surfaceHookUp/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceHookUp.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceHookUp
|
||||
@ -0,0 +1,9 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/fileFormats/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-lfileFormats \
|
||||
-ltriSurface
|
||||
525
applications/utilities/surface/surfaceHookUp/surfaceHookUp.C
Normal file
525
applications/utilities/surface/surfaceHookUp/surfaceHookUp.C
Normal file
@ -0,0 +1,525 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2013 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
surfaceHookUp
|
||||
|
||||
Description
|
||||
Find close open edges and stitches the surface along them
|
||||
|
||||
Usage
|
||||
- surfaceHookUp hookDistance [OPTION]
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
|
||||
#include "triSurfaceMesh.H"
|
||||
#include "indexedOctree.H"
|
||||
#include "treeBoundBox.H"
|
||||
#include "PackedBoolList.H"
|
||||
#include "unitConversion.H"
|
||||
#include "searchableSurfaces.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// Split faceI along edgeI at position newPointI
|
||||
void greenRefine
|
||||
(
|
||||
const triSurface& surf,
|
||||
const label faceI,
|
||||
const label edgeI,
|
||||
const label newPointI,
|
||||
DynamicList<labelledTri>& newFaces
|
||||
)
|
||||
{
|
||||
const labelledTri& f = surf.localFaces()[faceI];
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
// Find index of edge in face.
|
||||
|
||||
label fp0 = findIndex(f, e[0]);
|
||||
label fp1 = f.fcIndex(fp0);
|
||||
label fp2 = f.fcIndex(fp1);
|
||||
|
||||
if (f[fp1] == e[1])
|
||||
{
|
||||
// Edge oriented like face
|
||||
newFaces.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp0],
|
||||
newPointI,
|
||||
f[fp2],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
newFaces.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
newPointI,
|
||||
f[fp1],
|
||||
f[fp2],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
newFaces.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp2],
|
||||
newPointI,
|
||||
f[fp1],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
newFaces.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
newPointI,
|
||||
f[fp0],
|
||||
f[fp1],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//scalar checkEdgeAngle
|
||||
//(
|
||||
// const triSurface& surf,
|
||||
// const label edgeIndex,
|
||||
// const label pointIndex,
|
||||
// const scalar& angle
|
||||
//)
|
||||
//{
|
||||
// const edge& e = surf.edges()[edgeIndex];
|
||||
|
||||
// vector eVec = e.vec(surf.localPoints());
|
||||
// eVec /= mag(eVec) + SMALL;
|
||||
|
||||
// const labelList& pEdges = surf.pointEdges()[pointIndex];
|
||||
//
|
||||
// forAll(pEdges, eI)
|
||||
// {
|
||||
// const edge& nearE = surf.edges()[pEdges[eI]];
|
||||
|
||||
// vector nearEVec = nearE.vec(surf.localPoints());
|
||||
// nearEVec /= mag(nearEVec) + SMALL;
|
||||
|
||||
// const scalar dot = eVec & nearEVec;
|
||||
// const scalar minCos = degToRad(angle);
|
||||
|
||||
// if (mag(dot) > minCos)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
|
||||
void createBoundaryEdgeTrees
|
||||
(
|
||||
const PtrList<triSurfaceMesh>& surfs,
|
||||
PtrList<indexedOctree<treeDataEdge> >& bEdgeTrees,
|
||||
labelListList& treeBoundaryEdges
|
||||
)
|
||||
{
|
||||
forAll(surfs, surfI)
|
||||
{
|
||||
const triSurface& surf = surfs[surfI];
|
||||
|
||||
// Boundary edges
|
||||
treeBoundaryEdges[surfI] =
|
||||
labelList
|
||||
(
|
||||
identity(surf.nEdges() - surf.nInternalEdges())
|
||||
+ surf.nInternalEdges()
|
||||
);
|
||||
|
||||
Random rndGen(17301893);
|
||||
|
||||
// Slightly extended bb. Slightly off-centred just so on symmetric
|
||||
// geometry there are less face/edge aligned items.
|
||||
treeBoundBox bb
|
||||
(
|
||||
treeBoundBox(UList<point>(surf.localPoints())).extend(rndGen, 1e-4)
|
||||
);
|
||||
|
||||
bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
|
||||
bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
|
||||
|
||||
bEdgeTrees.set
|
||||
(
|
||||
surfI,
|
||||
new indexedOctree<treeDataEdge>
|
||||
(
|
||||
treeDataEdge
|
||||
(
|
||||
false, // cachebb
|
||||
surf.edges(), // edges
|
||||
surf.localPoints(), // points
|
||||
treeBoundaryEdges[surfI] // selected edges
|
||||
),
|
||||
bb, // bb
|
||||
8, // maxLevel
|
||||
10, // leafsize
|
||||
3.0 // duplicity
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"hook surfaces to other surfaces by moving and retriangulating their"
|
||||
"boundary edges to match other surface boundary edges"
|
||||
);
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("hookTolerance");
|
||||
|
||||
# include "addDictOption.H"
|
||||
|
||||
# include "setRootCase.H"
|
||||
# include "createTime.H"
|
||||
|
||||
const word dictName("surfaceHookUpDict");
|
||||
# include "setSystemRunTimeDictionaryIO.H"
|
||||
|
||||
Info<< "Reading " << dictName << nl << endl;
|
||||
|
||||
const IOdictionary dict(dictIO);
|
||||
|
||||
const scalar dist(args.argRead<scalar>(1));
|
||||
const scalar matchTolerance(SMALL);
|
||||
|
||||
Info<< "Hooking distance = " << dist << endl;
|
||||
|
||||
searchableSurfaces surfs
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"surfacesToHook",
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime
|
||||
),
|
||||
dict
|
||||
);
|
||||
|
||||
Info<< nl << "Reading surfaces: " << endl;
|
||||
forAll(surfs, surfI)
|
||||
{
|
||||
Info<< incrIndent;
|
||||
Info<< nl << indent << "Surface = " << surfs.names()[surfI] << endl;
|
||||
|
||||
const wordList& regions = surfs[surfI].regions();
|
||||
forAll(regions, surfRegionI)
|
||||
{
|
||||
Info<< incrIndent;
|
||||
Info<< indent << "Regions = " << regions[surfRegionI] << endl;
|
||||
Info<< decrIndent;
|
||||
}
|
||||
Info<< decrIndent;
|
||||
}
|
||||
|
||||
PtrList<indexedOctree<treeDataEdge> > bEdgeTrees(surfs.size());
|
||||
labelListList treeBoundaryEdges(surfs.size());
|
||||
|
||||
List<DynamicList<labelledTri> > newFaces(surfs.size());
|
||||
List<DynamicList<point> > newPoints(surfs.size());
|
||||
List<PackedBoolList> visitedFace(surfs.size());
|
||||
|
||||
PtrList<triSurfaceMesh> newSurfaces(surfs.size());
|
||||
forAll(surfs, surfI)
|
||||
{
|
||||
const triSurfaceMesh& surf =
|
||||
refCast<const triSurfaceMesh>(surfs[surfI]);
|
||||
|
||||
newSurfaces.set
|
||||
(
|
||||
surfI,
|
||||
new triSurfaceMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"hookedSurface_" + surfs.names()[surfI],
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime
|
||||
),
|
||||
surf
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
label nChanged = 0;
|
||||
label nIters = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Info<< nl << "Iteration = " << nIters++ << endl;
|
||||
nChanged = 0;
|
||||
|
||||
createBoundaryEdgeTrees(newSurfaces, bEdgeTrees, treeBoundaryEdges);
|
||||
|
||||
forAll(newSurfaces, surfI)
|
||||
{
|
||||
const triSurface& newSurf = newSurfaces[surfI];
|
||||
|
||||
newFaces[surfI] = newSurf.localFaces();
|
||||
newPoints[surfI] = newSurf.localPoints();
|
||||
visitedFace[surfI] = PackedBoolList(newSurf.size(), false);
|
||||
}
|
||||
|
||||
forAll(newSurfaces, surfI)
|
||||
{
|
||||
const triSurface& surf = newSurfaces[surfI];
|
||||
|
||||
List<pointIndexHit> bPointsTobEdges(surf.boundaryPoints().size());
|
||||
labelList bPointsHitTree(surf.boundaryPoints().size(), -1);
|
||||
|
||||
const labelListList& pointEdges = surf.pointEdges();
|
||||
|
||||
forAll(bPointsTobEdges, bPointI)
|
||||
{
|
||||
pointIndexHit& nearestHit = bPointsTobEdges[bPointI];
|
||||
|
||||
const label pointI = surf.boundaryPoints()[bPointI];
|
||||
const point& samplePt = surf.localPoints()[pointI];
|
||||
|
||||
const labelList& pEdges = pointEdges[pointI];
|
||||
|
||||
// Add edges connected to the edge to the shapeMask
|
||||
DynamicList<label> shapeMask;
|
||||
shapeMask.append(pEdges);
|
||||
|
||||
forAll(bEdgeTrees, treeI)
|
||||
{
|
||||
const indexedOctree<treeDataEdge>& bEdgeTree =
|
||||
bEdgeTrees[treeI];
|
||||
|
||||
pointIndexHit currentHit =
|
||||
bEdgeTree.findNearest
|
||||
(
|
||||
samplePt,
|
||||
sqr(dist),
|
||||
treeDataEdge::findNearestOpSubset
|
||||
(
|
||||
bEdgeTree,
|
||||
shapeMask
|
||||
)
|
||||
);
|
||||
|
||||
if
|
||||
(
|
||||
currentHit.hit()
|
||||
&&
|
||||
(
|
||||
!nearestHit.hit()
|
||||
||
|
||||
(
|
||||
magSqr(currentHit.hitPoint() - samplePt)
|
||||
< magSqr(nearestHit.hitPoint() - samplePt)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
nearestHit = currentHit;
|
||||
bPointsHitTree[bPointI] = treeI;
|
||||
}
|
||||
}
|
||||
|
||||
scalar dist2 = magSqr(nearestHit.rawPoint() - samplePt);
|
||||
|
||||
if (nearestHit.hit())
|
||||
{
|
||||
// bool rejectEdge =
|
||||
// checkEdgeAngle
|
||||
// (
|
||||
// surf,
|
||||
// nearestHit.index(),
|
||||
// pointI,
|
||||
// 30
|
||||
// );
|
||||
|
||||
if (dist2 > Foam::sqr(dist))
|
||||
{
|
||||
nearestHit.setMiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forAll(bPointsTobEdges, bPointI)
|
||||
{
|
||||
const pointIndexHit& eHit = bPointsTobEdges[bPointI];
|
||||
|
||||
if (eHit.hit())
|
||||
{
|
||||
const label hitSurfI = bPointsHitTree[bPointI];
|
||||
const triSurface& hitSurf = newSurfaces[hitSurfI];
|
||||
|
||||
const label eIndex =
|
||||
treeBoundaryEdges[hitSurfI][eHit.index()];
|
||||
const edge& e = hitSurf.edges()[eIndex];
|
||||
|
||||
const label pointI = surf.boundaryPoints()[bPointI];
|
||||
|
||||
const labelList& eFaces = hitSurf.edgeFaces()[eIndex];
|
||||
|
||||
if (eFaces.size() != 1)
|
||||
{
|
||||
WarningIn(args.executable())
|
||||
<< "Edge is attached to " << eFaces.size()
|
||||
<< " faces." << endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const label faceI = eFaces[0];
|
||||
|
||||
if (visitedFace[hitSurfI][faceI])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DynamicList<labelledTri> newFacesFromSplit(2);
|
||||
|
||||
const point& pt = surf.localPoints()[pointI];
|
||||
|
||||
if
|
||||
(
|
||||
(
|
||||
magSqr(pt - hitSurf.localPoints()[e.start()])
|
||||
< matchTolerance
|
||||
)
|
||||
|| (
|
||||
magSqr(pt - hitSurf.localPoints()[e.end()])
|
||||
< matchTolerance
|
||||
)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
nChanged++;
|
||||
|
||||
// Keep the points in the same place and move the edge
|
||||
newPoints[hitSurfI].append(newPoints[surfI][pointI]);
|
||||
|
||||
// Move the points to the edges
|
||||
//newPoints[pointI] = eHit.hitPoint();
|
||||
//newPoints.append(eHit.hitPoint());
|
||||
|
||||
visitedFace[hitSurfI][faceI] = true;
|
||||
|
||||
// Split the other face.
|
||||
greenRefine
|
||||
(
|
||||
hitSurf,
|
||||
faceI,
|
||||
eIndex,
|
||||
newPoints[hitSurfI].size() - 1,
|
||||
newFacesFromSplit
|
||||
);
|
||||
|
||||
forAll(newFacesFromSplit, newFaceI)
|
||||
{
|
||||
if (newFaceI == 0)
|
||||
{
|
||||
newFaces[hitSurfI][faceI] = newFacesFromSplit[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
newFaces[hitSurfI].append
|
||||
(
|
||||
newFacesFromSplit[newFaceI]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< " Number of edges split = " << nChanged << endl;
|
||||
|
||||
forAll(newSurfaces, surfI)
|
||||
{
|
||||
newSurfaces.set
|
||||
(
|
||||
surfI,
|
||||
new triSurfaceMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"hookedSurface_" + surfs.names()[surfI],
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime
|
||||
),
|
||||
triSurface
|
||||
(
|
||||
newFaces[surfI],
|
||||
newSurfaces[surfI].patches(),
|
||||
pointField(newPoints[surfI])
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
} while (nChanged > 0);
|
||||
|
||||
Info<< endl;
|
||||
|
||||
forAll(newSurfaces, surfI)
|
||||
{
|
||||
const triSurfaceMesh& newSurf = newSurfaces[surfI];
|
||||
|
||||
Info<< "Writing hooked surface " << newSurf.searchableSurface::name()
|
||||
<< endl;
|
||||
|
||||
newSurf.searchableSurface::write();
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,22 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: dev |
|
||||
| \\ / A nd | Web: www.OpenFOAM.org |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
location "system";
|
||||
object surfaceHookUpDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
surface1.stl {type triSurfaceMesh;}
|
||||
surface2.stl {type triSurfaceMesh;}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user