mirror of
https://github.com/OpenFOAM/OpenFOAM-6.git
synced 2025-12-08 06:57:46 +00:00
Add the OpenFOAM source tree
This commit is contained in:
46
applications/utilities/surface/README
Normal file
46
applications/utilities/surface/README
Normal file
@ -0,0 +1,46 @@
|
||||
2008-10-23
|
||||
|
||||
Contents:
|
||||
|
||||
surfaceAdd
|
||||
- adds to surface files. (but does not intersect or anything)
|
||||
|
||||
surfaceBooleanOp
|
||||
- Boolean operations (add, or, xor) on closed surfaces. Probably not working.
|
||||
|
||||
surfaceCheck
|
||||
- checks surface for incorrect topology. Checks normals of neighbouring faces.
|
||||
|
||||
surfaceCoarsen
|
||||
- Stan Melax coarsening algorithm
|
||||
|
||||
surfaceConvert
|
||||
- Converts surfaces to/from various formats
|
||||
|
||||
surfaceFind
|
||||
- Finds nearest vertex and face to given point.
|
||||
|
||||
surfaceMeshTriangulate
|
||||
- Triangulate external faces of mesh and write as surface.
|
||||
|
||||
surfacePointMerge
|
||||
- Explicit point merge of surface.
|
||||
|
||||
surfaceSetOutside
|
||||
- Orient normals on (closed) surface.
|
||||
|
||||
surfaceSmooth
|
||||
- Laplacian smoothing on surface vertices
|
||||
|
||||
surfaceSubset
|
||||
- Subsets surface
|
||||
|
||||
surfaceToPatch
|
||||
- Applies region information of surfaces to mesh.
|
||||
Each external face of mesh gets region number of nearest surface triangle.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
surfaceMeshConvert
|
||||
- Similar to surfaceConvert, but uses surfMesh library
|
||||
|
||||
3
applications/utilities/surface/surfaceAdd/Make/files
Normal file
3
applications/utilities/surface/surfaceAdd/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceAdd.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceAdd
|
||||
6
applications/utilities/surface/surfaceAdd/Make/options
Normal file
6
applications/utilities/surface/surfaceAdd/Make/options
Normal file
@ -0,0 +1,6 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ltriSurface \
|
||||
-lmeshTools
|
||||
293
applications/utilities/surface/surfaceAdd/surfaceAdd.C
Normal file
293
applications/utilities/surface/surfaceAdd/surfaceAdd.C
Normal file
@ -0,0 +1,293 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceAdd
|
||||
|
||||
Description
|
||||
Add two surfaces. Does geometric merge on points. Does not check for
|
||||
overlapping/intersecting triangles.
|
||||
|
||||
Keeps patches separate by renumbering.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "fileName.H"
|
||||
#include "triSurface.H"
|
||||
#include "OFstream.H"
|
||||
#include "IFstream.H"
|
||||
#include "triFace.H"
|
||||
#include "triFaceList.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"add two surfaces via a geometric merge on points."
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
|
||||
argList::addOption
|
||||
(
|
||||
"points",
|
||||
"file",
|
||||
"provide additional points"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"mergeRegions",
|
||||
"combine regions from both surfaces"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName inFileName1 = args[1];
|
||||
const fileName inFileName2 = args[2];
|
||||
const fileName outFileName = args[3];
|
||||
|
||||
const bool addPoint = args.optionFound("points");
|
||||
const bool mergeRegions = args.optionFound("mergeRegions");
|
||||
|
||||
if (addPoint)
|
||||
{
|
||||
Info<< "Reading a surface and adding points from a file"
|
||||
<< "; merging the points and writing the surface to another file"
|
||||
<< nl << endl;
|
||||
|
||||
Info<< "Surface : " << inFileName1<< nl
|
||||
<< "Points : " << args["points"] << nl
|
||||
<< "Writing : " << outFileName << nl << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Reading two surfaces"
|
||||
<< "; merging points and writing the surface to another file"
|
||||
<< nl << endl;
|
||||
|
||||
if (mergeRegions)
|
||||
{
|
||||
Info<< "Regions from the two files will get merged" << nl
|
||||
<< "Do not use this option if you want to keep the regions"
|
||||
<< " separate" << nl << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Regions from the two files will not get merged" << nl
|
||||
<< "Regions from " << inFileName2 << " will get offset so"
|
||||
<< " as not to overlap with the regions in " << inFileName1
|
||||
<< nl << endl;
|
||||
}
|
||||
|
||||
|
||||
Info<< "Surface1 : " << inFileName1<< nl
|
||||
<< "Surface2 : " << inFileName2<< nl
|
||||
<< "Writing : " << outFileName << nl << endl;
|
||||
}
|
||||
|
||||
const triSurface surface1(inFileName1);
|
||||
|
||||
Info<< "Surface1:" << endl;
|
||||
surface1.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
const pointField& points1 = surface1.points();
|
||||
|
||||
// Final surface
|
||||
triSurface combinedSurf;
|
||||
|
||||
if (addPoint)
|
||||
{
|
||||
IFstream pointsFile(args["points"]);
|
||||
pointField extraPoints(pointsFile);
|
||||
|
||||
Info<< "Additional Points:" << extraPoints.size() << endl;
|
||||
|
||||
vectorField pointsAll(points1);
|
||||
label pointI = pointsAll.size();
|
||||
pointsAll.setSize(pointsAll.size() + extraPoints.size());
|
||||
|
||||
forAll(extraPoints, i)
|
||||
{
|
||||
pointsAll[pointI++] = extraPoints[i];
|
||||
}
|
||||
|
||||
combinedSurf = triSurface(surface1, surface1.patches(), pointsAll);
|
||||
}
|
||||
else
|
||||
{
|
||||
const triSurface surface2(inFileName2);
|
||||
|
||||
Info<< "Surface2:" << endl;
|
||||
surface2.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
|
||||
// Make new storage
|
||||
List<labelledTri> facesAll(surface1.size() + surface2.size());
|
||||
|
||||
const pointField& points2 = surface2.points();
|
||||
|
||||
vectorField pointsAll(points1.size() + points2.size());
|
||||
|
||||
|
||||
label pointi = 0;
|
||||
// Copy points1 into pointsAll
|
||||
forAll(points1, point1i)
|
||||
{
|
||||
pointsAll[pointi++] = points1[point1i];
|
||||
}
|
||||
// Add surface2 points
|
||||
forAll(points2, point2i)
|
||||
{
|
||||
pointsAll[pointi++] = points2[point2i];
|
||||
}
|
||||
|
||||
|
||||
label trianglei = 0;
|
||||
|
||||
// Copy triangles1 into trianglesAll
|
||||
forAll(surface1, faceI)
|
||||
{
|
||||
facesAll[trianglei++] = surface1[faceI];
|
||||
}
|
||||
label nRegions1 = surface1.patches().size();
|
||||
|
||||
|
||||
if (!mergeRegions)
|
||||
{
|
||||
Info<< "Surface " << inFileName1 << " has " << nRegions1
|
||||
<< " regions"
|
||||
<< nl
|
||||
<< "All region numbers in " << inFileName2 << " will be offset"
|
||||
<< " by this amount" << nl << endl;
|
||||
}
|
||||
|
||||
// Add (renumbered) surface2 triangles
|
||||
forAll(surface2, faceI)
|
||||
{
|
||||
const labelledTri& tri = surface2[faceI];
|
||||
|
||||
labelledTri& destTri = facesAll[trianglei++];
|
||||
destTri[0] = tri[0] + points1.size();
|
||||
destTri[1] = tri[1] + points1.size();
|
||||
destTri[2] = tri[2] + points1.size();
|
||||
if (mergeRegions)
|
||||
{
|
||||
destTri.region() = tri.region();
|
||||
}
|
||||
else
|
||||
{
|
||||
destTri.region() = tri.region() + nRegions1;
|
||||
}
|
||||
}
|
||||
|
||||
label nRegions2 = surface2.patches().size();
|
||||
|
||||
geometricSurfacePatchList newPatches;
|
||||
|
||||
if (mergeRegions)
|
||||
{
|
||||
// Overwrite
|
||||
newPatches.setSize(max(nRegions1, nRegions2));
|
||||
|
||||
forAll(surface1.patches(), patchI)
|
||||
{
|
||||
newPatches[patchI] = surface1.patches()[patchI];
|
||||
}
|
||||
forAll(surface2.patches(), patchI)
|
||||
{
|
||||
newPatches[patchI] = surface2.patches()[patchI];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Regions from " << inFileName2 << " have been renumbered:"
|
||||
<< nl
|
||||
<< " old\tnew" << nl;
|
||||
|
||||
for (label regionI = 0; regionI < nRegions2; regionI++)
|
||||
{
|
||||
Info<< " " << regionI << '\t' << regionI+nRegions1
|
||||
<< nl;
|
||||
}
|
||||
Info<< nl;
|
||||
|
||||
newPatches.setSize(nRegions1 + nRegions2);
|
||||
|
||||
label newPatchI = 0;
|
||||
|
||||
forAll(surface1.patches(), patchI)
|
||||
{
|
||||
newPatches[newPatchI++] = surface1.patches()[patchI];
|
||||
}
|
||||
|
||||
forAll(surface2.patches(), patchI)
|
||||
{
|
||||
newPatches[newPatchI++] = surface2.patches()[patchI];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Info<< "New patches:" << nl;
|
||||
forAll(newPatches, patchI)
|
||||
{
|
||||
Info<< " " << patchI << '\t' << newPatches[patchI].name() << nl;
|
||||
}
|
||||
Info<< endl;
|
||||
|
||||
|
||||
// Construct new surface mesh
|
||||
combinedSurf = triSurface(facesAll, newPatches, pointsAll);
|
||||
}
|
||||
|
||||
// Merge all common points and do some checks
|
||||
combinedSurf.cleanup(true);
|
||||
|
||||
Info<< "Merged surface:" << endl;
|
||||
|
||||
combinedSurf.writeStats(Info);
|
||||
|
||||
Info<< endl;
|
||||
|
||||
Info<< "Writing : " << outFileName << endl;
|
||||
|
||||
// No need to 'group' while writing since all in correct order anyway.
|
||||
combinedSurf.write(outFileName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceAutoPatch.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceAutoPatch
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
@ -0,0 +1,125 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceAutoPatch
|
||||
|
||||
Description
|
||||
Patches surface according to feature angle. Like autoPatch.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "triangle.H"
|
||||
#include "triSurface.H"
|
||||
#include "argList.H"
|
||||
#include "surfaceFeatures.H"
|
||||
#include "treeBoundBox.H"
|
||||
#include "meshTools.H"
|
||||
#include "OFstream.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("input surfaceFile");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList::validArgs.append("includedAngle [0..180]");
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName inFileName = args[1];
|
||||
const fileName outFileName = args[2];
|
||||
const scalar includedAngle = args.argRead<scalar>(3);
|
||||
|
||||
Info<< "Surface : " << inFileName << nl << endl;
|
||||
|
||||
|
||||
// Read
|
||||
// ~~~~
|
||||
|
||||
Info<< "Reading : " << inFileName << endl;
|
||||
triSurface surf(inFileName);
|
||||
|
||||
Info<< "Read surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
|
||||
|
||||
// Construct features from surface&featureangle
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Info<< "Constructing feature set from included angle " << includedAngle
|
||||
<< endl;
|
||||
|
||||
surfaceFeatures set(surf, includedAngle);
|
||||
|
||||
Info<< nl
|
||||
<< "Feature set:" << nl
|
||||
<< " feature points : " << set.featurePoints().size() << nl
|
||||
<< " feature edges : " << set.featureEdges().size() << nl
|
||||
<< " of which" << nl
|
||||
<< " region edges : " << set.nRegionEdges() << nl
|
||||
<< " external edges : " << set.nExternalEdges() << nl
|
||||
<< " internal edges : " << set.nInternalEdges() << nl
|
||||
<< endl;
|
||||
|
||||
// Get per-edge status.
|
||||
boolList borderEdge(surf.nEdges(), false);
|
||||
forAll(set.featureEdges(), i)
|
||||
{
|
||||
borderEdge[set.featureEdges()[i]] = true;
|
||||
}
|
||||
|
||||
labelList faceRegion(surf.size());
|
||||
label nRegions = surf.markZones(borderEdge, faceRegion);
|
||||
|
||||
// Reregion triangles.
|
||||
forAll(surf, i)
|
||||
{
|
||||
surf[i].region() = faceRegion[i];
|
||||
}
|
||||
|
||||
// Create some patches
|
||||
surf.patches().setSize(nRegions);
|
||||
|
||||
forAll(surf.patches(), patchI)
|
||||
{
|
||||
surf.patches()[patchI].name() = "patch" + Foam::name(patchI);
|
||||
surf.patches()[patchI].geometricType() = "empty";
|
||||
}
|
||||
|
||||
|
||||
Info<< "Writing : " << outFileName << endl;
|
||||
surf.write(outFileName, true);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceBooleanFeatures.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceBooleanFeatures
|
||||
@ -0,0 +1,9 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||
-I$(LIB_SRC)/edgeMesh/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ltriSurface \
|
||||
-ledgeMesh \
|
||||
-lmeshTools
|
||||
@ -0,0 +1,821 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceBooleanFeatures
|
||||
|
||||
Description
|
||||
|
||||
Generates the extendedFeatureEdgeMesh for the interface between a boolean
|
||||
operation on two surfaces. Assumes that the orientation of the surfaces is
|
||||
correct:
|
||||
|
||||
+ if the operation is union or intersection, that both surface's normals
|
||||
(n) have the same orientation with respect to a point, i.e. surfaces and b
|
||||
are orientated the same with respect to point x:
|
||||
|
||||
@verbatim
|
||||
_______
|
||||
| |--> n
|
||||
| ___|___ x
|
||||
|a | | |--> n
|
||||
|___|___| b|
|
||||
| |
|
||||
|_______|
|
||||
|
||||
@endverbatim
|
||||
|
||||
+ if the operation is a subtraction, the surfaces should be oppositely
|
||||
oriented with respect to a point, i.e. for (a - b), then b's orientation
|
||||
should be such that x is "inside", and a's orientation such that x is
|
||||
"outside"
|
||||
|
||||
@verbatim
|
||||
_______
|
||||
| |--> n
|
||||
| ___|___ x
|
||||
|a | | |
|
||||
|___|___| b|
|
||||
| n <--|
|
||||
|_______|
|
||||
|
||||
@endverbatim
|
||||
|
||||
When the operation is peformed - for union, all of the edges generates where
|
||||
one surfaces cuts another are all "internal" for union, and "external" for
|
||||
intersection, b - a and a - b. This has been assumed, formal (dis)proof is
|
||||
invited.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "triSurface.H"
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "featureEdgeMesh.H"
|
||||
#include "extendedFeatureEdgeMesh.H"
|
||||
#include "triSurfaceSearch.H"
|
||||
#include "OFstream.H"
|
||||
#include "booleanSurface.H"
|
||||
#include "edgeIntersections.H"
|
||||
#include "meshTools.H"
|
||||
#include "labelPair.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
bool intersectSurfaces
|
||||
(
|
||||
triSurface& surf,
|
||||
edgeIntersections& edgeCuts
|
||||
)
|
||||
{
|
||||
bool hasMoved = false;
|
||||
|
||||
for (label iter = 0; iter < 10; iter++)
|
||||
{
|
||||
Info<< "Determining intersections of surface edges with itself" << endl;
|
||||
|
||||
// Determine surface edge intersections. Allow surface to be moved.
|
||||
|
||||
// Number of iterations needed to resolve degenerates
|
||||
label nIters = 0;
|
||||
{
|
||||
triSurfaceSearch querySurf(surf);
|
||||
|
||||
scalarField surfPointTol
|
||||
(
|
||||
1e-3*edgeIntersections::minEdgeLength(surf)
|
||||
);
|
||||
|
||||
// Determine raw intersections
|
||||
edgeCuts = edgeIntersections
|
||||
(
|
||||
surf,
|
||||
querySurf,
|
||||
surfPointTol
|
||||
);
|
||||
|
||||
// Shuffle a bit to resolve degenerate edge-face hits
|
||||
{
|
||||
pointField points(surf.points());
|
||||
|
||||
nIters =
|
||||
edgeCuts.removeDegenerates
|
||||
(
|
||||
5, // max iterations
|
||||
surf,
|
||||
querySurf,
|
||||
surfPointTol,
|
||||
points // work array
|
||||
);
|
||||
|
||||
if (nIters != 0)
|
||||
{
|
||||
// Update geometric quantities
|
||||
surf.movePoints(points);
|
||||
hasMoved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMoved)
|
||||
{
|
||||
fileName newFile("surf.obj");
|
||||
Info<< "Surface has been moved. Writing to " << newFile << endl;
|
||||
surf.write(newFile);
|
||||
}
|
||||
|
||||
return hasMoved;
|
||||
}
|
||||
|
||||
|
||||
// Keep on shuffling surface points until no more degenerate intersections.
|
||||
// Moves both surfaces and updates set of edge cuts.
|
||||
bool intersectSurfaces
|
||||
(
|
||||
triSurface& surf1,
|
||||
edgeIntersections& edgeCuts1,
|
||||
triSurface& surf2,
|
||||
edgeIntersections& edgeCuts2
|
||||
)
|
||||
{
|
||||
bool hasMoved1 = false;
|
||||
bool hasMoved2 = false;
|
||||
|
||||
for (label iter = 0; iter < 10; iter++)
|
||||
{
|
||||
Info<< "Determining intersections of surf1 edges with surf2"
|
||||
<< " faces" << endl;
|
||||
|
||||
// Determine surface1 edge intersections. Allow surface to be moved.
|
||||
|
||||
// Number of iterations needed to resolve degenerates
|
||||
label nIters1 = 0;
|
||||
{
|
||||
triSurfaceSearch querySurf2(surf2);
|
||||
|
||||
scalarField surf1PointTol
|
||||
(
|
||||
1e-3*edgeIntersections::minEdgeLength(surf1)
|
||||
);
|
||||
|
||||
// Determine raw intersections
|
||||
edgeCuts1 = edgeIntersections
|
||||
(
|
||||
surf1,
|
||||
querySurf2,
|
||||
surf1PointTol
|
||||
);
|
||||
|
||||
// Shuffle a bit to resolve degenerate edge-face hits
|
||||
{
|
||||
pointField points1(surf1.points());
|
||||
|
||||
nIters1 =
|
||||
edgeCuts1.removeDegenerates
|
||||
(
|
||||
5, // max iterations
|
||||
surf1,
|
||||
querySurf2,
|
||||
surf1PointTol,
|
||||
points1 // work array
|
||||
);
|
||||
|
||||
if (nIters1 != 0)
|
||||
{
|
||||
// Update geometric quantities
|
||||
surf1.movePoints(points1);
|
||||
hasMoved1 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "Determining intersections of surf2 edges with surf1"
|
||||
<< " faces" << endl;
|
||||
|
||||
label nIters2 = 0;
|
||||
{
|
||||
triSurfaceSearch querySurf1(surf1);
|
||||
|
||||
scalarField surf2PointTol
|
||||
(
|
||||
1e-3*edgeIntersections::minEdgeLength(surf2)
|
||||
);
|
||||
|
||||
// Determine raw intersections
|
||||
edgeCuts2 = edgeIntersections
|
||||
(
|
||||
surf2,
|
||||
querySurf1,
|
||||
surf2PointTol
|
||||
);
|
||||
|
||||
// Shuffle a bit to resolve degenerate edge-face hits
|
||||
{
|
||||
pointField points2(surf2.points());
|
||||
|
||||
nIters2 =
|
||||
edgeCuts2.removeDegenerates
|
||||
(
|
||||
5, // max iterations
|
||||
surf2,
|
||||
querySurf1,
|
||||
surf2PointTol,
|
||||
points2 // work array
|
||||
);
|
||||
|
||||
if (nIters2 != 0)
|
||||
{
|
||||
// Update geometric quantities
|
||||
surf2.movePoints(points2);
|
||||
hasMoved2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nIters1 == 0 && nIters2 == 0)
|
||||
{
|
||||
Info<< "** Resolved all intersections to be proper edge-face pierce"
|
||||
<< endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMoved1)
|
||||
{
|
||||
fileName newFile("surf1.obj");
|
||||
Info<< "Surface 1 has been moved. Writing to " << newFile
|
||||
<< endl;
|
||||
surf1.write(newFile);
|
||||
}
|
||||
|
||||
if (hasMoved2)
|
||||
{
|
||||
fileName newFile("surf2.obj");
|
||||
Info<< "Surface 2 has been moved. Writing to " << newFile
|
||||
<< endl;
|
||||
surf2.write(newFile);
|
||||
}
|
||||
|
||||
return hasMoved1 || hasMoved2;
|
||||
}
|
||||
|
||||
|
||||
label calcNormalDirection
|
||||
(
|
||||
const vector& normal,
|
||||
const vector& otherNormal,
|
||||
const vector& edgeDir,
|
||||
const vector& faceCentre,
|
||||
const vector& pointOnEdge
|
||||
)
|
||||
{
|
||||
vector cross = (normal ^ edgeDir);
|
||||
cross /= mag(cross);
|
||||
|
||||
vector fC0tofE0 = faceCentre - pointOnEdge;
|
||||
fC0tofE0 /= mag(fC0tofE0);
|
||||
|
||||
label nDir = ((cross & fC0tofE0) > 0.0 ? 1 : -1);
|
||||
|
||||
nDir *= ((otherNormal & fC0tofE0) > 0.0 ? -1 : 1);
|
||||
|
||||
return nDir;
|
||||
}
|
||||
|
||||
|
||||
void calcEdgeCuts
|
||||
(
|
||||
triSurface& surf1,
|
||||
triSurface& surf2,
|
||||
const bool perturb,
|
||||
edgeIntersections& edge1Cuts,
|
||||
edgeIntersections& edge2Cuts
|
||||
)
|
||||
{
|
||||
if (perturb)
|
||||
{
|
||||
intersectSurfaces
|
||||
(
|
||||
surf1,
|
||||
edge1Cuts,
|
||||
surf2,
|
||||
edge2Cuts
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
triSurfaceSearch querySurf2(surf2);
|
||||
|
||||
Info<< "Determining intersections of surf1 edges with surf2 faces"
|
||||
<< endl;
|
||||
|
||||
edge1Cuts = edgeIntersections
|
||||
(
|
||||
surf1,
|
||||
querySurf2,
|
||||
1e-3*edgeIntersections::minEdgeLength(surf1)
|
||||
);
|
||||
|
||||
triSurfaceSearch querySurf1(surf1);
|
||||
|
||||
Info<< "Determining intersections of surf2 edges with surf1 faces"
|
||||
<< endl;
|
||||
|
||||
edge2Cuts = edgeIntersections
|
||||
(
|
||||
surf2,
|
||||
querySurf1,
|
||||
1e-3*edgeIntersections::minEdgeLength(surf2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void calcFeaturePoints(const pointField& points, const edgeList& edges)
|
||||
{
|
||||
edgeMesh eMesh(points, edges);
|
||||
|
||||
const labelListList& pointEdges = eMesh.pointEdges();
|
||||
|
||||
|
||||
// Get total number of feature points
|
||||
label nFeaturePoints = 0;
|
||||
forAll(pointEdges, pI)
|
||||
{
|
||||
const labelList& pEdges = pointEdges[pI];
|
||||
|
||||
if (pEdges.size() == 1)
|
||||
{
|
||||
nFeaturePoints++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate addressing from feature point to cut point and cut edge
|
||||
labelList featurePointToCutPoint(nFeaturePoints);
|
||||
labelList featurePointToCutEdge(nFeaturePoints);
|
||||
|
||||
label nFeatPts = 0;
|
||||
forAll(pointEdges, pI)
|
||||
{
|
||||
const labelList& pEdges = pointEdges[pI];
|
||||
|
||||
if (pEdges.size() == 1)
|
||||
{
|
||||
featurePointToCutPoint[nFeatPts] = pI;
|
||||
featurePointToCutEdge[nFeatPts] = pEdges[0];
|
||||
nFeatPts++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
label concaveStart = 0;
|
||||
label mixedStart = 0;
|
||||
label nonFeatureStart = nFeaturePoints;
|
||||
|
||||
|
||||
labelListList featurePointNormals(nFeaturePoints);
|
||||
labelListList featurePointEdges(nFeaturePoints);
|
||||
labelList regionEdges;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("action");
|
||||
argList::validArgs.append("surface file");
|
||||
argList::validArgs.append("surface file");
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"surf1Baffle",
|
||||
"Mark surface 1 as a baffle"
|
||||
);
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"surf2Baffle",
|
||||
"Mark surface 2 as a baffle"
|
||||
);
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"perturb",
|
||||
"Perturb surface points to escape degenerate intersections"
|
||||
);
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"invertedSpace",
|
||||
"do the surfaces have inverted space orientation, "
|
||||
"i.e. a point at infinity is considered inside. "
|
||||
"This is only sensible for union and intersection."
|
||||
);
|
||||
|
||||
# include "setRootCase.H"
|
||||
# include "createTime.H"
|
||||
|
||||
word action(args.args()[1]);
|
||||
|
||||
HashTable<booleanSurface::booleanOpType> validActions;
|
||||
validActions.insert("intersection", booleanSurface::INTERSECTION);
|
||||
validActions.insert("union", booleanSurface::UNION);
|
||||
validActions.insert("difference", booleanSurface::DIFFERENCE);
|
||||
|
||||
if (!validActions.found(action))
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Unsupported action " << action << endl
|
||||
<< "Supported actions:" << validActions.toc() << abort(FatalError);
|
||||
}
|
||||
|
||||
fileName surf1Name(args.args()[2]);
|
||||
Info<< "Reading surface " << surf1Name << endl;
|
||||
triSurface surf1(surf1Name);
|
||||
|
||||
Info<< surf1Name << " statistics:" << endl;
|
||||
surf1.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
fileName surf2Name(args[3]);
|
||||
Info<< "Reading surface " << surf2Name << endl;
|
||||
triSurface surf2(surf2Name);
|
||||
|
||||
Info<< surf2Name << " statistics:" << endl;
|
||||
surf2.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
const bool surf1Baffle = args.optionFound("surf1Baffle");
|
||||
const bool surf2Baffle = args.optionFound("surf2Baffle");
|
||||
|
||||
edgeIntersections edge1Cuts;
|
||||
edgeIntersections edge2Cuts;
|
||||
|
||||
bool invertedSpace = args.optionFound("invertedSpace");
|
||||
|
||||
if (invertedSpace && validActions[action] == booleanSurface::DIFFERENCE)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Inverted space only makes sense for union or intersection."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// Calculate the points where the edges are cut by the other surface
|
||||
calcEdgeCuts
|
||||
(
|
||||
surf1,
|
||||
surf2,
|
||||
args.optionFound("perturb"),
|
||||
edge1Cuts,
|
||||
edge2Cuts
|
||||
);
|
||||
|
||||
// Determine intersection edges from the edge cuts
|
||||
surfaceIntersection inter
|
||||
(
|
||||
surf1,
|
||||
edge1Cuts,
|
||||
surf2,
|
||||
edge2Cuts
|
||||
);
|
||||
|
||||
fileName sFeatFileName
|
||||
(
|
||||
surf1Name.lessExt().name()
|
||||
+ "_"
|
||||
+ surf2Name.lessExt().name()
|
||||
+ "_"
|
||||
+ action
|
||||
);
|
||||
|
||||
label nFeatEds = inter.cutEdges().size();
|
||||
|
||||
DynamicList<vector> normals(2*nFeatEds);
|
||||
vectorField edgeDirections(nFeatEds, vector::zero);
|
||||
DynamicList<extendedFeatureEdgeMesh::sideVolumeType> normalVolumeTypes
|
||||
(
|
||||
2*nFeatEds
|
||||
);
|
||||
List<DynamicList<label> > edgeNormals(nFeatEds);
|
||||
List<DynamicList<label> > normalDirections(nFeatEds);
|
||||
|
||||
forAllConstIter(labelPairLookup, inter.facePairToEdge(), iter)
|
||||
{
|
||||
const label& cutEdgeI = iter();
|
||||
const labelPair& facePair = iter.key();
|
||||
|
||||
const edge& fE = inter.cutEdges()[cutEdgeI];
|
||||
|
||||
const vector& norm1 = surf1.faceNormals()[facePair.first()];
|
||||
const vector& norm2 = surf2.faceNormals()[facePair.second()];
|
||||
|
||||
DynamicList<label>& eNormals = edgeNormals[cutEdgeI];
|
||||
DynamicList<label>& nDirections = normalDirections[cutEdgeI];
|
||||
|
||||
edgeDirections[cutEdgeI] = fE.vec(inter.cutPoints());
|
||||
|
||||
normals.append(norm1);
|
||||
eNormals.append(normals.size() - 1);
|
||||
|
||||
if (surf1Baffle)
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::BOTH);
|
||||
|
||||
nDirections.append(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::INSIDE);
|
||||
nDirections.append
|
||||
(
|
||||
calcNormalDirection
|
||||
(
|
||||
norm1,
|
||||
norm2,
|
||||
edgeDirections[cutEdgeI],
|
||||
surf1[facePair.first()].centre(surf1.points()),
|
||||
inter.cutPoints()[fE.start()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
normals.append(norm2);
|
||||
eNormals.append(normals.size() - 1);
|
||||
|
||||
if (surf2Baffle)
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::BOTH);
|
||||
|
||||
nDirections.append(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::INSIDE);
|
||||
|
||||
nDirections.append
|
||||
(
|
||||
calcNormalDirection
|
||||
(
|
||||
norm2,
|
||||
norm1,
|
||||
edgeDirections[cutEdgeI],
|
||||
surf2[facePair.second()].centre(surf2.points()),
|
||||
inter.cutPoints()[fE.start()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (surf1Baffle)
|
||||
{
|
||||
normals.append(norm2);
|
||||
|
||||
if (surf2Baffle)
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::BOTH);
|
||||
|
||||
nDirections.append(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::INSIDE);
|
||||
|
||||
nDirections.append
|
||||
(
|
||||
calcNormalDirection
|
||||
(
|
||||
norm2,
|
||||
norm1,
|
||||
edgeDirections[cutEdgeI],
|
||||
surf2[facePair.second()].centre(surf2.points()),
|
||||
inter.cutPoints()[fE.start()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
eNormals.append(normals.size() - 1);
|
||||
}
|
||||
|
||||
if (surf2Baffle)
|
||||
{
|
||||
normals.append(norm1);
|
||||
|
||||
if (surf1Baffle)
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::BOTH);
|
||||
|
||||
nDirections.append(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalVolumeTypes.append(extendedFeatureEdgeMesh::INSIDE);
|
||||
|
||||
nDirections.append
|
||||
(
|
||||
calcNormalDirection
|
||||
(
|
||||
norm1,
|
||||
norm2,
|
||||
edgeDirections[cutEdgeI],
|
||||
surf1[facePair.first()].centre(surf1.points()),
|
||||
inter.cutPoints()[fE.start()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
eNormals.append(normals.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
label internalStart = -1;
|
||||
label nIntOrExt = 0;
|
||||
label nFlat = 0;
|
||||
label nOpen = 0;
|
||||
label nMultiple = 0;
|
||||
|
||||
forAll(edgeNormals, eI)
|
||||
{
|
||||
label nEdNorms = edgeNormals[eI].size();
|
||||
|
||||
if (nEdNorms == 1)
|
||||
{
|
||||
nOpen++;
|
||||
}
|
||||
else if (nEdNorms == 2)
|
||||
{
|
||||
const vector& n0(normals[edgeNormals[eI][0]]);
|
||||
const vector& n1(normals[edgeNormals[eI][1]]);
|
||||
|
||||
if ((n0 & n1) > extendedFeatureEdgeMesh::cosNormalAngleTol_)
|
||||
{
|
||||
nFlat++;
|
||||
}
|
||||
else
|
||||
{
|
||||
nIntOrExt++;
|
||||
}
|
||||
}
|
||||
else if (nEdNorms > 2)
|
||||
{
|
||||
nMultiple++;
|
||||
}
|
||||
}
|
||||
|
||||
if (validActions[action] == booleanSurface::UNION)
|
||||
{
|
||||
if (!invertedSpace)
|
||||
{
|
||||
// All edges are internal
|
||||
internalStart = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All edges are external
|
||||
internalStart = nIntOrExt;
|
||||
}
|
||||
}
|
||||
else if (validActions[action] == booleanSurface::INTERSECTION)
|
||||
{
|
||||
if (!invertedSpace)
|
||||
{
|
||||
// All edges are external
|
||||
internalStart = nIntOrExt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All edges are internal
|
||||
internalStart = 0;
|
||||
}
|
||||
}
|
||||
else if (validActions[action] == booleanSurface::DIFFERENCE)
|
||||
{
|
||||
// All edges are external
|
||||
internalStart = nIntOrExt;
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Unsupported booleanSurface:booleanOpType and space "
|
||||
<< action << " " << invertedSpace
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
// There are no feature points supported by surfaceIntersection
|
||||
// Flat, open or multiple edges are assumed to be impossible
|
||||
// Region edges are not explicitly supported by surfaceIntersection
|
||||
|
||||
vectorField normalsTmp(normals);
|
||||
List<extendedFeatureEdgeMesh::sideVolumeType> normalVolumeTypesTmp
|
||||
(
|
||||
normalVolumeTypes
|
||||
);
|
||||
labelListList edgeNormalsTmp(edgeNormals.size());
|
||||
forAll(edgeNormalsTmp, i)
|
||||
{
|
||||
edgeNormalsTmp[i] = edgeNormals[i];
|
||||
}
|
||||
labelListList normalDirectionsTmp(normalDirections.size());
|
||||
forAll(normalDirectionsTmp, i)
|
||||
{
|
||||
normalDirectionsTmp[i] = normalDirections[i];
|
||||
}
|
||||
|
||||
calcFeaturePoints(inter.cutPoints(), inter.cutEdges());
|
||||
|
||||
extendedFeatureEdgeMesh feMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
sFeatFileName + ".extendedFeatureEdgeMesh",
|
||||
runTime.constant(),
|
||||
"extendedFeatureEdgeMesh",
|
||||
runTime,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE
|
||||
),
|
||||
inter.cutPoints(),
|
||||
inter.cutEdges(),
|
||||
|
||||
0, // concaveStart,
|
||||
0, // mixedStart,
|
||||
0, // nonFeatureStart,
|
||||
|
||||
internalStart, // internalStart,
|
||||
nIntOrExt, // flatStart,
|
||||
nIntOrExt + nFlat, // openStart,
|
||||
nIntOrExt + nFlat + nOpen, // multipleStart,
|
||||
|
||||
normalsTmp,
|
||||
normalVolumeTypesTmp,
|
||||
edgeDirections,
|
||||
normalDirectionsTmp,
|
||||
edgeNormalsTmp,
|
||||
|
||||
labelListList(0), // featurePointNormals,
|
||||
labelListList(0), // featurePointEdges,
|
||||
labelList(0) // regionEdges
|
||||
);
|
||||
|
||||
feMesh.write();
|
||||
|
||||
feMesh.writeObj(feMesh.path()/sFeatFileName);
|
||||
|
||||
{
|
||||
// Write a featureEdgeMesh for backwards compatibility
|
||||
featureEdgeMesh bfeMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
sFeatFileName + ".eMesh", // name
|
||||
runTime.constant(), // instance
|
||||
"triSurface",
|
||||
runTime, // registry
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
feMesh.points(),
|
||||
feMesh.edges()
|
||||
);
|
||||
|
||||
Info<< nl << "Writing featureEdgeMesh to "
|
||||
<< bfeMesh.objectPath() << endl;
|
||||
|
||||
bfeMesh.regIOobject::write();
|
||||
}
|
||||
|
||||
Info << "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/utilities/surface/surfaceCheck/Make/files
Normal file
3
applications/utilities/surface/surfaceCheck/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceCheck.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceCheck
|
||||
11
applications/utilities/surface/surfaceCheck/Make/options
Normal file
11
applications/utilities/surface/surfaceCheck/Make/options
Normal file
@ -0,0 +1,11 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/sampling/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lsampling \
|
||||
-ltriSurface \
|
||||
-lsurfMesh \
|
||||
-lmeshTools
|
||||
793
applications/utilities/surface/surfaceCheck/surfaceCheck.C
Normal file
793
applications/utilities/surface/surfaceCheck/surfaceCheck.C
Normal file
@ -0,0 +1,793 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2014 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
|
||||
surfaceCheck
|
||||
|
||||
Description
|
||||
Checks geometric and topological quality of a surface.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "triangle.H"
|
||||
#include "triSurface.H"
|
||||
#include "triSurfaceSearch.H"
|
||||
#include "argList.H"
|
||||
#include "OFstream.H"
|
||||
#include "OBJstream.H"
|
||||
#include "SortableList.H"
|
||||
#include "PatchTools.H"
|
||||
#include "vtkSurfaceWriter.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// Does face use valid vertices?
|
||||
bool validTri
|
||||
(
|
||||
const bool verbose,
|
||||
const triSurface& surf,
|
||||
const label faceI
|
||||
)
|
||||
{
|
||||
// Simple check on indices ok.
|
||||
|
||||
const labelledTri& f = surf[faceI];
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
if (f[fp] < 0 || f[fp] >= surf.points().size())
|
||||
{
|
||||
WarningIn("validTri(const triSurface&, const label)")
|
||||
<< "triangle " << faceI << " vertices " << f
|
||||
<< " uses point indices outside point range 0.."
|
||||
<< surf.points().size()-1 << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
|
||||
{
|
||||
WarningIn("validTri(const triSurface&, const label)")
|
||||
<< "triangle " << faceI
|
||||
<< " uses non-unique vertices " << f
|
||||
<< " coords:" << f.points(surf.points())
|
||||
<< endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// duplicate triangle check
|
||||
|
||||
const labelList& fFaces = surf.faceFaces()[faceI];
|
||||
|
||||
// Check if faceNeighbours use same points as this face.
|
||||
// Note: discards normal information - sides of baffle are merged.
|
||||
forAll(fFaces, i)
|
||||
{
|
||||
label nbrFaceI = fFaces[i];
|
||||
|
||||
if (nbrFaceI <= faceI)
|
||||
{
|
||||
// lower numbered faces already checked
|
||||
continue;
|
||||
}
|
||||
|
||||
const labelledTri& nbrF = surf[nbrFaceI];
|
||||
|
||||
if
|
||||
(
|
||||
((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
|
||||
&& ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
|
||||
&& ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
|
||||
)
|
||||
{
|
||||
WarningIn("validTri(const triSurface&, const label)")
|
||||
<< "triangle " << faceI << " vertices " << f
|
||||
<< " has the same vertices as triangle " << nbrFaceI
|
||||
<< " vertices " << nbrF
|
||||
<< " coords:" << f.points(surf.points())
|
||||
<< endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
labelList countBins
|
||||
(
|
||||
const scalar min,
|
||||
const scalar max,
|
||||
const label nBins,
|
||||
const scalarField& vals
|
||||
)
|
||||
{
|
||||
scalar dist = nBins/(max - min);
|
||||
|
||||
labelList binCount(nBins, 0);
|
||||
|
||||
forAll(vals, i)
|
||||
{
|
||||
scalar val = vals[i];
|
||||
|
||||
label index = -1;
|
||||
|
||||
if (Foam::mag(val - min) < SMALL)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (val >= max - SMALL)
|
||||
{
|
||||
index = nBins - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = label((val - min)*dist);
|
||||
|
||||
if ((index < 0) || (index >= nBins))
|
||||
{
|
||||
WarningIn
|
||||
(
|
||||
"countBins(const scalar, const scalar, const label"
|
||||
", const scalarField&)"
|
||||
) << "value " << val << " at index " << i
|
||||
<< " outside range " << min << " .. " << max << endl;
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = nBins - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
binCount[index]++;
|
||||
}
|
||||
|
||||
return binCount;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::addBoolOption
|
||||
(
|
||||
"checkSelfIntersection",
|
||||
"also check for self-intersection"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"splitNonManifold",
|
||||
"split surface along non-manifold edges"
|
||||
" (default split is fully disconnected)"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"verbose",
|
||||
"verbose operation"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"blockMesh",
|
||||
"write vertices/blocks for blockMeshDict"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const bool checkSelfIntersect = args.optionFound("checkSelfIntersection");
|
||||
const bool verbose = args.optionFound("verbose");
|
||||
const bool splitNonManifold = args.optionFound("splitNonManifold");
|
||||
|
||||
Info<< "Reading surface from " << surfFileName << " ..." << nl << endl;
|
||||
|
||||
|
||||
// Read
|
||||
// ~~~~
|
||||
|
||||
triSurface surf(surfFileName);
|
||||
|
||||
|
||||
Info<< "Statistics:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
// write bounding box corners
|
||||
if (args.optionFound("blockMesh"))
|
||||
{
|
||||
pointField cornerPts(boundBox(surf.points(), false).points());
|
||||
|
||||
Info<<"// blockMeshDict info" << nl
|
||||
<<"vertices\n(" << nl;
|
||||
forAll(cornerPts, ptI)
|
||||
{
|
||||
Info << " " << cornerPts[ptI] << nl;
|
||||
}
|
||||
|
||||
// number of divisions needs adjustment later
|
||||
Info<<");\n" << nl
|
||||
<<"blocks\n"
|
||||
<<"(\n"
|
||||
<<" hex (0 1 2 3 4 5 6 7) (10 10 10) simpleGrading (1 1 1)\n"
|
||||
<<");\n" << nl;
|
||||
|
||||
Info<<"edges\n();" << nl
|
||||
<<"patches\n();" << endl;
|
||||
}
|
||||
|
||||
|
||||
// Region sizes
|
||||
// ~~~~~~~~~~~~
|
||||
|
||||
{
|
||||
labelList regionSize(surf.patches().size(), 0);
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
label region = surf[faceI].region();
|
||||
|
||||
if (region < 0 || region >= regionSize.size())
|
||||
{
|
||||
WarningIn(args.executable())
|
||||
<< "Triangle " << faceI << " vertices " << surf[faceI]
|
||||
<< " has region " << region << " which is outside the range"
|
||||
<< " of regions 0.." << surf.patches().size()-1
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
regionSize[region]++;
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "Region\tSize" << nl
|
||||
<< "------\t----" << nl;
|
||||
forAll(surf.patches(), patchI)
|
||||
{
|
||||
Info<< surf.patches()[patchI].name() << '\t'
|
||||
<< regionSize[patchI] << nl;
|
||||
}
|
||||
Info<< nl << endl;
|
||||
}
|
||||
|
||||
|
||||
// Check triangles
|
||||
// ~~~~~~~~~~~~~~~
|
||||
|
||||
{
|
||||
DynamicList<label> illegalFaces(surf.size()/100 + 1);
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
if (!validTri(verbose, surf, faceI))
|
||||
{
|
||||
illegalFaces.append(faceI);
|
||||
}
|
||||
}
|
||||
|
||||
if (illegalFaces.size())
|
||||
{
|
||||
Info<< "Surface has " << illegalFaces.size()
|
||||
<< " illegal triangles." << endl;
|
||||
|
||||
OFstream str("illegalFaces");
|
||||
Info<< "Dumping conflicting face labels to " << str.name() << endl
|
||||
<< "Paste this into the input for surfaceSubset" << endl;
|
||||
str << illegalFaces;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Surface has no illegal triangles." << endl;
|
||||
}
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Triangle quality
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
|
||||
{
|
||||
scalarField triQ(surf.size(), 0);
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
const labelledTri& f = surf[faceI];
|
||||
|
||||
if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
|
||||
{
|
||||
//WarningIn(args.executable())
|
||||
// << "Illegal triangle " << faceI << " vertices " << f
|
||||
// << " coords " << f.points(surf.points()) << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
triQ[faceI] = triPointRef
|
||||
(
|
||||
surf.points()[f[0]],
|
||||
surf.points()[f[1]],
|
||||
surf.points()[f[2]]
|
||||
).quality();
|
||||
}
|
||||
}
|
||||
|
||||
labelList binCount = countBins(0, 1, 20, triQ);
|
||||
|
||||
Info<< "Triangle quality (equilateral=1, collapsed=0):"
|
||||
<< endl;
|
||||
|
||||
|
||||
OSstream& os = Info;
|
||||
os.width(4);
|
||||
|
||||
scalar dist = (1.0 - 0.0)/20.0;
|
||||
scalar min = 0;
|
||||
forAll(binCount, binI)
|
||||
{
|
||||
Info<< " " << min << " .. " << min+dist << " : "
|
||||
<< 1.0/surf.size() * binCount[binI]
|
||||
<< endl;
|
||||
min += dist;
|
||||
}
|
||||
Info<< endl;
|
||||
|
||||
label minIndex = findMin(triQ);
|
||||
label maxIndex = findMax(triQ);
|
||||
|
||||
Info<< " min " << triQ[minIndex] << " for triangle " << minIndex
|
||||
<< nl
|
||||
<< " max " << triQ[maxIndex] << " for triangle " << maxIndex
|
||||
<< nl
|
||||
<< endl;
|
||||
|
||||
|
||||
if (triQ[minIndex] < SMALL)
|
||||
{
|
||||
WarningIn(args.executable()) << "Minimum triangle quality is "
|
||||
<< triQ[minIndex] << ". This might give problems in"
|
||||
<< " self-intersection testing later on." << endl;
|
||||
}
|
||||
|
||||
// Dump for subsetting
|
||||
{
|
||||
DynamicList<label> problemFaces(surf.size()/100+1);
|
||||
|
||||
forAll(triQ, faceI)
|
||||
{
|
||||
if (triQ[faceI] < 1e-11)
|
||||
{
|
||||
problemFaces.append(faceI);
|
||||
}
|
||||
}
|
||||
|
||||
if (!problemFaces.empty())
|
||||
{
|
||||
OFstream str("badFaces");
|
||||
|
||||
Info<< "Dumping bad quality faces to " << str.name() << endl
|
||||
<< "Paste this into the input for surfaceSubset" << nl
|
||||
<< nl << endl;
|
||||
|
||||
str << problemFaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Edges
|
||||
// ~~~~~
|
||||
{
|
||||
const edgeList& edges = surf.edges();
|
||||
const pointField& localPoints = surf.localPoints();
|
||||
|
||||
scalarField edgeMag(edges.size());
|
||||
|
||||
forAll(edges, edgeI)
|
||||
{
|
||||
edgeMag[edgeI] = edges[edgeI].mag(localPoints);
|
||||
}
|
||||
|
||||
label minEdgeI = findMin(edgeMag);
|
||||
label maxEdgeI = findMax(edgeMag);
|
||||
|
||||
const edge& minE = edges[minEdgeI];
|
||||
const edge& maxE = edges[maxEdgeI];
|
||||
|
||||
|
||||
Info<< "Edges:" << nl
|
||||
<< " min " << edgeMag[minEdgeI] << " for edge " << minEdgeI
|
||||
<< " points " << localPoints[minE[0]] << localPoints[minE[1]]
|
||||
<< nl
|
||||
<< " max " << edgeMag[maxEdgeI] << " for edge " << maxEdgeI
|
||||
<< " points " << localPoints[maxE[0]] << localPoints[maxE[1]]
|
||||
<< nl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Close points
|
||||
// ~~~~~~~~~~~~
|
||||
{
|
||||
const edgeList& edges = surf.edges();
|
||||
const pointField& localPoints = surf.localPoints();
|
||||
|
||||
const boundBox bb(localPoints);
|
||||
scalar smallDim = 1e-6 * bb.mag();
|
||||
|
||||
Info<< "Checking for points less than 1e-6 of bounding box ("
|
||||
<< bb.span() << " metre) apart."
|
||||
<< endl;
|
||||
|
||||
// Sort points
|
||||
SortableList<scalar> sortedMag(mag(localPoints));
|
||||
|
||||
label nClose = 0;
|
||||
|
||||
for (label i = 1; i < sortedMag.size(); i++)
|
||||
{
|
||||
label ptI = sortedMag.indices()[i];
|
||||
|
||||
label prevPtI = sortedMag.indices()[i-1];
|
||||
|
||||
if (mag(localPoints[ptI] - localPoints[prevPtI]) < smallDim)
|
||||
{
|
||||
// Check if neighbours.
|
||||
const labelList& pEdges = surf.pointEdges()[ptI];
|
||||
|
||||
label edgeI = -1;
|
||||
|
||||
forAll(pEdges, i)
|
||||
{
|
||||
const edge& e = edges[pEdges[i]];
|
||||
|
||||
if (e[0] == prevPtI || e[1] == prevPtI)
|
||||
{
|
||||
// point1 and point0 are connected through edge.
|
||||
edgeI = pEdges[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nClose++;
|
||||
|
||||
if (edgeI == -1)
|
||||
{
|
||||
Info<< " close unconnected points "
|
||||
<< ptI << ' ' << localPoints[ptI]
|
||||
<< " and " << prevPtI << ' '
|
||||
<< localPoints[prevPtI]
|
||||
<< " distance:"
|
||||
<< mag(localPoints[ptI] - localPoints[prevPtI])
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< " small edge between points "
|
||||
<< ptI << ' ' << localPoints[ptI]
|
||||
<< " and " << prevPtI << ' '
|
||||
<< localPoints[prevPtI]
|
||||
<< " distance:"
|
||||
<< mag(localPoints[ptI] - localPoints[prevPtI])
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "Found " << nClose << " nearby points." << nl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check manifold
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
DynamicList<label> problemFaces(surf.size()/100 + 1);
|
||||
|
||||
const labelListList& eFaces = surf.edgeFaces();
|
||||
|
||||
label nSingleEdges = 0;
|
||||
forAll(eFaces, edgeI)
|
||||
{
|
||||
const labelList& myFaces = eFaces[edgeI];
|
||||
|
||||
if (myFaces.size() == 1)
|
||||
{
|
||||
problemFaces.append(myFaces[0]);
|
||||
|
||||
nSingleEdges++;
|
||||
}
|
||||
}
|
||||
|
||||
label nMultEdges = 0;
|
||||
forAll(eFaces, edgeI)
|
||||
{
|
||||
const labelList& myFaces = eFaces[edgeI];
|
||||
|
||||
if (myFaces.size() > 2)
|
||||
{
|
||||
forAll(myFaces, myFaceI)
|
||||
{
|
||||
problemFaces.append(myFaces[myFaceI]);
|
||||
}
|
||||
|
||||
nMultEdges++;
|
||||
}
|
||||
}
|
||||
problemFaces.shrink();
|
||||
|
||||
if ((nSingleEdges != 0) || (nMultEdges != 0))
|
||||
{
|
||||
Info<< "Surface is not closed since not all edges connected to "
|
||||
<< "two faces:" << endl
|
||||
<< " connected to one face : " << nSingleEdges << endl
|
||||
<< " connected to >2 faces : " << nMultEdges << endl;
|
||||
|
||||
Info<< "Conflicting face labels:" << problemFaces.size() << endl;
|
||||
|
||||
OFstream str("problemFaces");
|
||||
|
||||
Info<< "Dumping conflicting face labels to " << str.name() << endl
|
||||
<< "Paste this into the input for surfaceSubset" << endl;
|
||||
|
||||
str << problemFaces;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Surface is closed. All edges connected to two faces." << endl;
|
||||
}
|
||||
Info<< endl;
|
||||
|
||||
|
||||
|
||||
// Check singly connected domain
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
{
|
||||
boolList borderEdge(surf.nEdges(), false);
|
||||
if (splitNonManifold)
|
||||
{
|
||||
const labelListList& eFaces = surf.edgeFaces();
|
||||
forAll(eFaces, edgeI)
|
||||
{
|
||||
if (eFaces[edgeI].size() > 2)
|
||||
{
|
||||
borderEdge[edgeI] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
labelList faceZone;
|
||||
label numZones = surf.markZones(borderEdge, faceZone);
|
||||
|
||||
Info<< "Number of unconnected parts : " << numZones << endl;
|
||||
|
||||
if (numZones > 1)
|
||||
{
|
||||
Info<< "Splitting surface into parts ..." << endl << endl;
|
||||
|
||||
fileName surfFileNameBase(surfFileName.name());
|
||||
const word fileType = surfFileNameBase.ext();
|
||||
// Strip extension
|
||||
surfFileNameBase = surfFileNameBase.lessExt();
|
||||
// If extension was .gz strip original extension
|
||||
if (fileType == "gz")
|
||||
{
|
||||
surfFileNameBase = surfFileNameBase.lessExt();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Info<< "Writing zoning to "
|
||||
<< fileName
|
||||
(
|
||||
"zone_"
|
||||
+ surfFileNameBase
|
||||
+ '.'
|
||||
+ vtkSurfaceWriter::typeName
|
||||
)
|
||||
<< "..." << endl << endl;
|
||||
|
||||
// Convert data
|
||||
scalarField scalarFaceZone(faceZone.size());
|
||||
forAll(faceZone, i)
|
||||
{
|
||||
scalarFaceZone[i] = faceZone[i];
|
||||
}
|
||||
faceList faces(surf.size());
|
||||
forAll(surf, i)
|
||||
{
|
||||
faces[i] = surf[i].triFaceFace();
|
||||
}
|
||||
|
||||
vtkSurfaceWriter().write
|
||||
(
|
||||
surfFileName.path(),
|
||||
surfFileNameBase,
|
||||
surf.points(),
|
||||
faces,
|
||||
"zone",
|
||||
scalarFaceZone,
|
||||
false // face based data
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
for (label zone = 0; zone < numZones; zone++)
|
||||
{
|
||||
boolList includeMap(surf.size(), false);
|
||||
|
||||
forAll(faceZone, faceI)
|
||||
{
|
||||
if (faceZone[faceI] == zone)
|
||||
{
|
||||
includeMap[faceI] = true;
|
||||
}
|
||||
}
|
||||
|
||||
labelList pointMap;
|
||||
labelList faceMap;
|
||||
|
||||
triSurface subSurf
|
||||
(
|
||||
surf.subsetMesh
|
||||
(
|
||||
includeMap,
|
||||
pointMap,
|
||||
faceMap
|
||||
)
|
||||
);
|
||||
|
||||
fileName subName(surfFileNameBase + "_" + name(zone) + ".obj");
|
||||
|
||||
Info<< "writing part " << zone << " size " << subSurf.size()
|
||||
<< " to " << subName << endl;
|
||||
|
||||
subSurf.write(subName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check orientation
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
|
||||
labelHashSet borderEdge(surf.size()/1000);
|
||||
PatchTools::checkOrientation(surf, false, &borderEdge);
|
||||
|
||||
//
|
||||
// Colour all faces into zones using borderEdge
|
||||
//
|
||||
labelList normalZone;
|
||||
label numNormalZones = PatchTools::markZones(surf, borderEdge, normalZone);
|
||||
|
||||
Info<< endl
|
||||
<< "Number of zones (connected area with consistent normal) : "
|
||||
<< numNormalZones << endl;
|
||||
|
||||
if (numNormalZones > 1)
|
||||
{
|
||||
Info<< "More than one normal orientation." << endl;
|
||||
}
|
||||
Info<< endl;
|
||||
|
||||
|
||||
|
||||
// Check self-intersection
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
if (checkSelfIntersect)
|
||||
{
|
||||
Info<< "Checking self-intersection." << endl;
|
||||
|
||||
triSurfaceSearch querySurf(surf);
|
||||
|
||||
const indexedOctree<treeDataTriSurface>& tree = querySurf.tree();
|
||||
|
||||
OBJstream intStream("selfInterPoints.obj");
|
||||
|
||||
label nInt = 0;
|
||||
|
||||
forAll(surf.edges(), edgeI)
|
||||
{
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
pointIndexHit hitInfo
|
||||
(
|
||||
tree.findLine
|
||||
(
|
||||
surf.points()[surf.meshPoints()[e[0]]],
|
||||
surf.points()[surf.meshPoints()[e[1]]],
|
||||
treeDataTriSurface::findSelfIntersectOp
|
||||
(
|
||||
tree,
|
||||
edgeI
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (hitInfo.hit())
|
||||
{
|
||||
intStream.write(hitInfo.hitPoint());
|
||||
nInt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nInt == 0)
|
||||
{
|
||||
Info<< "Surface is not self-intersecting" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Surface is self-intersecting at " << nInt
|
||||
<< " locations." << endl;
|
||||
Info<< "Writing intersection points to " << intStream.name()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
//surfaceIntersection inter(querySurf);
|
||||
//
|
||||
//if (inter.cutEdges().empty() && inter.cutPoints().empty())
|
||||
//{
|
||||
// Info<< "Surface is not self-intersecting" << endl;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Info<< "Surface is self-intersecting" << endl;
|
||||
// Info<< "Writing edges of intersection to selfInter.obj" << endl;
|
||||
//
|
||||
// OFstream intStream("selfInter.obj");
|
||||
// forAll(inter.cutPoints(), cutPointI)
|
||||
// {
|
||||
// const point& pt = inter.cutPoints()[cutPointI];
|
||||
//
|
||||
// intStream << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z()
|
||||
// << endl;
|
||||
// }
|
||||
// forAll(inter.cutEdges(), cutEdgeI)
|
||||
// {
|
||||
// const edge& e = inter.cutEdges()[cutEdgeI];
|
||||
//
|
||||
// intStream << "l " << e.start()+1 << ' ' << e.end()+1 << endl;
|
||||
// }
|
||||
//}
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
6
applications/utilities/surface/surfaceClean/Make/files
Normal file
6
applications/utilities/surface/surfaceClean/Make/files
Normal file
@ -0,0 +1,6 @@
|
||||
collapseBase.C
|
||||
collapseEdge.C
|
||||
|
||||
surfaceClean.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceClean
|
||||
7
applications/utilities/surface/surfaceClean/Make/options
Normal file
7
applications/utilities/surface/surfaceClean/Make/options
Normal file
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
994
applications/utilities/surface/surfaceClean/collapseBase.C
Normal file
994
applications/utilities/surface/surfaceClean/collapseBase.C
Normal file
@ -0,0 +1,994 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2012 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/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "collapseBase.H"
|
||||
#include "triSurfaceTools.H"
|
||||
#include "argList.H"
|
||||
#include "OFstream.H"
|
||||
#include "SubList.H"
|
||||
#include "labelPair.H"
|
||||
#include "meshTools.H"
|
||||
#include "OSspecific.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
//// Dump collapse region to .obj file
|
||||
//static void writeRegionOBJ
|
||||
//(
|
||||
// const triSurface& surf,
|
||||
// const label regionI,
|
||||
// const labelList& collapseRegion,
|
||||
// const labelList& outsideVerts
|
||||
//)
|
||||
//{
|
||||
// fileName dir("regions");
|
||||
//
|
||||
// mkDir(dir);
|
||||
// fileName regionName(dir / "region_" + name(regionI) + ".obj");
|
||||
//
|
||||
// Pout<< "Dumping region " << regionI << " to file " << regionName << endl;
|
||||
//
|
||||
// boolList include(surf.size(), false);
|
||||
//
|
||||
// forAll(collapseRegion, faceI)
|
||||
// {
|
||||
// if (collapseRegion[faceI] == regionI)
|
||||
// {
|
||||
// include[faceI] = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// labelList pointMap, faceMap;
|
||||
//
|
||||
// triSurface regionSurf(surf.subsetMesh(include, pointMap, faceMap));
|
||||
//
|
||||
// Pout<< "Region " << regionI << " surface:" << nl;
|
||||
// regionSurf.writeStats(Pout);
|
||||
//
|
||||
// regionSurf.write(regionName);
|
||||
//
|
||||
//
|
||||
// // Dump corresponding outside vertices.
|
||||
// fileName pointsName(dir / "regionPoints_" + name(regionI) + ".obj");
|
||||
//
|
||||
// Pout<< "Dumping region " << regionI << " points to file " << pointsName
|
||||
// << endl;
|
||||
//
|
||||
// OFstream str(pointsName);
|
||||
//
|
||||
// forAll(outsideVerts, i)
|
||||
// {
|
||||
// meshTools::writeOBJ(str, surf.localPoints()[outsideVerts[i]]);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
// Split triangle into multiple triangles because edge e being split
|
||||
// into multiple edges.
|
||||
static void splitTri
|
||||
(
|
||||
const labelledTri& f,
|
||||
const edge& e,
|
||||
const labelList& splitPoints,
|
||||
DynamicList<labelledTri>& tris
|
||||
)
|
||||
{
|
||||
//label oldNTris = tris.size();
|
||||
|
||||
label fp = findIndex(f, e[0]);
|
||||
label fp1 = f.fcIndex(fp);
|
||||
label fp2 = f.fcIndex(fp1);
|
||||
|
||||
if (f[fp1] == e[1])
|
||||
{
|
||||
// Split triangle along fp to fp1
|
||||
tris.append(labelledTri(f[fp2], f[fp], splitPoints[0], f.region()));
|
||||
|
||||
for (label i = 1; i < splitPoints.size(); i++)
|
||||
{
|
||||
tris.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp2],
|
||||
splitPoints[i-1],
|
||||
splitPoints[i],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
tris.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp2],
|
||||
splitPoints.last(),
|
||||
f[fp1],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (f[fp2] == e[1])
|
||||
{
|
||||
// Split triangle along fp2 to fp. (Reverse order of splitPoints)
|
||||
|
||||
tris.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp1],
|
||||
f[fp2],
|
||||
splitPoints.last(),
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
|
||||
for (label i = splitPoints.size()-1; i > 0; --i)
|
||||
{
|
||||
tris.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp1],
|
||||
splitPoints[i],
|
||||
splitPoints[i-1],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
tris.append
|
||||
(
|
||||
labelledTri
|
||||
(
|
||||
f[fp1],
|
||||
splitPoints[0],
|
||||
f[fp],
|
||||
f.region()
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalErrorIn("splitTri(..)")
|
||||
<< "Edge " << e << " not part of triangle " << f
|
||||
<< " fp:" << fp
|
||||
<< " fp1:" << fp1
|
||||
<< " fp2:" << fp2
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
//Pout<< "Split face " << f << " along edge " << e
|
||||
// << " into triangles:" << endl;
|
||||
//
|
||||
//for (label i = oldNTris; i < tris.size(); i++)
|
||||
//{
|
||||
// Pout<< " " << tris[i] << nl;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
// Insert scalar into sortedVerts/sortedWeights so the weights are in
|
||||
// incrementing order.
|
||||
static bool insertSorted
|
||||
(
|
||||
const label vertI,
|
||||
const scalar weight,
|
||||
|
||||
labelList& sortedVerts,
|
||||
scalarField& sortedWeights
|
||||
)
|
||||
{
|
||||
if (findIndex(sortedVerts, vertI) != -1)
|
||||
{
|
||||
FatalErrorIn("insertSorted(..)") << "Trying to insert vertex " << vertI
|
||||
<< " which is already in list of sorted vertices "
|
||||
<< sortedVerts << abort(FatalError);
|
||||
}
|
||||
|
||||
if (weight <= 0 || weight >= 1)
|
||||
{
|
||||
FatalErrorIn("insertSorted(..)") << "Trying to insert vertex " << vertI
|
||||
<< " with illegal weight " << weight
|
||||
<< " into list of sorted vertices "
|
||||
<< sortedVerts << abort(FatalError);
|
||||
}
|
||||
|
||||
|
||||
label insertI = sortedVerts.size();
|
||||
|
||||
forAll(sortedVerts, sortedI)
|
||||
{
|
||||
scalar w = sortedWeights[sortedI];
|
||||
|
||||
if (mag(w - weight) < SMALL)
|
||||
{
|
||||
WarningIn("insertSorted(..)")
|
||||
<< "Trying to insert weight " << weight << " which is close to"
|
||||
<< " existing weight " << w << " in " << sortedWeights
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (w > weight)
|
||||
{
|
||||
// Start inserting before sortedI.
|
||||
insertI = sortedI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
label sz = sortedWeights.size();
|
||||
|
||||
sortedWeights.setSize(sz + 1);
|
||||
sortedVerts.setSize(sz + 1);
|
||||
|
||||
// Leave everything up to (not including) insertI intact.
|
||||
|
||||
// Make space by copying from insertI up.
|
||||
for (label i = sz-1; i >= insertI; --i)
|
||||
{
|
||||
sortedWeights[i+1] = sortedWeights[i];
|
||||
sortedVerts[i+1] = sortedVerts[i];
|
||||
}
|
||||
sortedWeights[insertI] = weight;
|
||||
sortedVerts[insertI] = vertI;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Is triangle candidate for collapse? Small height or small quality
|
||||
bool isSliver
|
||||
(
|
||||
const triSurface& surf,
|
||||
const scalar minLen,
|
||||
const scalar minQuality,
|
||||
const label faceI,
|
||||
const label edgeI
|
||||
)
|
||||
{
|
||||
const pointField& localPoints = surf.localPoints();
|
||||
|
||||
// Check
|
||||
// - opposite vertex projects onto base edge
|
||||
// - normal distance is small
|
||||
// - or triangle quality is small
|
||||
|
||||
label opposite0 =
|
||||
triSurfaceTools::oppositeVertex
|
||||
(
|
||||
surf,
|
||||
faceI,
|
||||
edgeI
|
||||
);
|
||||
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
const labelledTri& f = surf[faceI];
|
||||
|
||||
pointHit pHit =
|
||||
e.line(localPoints).nearestDist
|
||||
(
|
||||
localPoints[opposite0]
|
||||
);
|
||||
|
||||
if
|
||||
(
|
||||
pHit.hit()
|
||||
&& (
|
||||
pHit.distance() < minLen
|
||||
|| f.tri(surf.points()).quality() < minQuality
|
||||
)
|
||||
)
|
||||
{
|
||||
// Remove faceI and split all other faces using this
|
||||
// edge. This is done by 'replacing' the edgeI with the
|
||||
// opposite0 vertex
|
||||
//Pout<< "Splitting face " << faceI << " since distance "
|
||||
// << pHit.distance()
|
||||
// << " from vertex " << opposite0
|
||||
// << " to edge " << edgeI
|
||||
// << " points "
|
||||
// << localPoints[e[0]]
|
||||
// << localPoints[e[1]]
|
||||
// << " is too small or triangle quality "
|
||||
// << f.tri(surf.points()).quality()
|
||||
// << " too small." << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mark all faces that are going to be collapsed.
|
||||
// faceToEdge: per face -1 or the base edge of the face.
|
||||
static void markCollapsedFaces
|
||||
(
|
||||
const triSurface& surf,
|
||||
const scalar minLen,
|
||||
const scalar minQuality,
|
||||
labelList& faceToEdge
|
||||
)
|
||||
{
|
||||
faceToEdge.setSize(surf.size());
|
||||
faceToEdge = -1;
|
||||
|
||||
const labelListList& edgeFaces = surf.edgeFaces();
|
||||
|
||||
forAll(edgeFaces, edgeI)
|
||||
{
|
||||
const labelList& eFaces = surf.edgeFaces()[edgeI];
|
||||
|
||||
forAll(eFaces, i)
|
||||
{
|
||||
label faceI = eFaces[i];
|
||||
|
||||
bool isCandidate = isSliver(surf, minLen, minQuality, faceI, edgeI);
|
||||
|
||||
if (isCandidate)
|
||||
{
|
||||
// Mark face as being collapsed
|
||||
if (faceToEdge[faceI] != -1)
|
||||
{
|
||||
FatalErrorIn("markCollapsedFaces(..)")
|
||||
<< "Cannot collapse face " << faceI << " since "
|
||||
<< " is marked to be collapsed both to edge "
|
||||
<< faceToEdge[faceI] << " and " << edgeI
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
faceToEdge[faceI] = edgeI;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Recurse through collapsed faces marking all of them with regionI (in
|
||||
// collapseRegion)
|
||||
static void markRegion
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& faceToEdge,
|
||||
const label regionI,
|
||||
const label faceI,
|
||||
labelList& collapseRegion
|
||||
)
|
||||
{
|
||||
if (faceToEdge[faceI] == -1 || collapseRegion[faceI] != -1)
|
||||
{
|
||||
FatalErrorIn("markRegion(..)")
|
||||
<< "Problem : crossed into uncollapsed/regionized face"
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
collapseRegion[faceI] = regionI;
|
||||
|
||||
// Recurse across edges to collapsed neighbours
|
||||
|
||||
const labelList& fEdges = surf.faceEdges()[faceI];
|
||||
|
||||
forAll(fEdges, fEdgeI)
|
||||
{
|
||||
label edgeI = fEdges[fEdgeI];
|
||||
|
||||
const labelList& eFaces = surf.edgeFaces()[edgeI];
|
||||
|
||||
forAll(eFaces, i)
|
||||
{
|
||||
label nbrFaceI = eFaces[i];
|
||||
|
||||
if (faceToEdge[nbrFaceI] != -1)
|
||||
{
|
||||
if (collapseRegion[nbrFaceI] == -1)
|
||||
{
|
||||
markRegion
|
||||
(
|
||||
surf,
|
||||
faceToEdge,
|
||||
regionI,
|
||||
nbrFaceI,
|
||||
collapseRegion
|
||||
);
|
||||
}
|
||||
else if (collapseRegion[nbrFaceI] != regionI)
|
||||
{
|
||||
FatalErrorIn("markRegion(..)")
|
||||
<< "Edge:" << edgeI << " between face " << faceI
|
||||
<< " with region " << regionI
|
||||
<< " and face " << nbrFaceI
|
||||
<< " with region " << collapseRegion[nbrFaceI]
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mark every face with region (in collapseRegion) (or -1).
|
||||
// Return number of regions.
|
||||
static label markRegions
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& faceToEdge,
|
||||
labelList& collapseRegion
|
||||
)
|
||||
{
|
||||
label regionI = 0;
|
||||
|
||||
forAll(faceToEdge, faceI)
|
||||
{
|
||||
if (collapseRegion[faceI] == -1 && faceToEdge[faceI] != -1)
|
||||
{
|
||||
//Pout<< "markRegions : Marking region:" << regionI
|
||||
// << " starting from face " << faceI << endl;
|
||||
|
||||
// Collapsed face. Mark connected region with current region number
|
||||
markRegion(surf, faceToEdge, regionI++, faceI, collapseRegion);
|
||||
}
|
||||
}
|
||||
return regionI;
|
||||
}
|
||||
|
||||
|
||||
// Type of region.
|
||||
// -1 : edge inbetween uncollapsed faces.
|
||||
// -2 : edge inbetween collapsed faces
|
||||
// >=0 : edge inbetween uncollapsed and collapsed region. Returns region.
|
||||
static label edgeType
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& collapseRegion,
|
||||
const label edgeI
|
||||
)
|
||||
{
|
||||
const labelList& eFaces = surf.edgeFaces()[edgeI];
|
||||
|
||||
// Detect if edge is inbetween collapseRegion and non-collapse face
|
||||
bool usesUncollapsed = false;
|
||||
label usesRegion = -1;
|
||||
|
||||
forAll(eFaces, i)
|
||||
{
|
||||
label faceI = eFaces[i];
|
||||
|
||||
label region = collapseRegion[faceI];
|
||||
|
||||
if (region == -1)
|
||||
{
|
||||
usesUncollapsed = true;
|
||||
}
|
||||
else if (usesRegion == -1)
|
||||
{
|
||||
usesRegion = region;
|
||||
}
|
||||
else if (usesRegion != region)
|
||||
{
|
||||
FatalErrorIn("edgeRegion") << abort(FatalError);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Equal regions.
|
||||
}
|
||||
}
|
||||
|
||||
if (usesUncollapsed)
|
||||
{
|
||||
if (usesRegion == -1)
|
||||
{
|
||||
// uncollapsed faces only.
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// between uncollapsed and collapsed.
|
||||
return usesRegion;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (usesRegion == -1)
|
||||
{
|
||||
FatalErrorIn("edgeRegion") << abort(FatalError);
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get points on outside edge of region (= outside points)
|
||||
static labelListList getOutsideVerts
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& collapseRegion,
|
||||
const label nRegions
|
||||
)
|
||||
{
|
||||
const labelListList& edgeFaces = surf.edgeFaces();
|
||||
|
||||
// Per region all the outside vertices.
|
||||
labelListList outsideVerts(nRegions);
|
||||
|
||||
forAll(edgeFaces, edgeI)
|
||||
{
|
||||
// Detect if edge is inbetween collapseRegion and non-collapse face
|
||||
label regionI = edgeType(surf, collapseRegion, edgeI);
|
||||
|
||||
if (regionI >= 0)
|
||||
{
|
||||
// Edge borders both uncollapsed face and collapsed face on region
|
||||
// usesRegion.
|
||||
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
labelList& regionVerts = outsideVerts[regionI];
|
||||
|
||||
// Add both edge points to regionVerts.
|
||||
forAll(e, eI)
|
||||
{
|
||||
label v = e[eI];
|
||||
|
||||
if (findIndex(regionVerts, v) == -1)
|
||||
{
|
||||
label sz = regionVerts.size();
|
||||
regionVerts.setSize(sz+1);
|
||||
regionVerts[sz] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outsideVerts;
|
||||
}
|
||||
|
||||
|
||||
// n^2 search for furthest removed point pair.
|
||||
static labelPair getSpanPoints
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& outsideVerts
|
||||
)
|
||||
{
|
||||
const pointField& localPoints = surf.localPoints();
|
||||
|
||||
scalar maxDist = -GREAT;
|
||||
labelPair maxPair;
|
||||
|
||||
forAll(outsideVerts, i)
|
||||
{
|
||||
label v0 = outsideVerts[i];
|
||||
|
||||
for (label j = i+1; j < outsideVerts.size(); j++)
|
||||
{
|
||||
label v1 = outsideVerts[j];
|
||||
|
||||
scalar d = mag(localPoints[v0] - localPoints[v1]);
|
||||
|
||||
if (d > maxDist)
|
||||
{
|
||||
maxDist = d;
|
||||
maxPair[0] = v0;
|
||||
maxPair[1] = v1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxPair;
|
||||
}
|
||||
|
||||
|
||||
// Project all non-span points onto the span edge.
|
||||
static void projectNonSpanPoints
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& outsideVerts,
|
||||
const labelPair& spanPair,
|
||||
labelList& sortedVertices,
|
||||
scalarField& sortedWeights
|
||||
)
|
||||
{
|
||||
const point& p0 = surf.localPoints()[spanPair[0]];
|
||||
const point& p1 = surf.localPoints()[spanPair[1]];
|
||||
|
||||
forAll(outsideVerts, i)
|
||||
{
|
||||
label v = outsideVerts[i];
|
||||
|
||||
if (v != spanPair[0] && v != spanPair[1])
|
||||
{
|
||||
// Is a non-span point. Project onto spanning edge.
|
||||
|
||||
pointHit pHit =
|
||||
linePointRef(p0, p1).nearestDist
|
||||
(
|
||||
surf.localPoints()[v]
|
||||
);
|
||||
|
||||
if (!pHit.hit())
|
||||
{
|
||||
FatalErrorIn("projectNonSpanPoints")
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
scalar w = mag(pHit.hitPoint() - p0) / mag(p1 - p0);
|
||||
|
||||
insertSorted(v, w, sortedVertices, sortedWeights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Slice part of the orderVertices (and optionally reverse) for this edge.
|
||||
static void getSplitVerts
|
||||
(
|
||||
const triSurface& surf,
|
||||
const label regionI,
|
||||
const labelPair& spanPoints,
|
||||
const labelList& orderedVerts,
|
||||
const scalarField& orderedWeights,
|
||||
const label edgeI,
|
||||
|
||||
labelList& splitVerts,
|
||||
scalarField& splitWeights
|
||||
)
|
||||
{
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
const label sz = orderedVerts.size();
|
||||
|
||||
if (e[0] == spanPoints[0])
|
||||
{
|
||||
// Edge in same order as spanPoints&orderedVerts. Keep order.
|
||||
|
||||
if (e[1] == spanPoints[1])
|
||||
{
|
||||
// Copy all.
|
||||
splitVerts = orderedVerts;
|
||||
splitWeights = orderedWeights;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy upto (but not including) e[1]
|
||||
label i1 = findIndex(orderedVerts, e[1]);
|
||||
splitVerts = SubList<label>(orderedVerts, i1, 0);
|
||||
splitWeights = SubList<scalar>(orderedWeights, i1, 0);
|
||||
}
|
||||
}
|
||||
else if (e[0] == spanPoints[1])
|
||||
{
|
||||
// Reverse.
|
||||
|
||||
if (e[1] == spanPoints[0])
|
||||
{
|
||||
// Copy all.
|
||||
splitVerts = orderedVerts;
|
||||
reverse(splitVerts);
|
||||
splitWeights = orderedWeights;
|
||||
reverse(splitWeights);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy downto (but not including) e[1]
|
||||
|
||||
label i1 = findIndex(orderedVerts, e[1]);
|
||||
splitVerts = SubList<label>(orderedVerts, sz-(i1+1), i1+1);
|
||||
reverse(splitVerts);
|
||||
splitWeights = SubList<scalar>(orderedWeights, sz-(i1+1), i1+1);
|
||||
reverse(splitWeights);
|
||||
}
|
||||
}
|
||||
else if (e[1] == spanPoints[0])
|
||||
{
|
||||
// Reverse.
|
||||
|
||||
// Copy upto (but not including) e[0]
|
||||
|
||||
label i0 = findIndex(orderedVerts, e[0]);
|
||||
splitVerts = SubList<label>(orderedVerts, i0, 0);
|
||||
reverse(splitVerts);
|
||||
splitWeights = SubList<scalar>(orderedWeights, i0, 0);
|
||||
reverse(splitWeights);
|
||||
}
|
||||
else if (e[1] == spanPoints[1])
|
||||
{
|
||||
// Copy from (but not including) e[0] to end
|
||||
|
||||
label i0 = findIndex(orderedVerts, e[0]);
|
||||
splitVerts = SubList<label>(orderedVerts, sz-(i0+1), i0+1);
|
||||
splitWeights = SubList<scalar>(orderedWeights, sz-(i0+1), i0+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
label i0 = findIndex(orderedVerts, e[0]);
|
||||
label i1 = findIndex(orderedVerts, e[1]);
|
||||
|
||||
if (i0 == -1 || i1 == -1)
|
||||
{
|
||||
FatalErrorIn("getSplitVerts")
|
||||
<< "Did not find edge in projected vertices." << nl
|
||||
<< "region:" << regionI << nl
|
||||
<< "spanPoints:" << spanPoints
|
||||
<< " coords:" << surf.localPoints()[spanPoints[0]]
|
||||
<< surf.localPoints()[spanPoints[1]] << nl
|
||||
<< "edge:" << edgeI
|
||||
<< " verts:" << e
|
||||
<< " coords:" << surf.localPoints()[e[0]]
|
||||
<< surf.localPoints()[e[1]] << nl
|
||||
<< "orderedVerts:" << orderedVerts << nl
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
if (i0 < i1)
|
||||
{
|
||||
splitVerts = SubList<label>(orderedVerts, i1-i0-1, i0+1);
|
||||
splitWeights = SubList<scalar>(orderedWeights, i1-i0-1, i0+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
splitVerts = SubList<label>(orderedVerts, i0-i1-1, i1+1);
|
||||
reverse(splitVerts);
|
||||
splitWeights = SubList<scalar>(orderedWeights, i0-i1-1, i1+1);
|
||||
reverse(splitWeights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
label collapseBase
|
||||
(
|
||||
triSurface& surf,
|
||||
const scalar minLen,
|
||||
const scalar minQuality
|
||||
)
|
||||
{
|
||||
label nTotalSplit = 0;
|
||||
|
||||
label iter = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Detect faces to collapse
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// -1 or edge the face is collapsed onto.
|
||||
labelList faceToEdge(surf.size(), -1);
|
||||
|
||||
// Calculate faceToEdge (face collapses)
|
||||
markCollapsedFaces(surf, minLen, minQuality, faceToEdge);
|
||||
|
||||
|
||||
// Find regions of connected collapsed faces
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// per face -1 or region
|
||||
labelList collapseRegion(surf.size(), -1);
|
||||
|
||||
label nRegions = markRegions(surf, faceToEdge, collapseRegion);
|
||||
|
||||
//Pout<< "Detected " << nRegions << " regions of faces to be collapsed"
|
||||
// << nl << endl;
|
||||
|
||||
// Pick up all vertices on outside of region
|
||||
labelListList outsideVerts
|
||||
(
|
||||
getOutsideVerts(surf, collapseRegion, nRegions)
|
||||
);
|
||||
|
||||
// For all regions determine maximum distance between points
|
||||
List<labelPair> spanPoints(nRegions);
|
||||
labelListList orderedVertices(nRegions);
|
||||
List<scalarField> orderedWeights(nRegions);
|
||||
|
||||
forAll(spanPoints, regionI)
|
||||
{
|
||||
spanPoints[regionI] = getSpanPoints(surf, outsideVerts[regionI]);
|
||||
|
||||
//Pout<< "For region " << regionI << " found extrema at points "
|
||||
// << surf.localPoints()[spanPoints[regionI][0]]
|
||||
// << surf.localPoints()[spanPoints[regionI][1]]
|
||||
// << endl;
|
||||
|
||||
// Project all non-span points onto the span edge.
|
||||
projectNonSpanPoints
|
||||
(
|
||||
surf,
|
||||
outsideVerts[regionI],
|
||||
spanPoints[regionI],
|
||||
orderedVertices[regionI],
|
||||
orderedWeights[regionI]
|
||||
);
|
||||
|
||||
//Pout<< "For region:" << regionI
|
||||
// << " span:" << spanPoints[regionI]
|
||||
// << " orderedVerts:" << orderedVertices[regionI]
|
||||
// << " orderedWeights:" << orderedWeights[regionI]
|
||||
// << endl;
|
||||
|
||||
//writeRegionOBJ
|
||||
//(
|
||||
// surf,
|
||||
// regionI,
|
||||
// collapseRegion,
|
||||
// outsideVerts[regionI]
|
||||
//);
|
||||
|
||||
//Pout<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Actually split the edges
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
const List<labelledTri>& localFaces = surf.localFaces();
|
||||
const edgeList& edges = surf.edges();
|
||||
|
||||
label nSplit = 0;
|
||||
|
||||
// Storage for new triangles.
|
||||
DynamicList<labelledTri> newTris(surf.size());
|
||||
|
||||
// Whether face has been dealt with (either copied/split or deleted)
|
||||
boolList faceHandled(surf.size(), false);
|
||||
|
||||
|
||||
forAll(edges, edgeI)
|
||||
{
|
||||
const edge& e = edges[edgeI];
|
||||
|
||||
// Detect if edge is inbetween collapseRegion and non-collapse face
|
||||
label regionI = edgeType(surf, collapseRegion, edgeI);
|
||||
|
||||
if (regionI == -2)
|
||||
{
|
||||
// inbetween collapsed faces. nothing needs to be done.
|
||||
}
|
||||
else if (regionI == -1)
|
||||
{
|
||||
// edge inbetween uncollapsed faces. Handle these later on.
|
||||
}
|
||||
else
|
||||
{
|
||||
// some faces around edge are collapsed.
|
||||
|
||||
// Find additional set of points on edge to be used to split
|
||||
// the remaining faces.
|
||||
|
||||
labelList splitVerts;
|
||||
scalarField splitWeights;
|
||||
getSplitVerts
|
||||
(
|
||||
surf,
|
||||
regionI,
|
||||
spanPoints[regionI],
|
||||
orderedVertices[regionI],
|
||||
orderedWeights[regionI],
|
||||
edgeI,
|
||||
|
||||
splitVerts,
|
||||
splitWeights
|
||||
);
|
||||
|
||||
if (splitVerts.size())
|
||||
{
|
||||
// Split edge using splitVerts. All non-collapsed triangles
|
||||
// using edge will get split.
|
||||
|
||||
//{
|
||||
// const pointField& localPoints = surf.localPoints();
|
||||
// Pout<< "edge " << edgeI << ' ' << e
|
||||
// << " points "
|
||||
// << localPoints[e[0]] << ' ' << localPoints[e[1]]
|
||||
// << " split into edges with extra points:"
|
||||
// << endl;
|
||||
// forAll(splitVerts, i)
|
||||
// {
|
||||
// Pout<< " " << splitVerts[i] << " weight "
|
||||
// << splitWeights[i] << nl;
|
||||
// }
|
||||
//}
|
||||
|
||||
const labelList& eFaces = surf.edgeFaces()[edgeI];
|
||||
|
||||
forAll(eFaces, i)
|
||||
{
|
||||
label faceI = eFaces[i];
|
||||
|
||||
if (!faceHandled[faceI] && faceToEdge[faceI] == -1)
|
||||
{
|
||||
// Split face to use vertices.
|
||||
splitTri
|
||||
(
|
||||
localFaces[faceI],
|
||||
e,
|
||||
splitVerts,
|
||||
newTris
|
||||
);
|
||||
|
||||
faceHandled[faceI] = true;
|
||||
|
||||
nSplit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all unsplit faces
|
||||
forAll(faceHandled, faceI)
|
||||
{
|
||||
if (!faceHandled[faceI] && faceToEdge[faceI] == -1)
|
||||
{
|
||||
newTris.append(localFaces[faceI]);
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "collapseBase : collapsing " << nSplit
|
||||
<< " triangles by splitting their base edge."
|
||||
<< endl;
|
||||
|
||||
nTotalSplit += nSplit;
|
||||
|
||||
if (nSplit == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Pack the triangles
|
||||
newTris.shrink();
|
||||
|
||||
//Pout<< "Resetting surface from " << surf.size() << " to "
|
||||
// << newTris.size() << " triangles" << endl;
|
||||
surf = triSurface(newTris, surf.patches(), surf.localPoints());
|
||||
|
||||
//{
|
||||
// fileName fName("bla" + name(iter) + ".obj");
|
||||
// Pout<< "Writing surf to " << fName << endl;
|
||||
// surf.write(fName);
|
||||
//}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
// Remove any unused vertices
|
||||
surf = triSurface(surf.localFaces(), surf.patches(), surf.localPoints());
|
||||
|
||||
return nTotalSplit;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
58
applications/utilities/surface/surfaceClean/collapseBase.H
Normal file
58
applications/utilities/surface/surfaceClean/collapseBase.H
Normal file
@ -0,0 +1,58 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011 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/>.
|
||||
|
||||
InClass
|
||||
Foam::collapseBase
|
||||
|
||||
Description
|
||||
Routines collapse sliver triangles by splitting the base edge.
|
||||
|
||||
SourceFiles
|
||||
collapseBase.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef collapseBase_H
|
||||
#define collapseBase_H
|
||||
|
||||
#include "triSurface.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
//- Keep collapsing all triangles whose height is < minLen or quality < minQ.
|
||||
// Returns number of triangles collapsed.
|
||||
label collapseBase
|
||||
(
|
||||
triSurface& surf,
|
||||
const scalar minLen,
|
||||
const scalar minQuality
|
||||
);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
161
applications/utilities/surface/surfaceClean/collapseEdge.C
Normal file
161
applications/utilities/surface/surfaceClean/collapseEdge.C
Normal file
@ -0,0 +1,161 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011 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/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "collapseEdge.H"
|
||||
|
||||
//- Sets point neighbours of face to val
|
||||
static void markPointNbrs
|
||||
(
|
||||
const triSurface& surf,
|
||||
const label faceI,
|
||||
const bool val,
|
||||
boolList& okToCollapse
|
||||
)
|
||||
{
|
||||
const triSurface::FaceType& f = surf.localFaces()[faceI];
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
const labelList& pFaces = surf.pointFaces()[f[fp]];
|
||||
|
||||
forAll(pFaces, i)
|
||||
{
|
||||
okToCollapse[pFaces[i]] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static triSurface pack
|
||||
(
|
||||
const triSurface& surf,
|
||||
const pointField& localPoints,
|
||||
const labelList& pointMap
|
||||
)
|
||||
{
|
||||
List<labelledTri> newTriangles(surf.size());
|
||||
label newTriangleI = 0;
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
const labelledTri& f = surf.localFaces()[faceI];
|
||||
|
||||
label newA = pointMap[f[0]];
|
||||
label newB = pointMap[f[1]];
|
||||
label newC = pointMap[f[2]];
|
||||
|
||||
if ((newA != newB) && (newA != newC) && (newB != newC))
|
||||
{
|
||||
newTriangles[newTriangleI++] =
|
||||
labelledTri(newA, newB, newC, f.region());
|
||||
}
|
||||
}
|
||||
newTriangles.setSize(newTriangleI);
|
||||
|
||||
return triSurface(newTriangles, surf.patches(), localPoints);
|
||||
}
|
||||
|
||||
|
||||
// Collapses small edge to point, thus removing triangle.
|
||||
label collapseEdge(triSurface& surf, const scalar minLen)
|
||||
{
|
||||
label nTotalCollapsed = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const pointField& localPoints = surf.localPoints();
|
||||
const List<labelledTri>& localFaces = surf.localFaces();
|
||||
|
||||
|
||||
// Mapping from old to new points
|
||||
labelList pointMap(surf.nPoints());
|
||||
forAll(pointMap, i)
|
||||
{
|
||||
pointMap[i] = i;
|
||||
}
|
||||
|
||||
// Storage for new points.
|
||||
pointField newPoints(localPoints);
|
||||
|
||||
// To protect neighbours of collapsed faces.
|
||||
boolList okToCollapse(surf.size(), true);
|
||||
label nCollapsed = 0;
|
||||
|
||||
forAll(localFaces, faceI)
|
||||
{
|
||||
if (okToCollapse[faceI])
|
||||
{
|
||||
// Check edge lengths.
|
||||
const triSurface::FaceType& f = localFaces[faceI];
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
label v = f[fp];
|
||||
label v1 = f[f.fcIndex(fp)];
|
||||
|
||||
if (mag(localPoints[v1] - localPoints[v]) < minLen)
|
||||
{
|
||||
// Collapse f[fp1] onto f[fp].
|
||||
pointMap[v1] = v;
|
||||
newPoints[v] = 0.5*(localPoints[v1] + localPoints[v]);
|
||||
|
||||
//Pout<< "Collapsing triange " << faceI
|
||||
// << " to edge mid " << newPoints[v] << endl;
|
||||
|
||||
nCollapsed++;
|
||||
okToCollapse[faceI] = false;
|
||||
|
||||
// Protect point neighbours from collapsing.
|
||||
markPointNbrs(surf, faceI, false, okToCollapse);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "collapseEdge : collapsing " << nCollapsed
|
||||
<< " triangles to a single edge."
|
||||
<< endl;
|
||||
|
||||
nTotalCollapsed += nCollapsed;
|
||||
|
||||
if (nCollapsed == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Pack the triangles
|
||||
surf = pack(surf, newPoints, pointMap);
|
||||
}
|
||||
|
||||
// Remove any unused vertices
|
||||
surf = triSurface(surf.localFaces(), surf.patches(), surf.localPoints());
|
||||
|
||||
return nTotalCollapsed;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
53
applications/utilities/surface/surfaceClean/collapseEdge.H
Normal file
53
applications/utilities/surface/surfaceClean/collapseEdge.H
Normal file
@ -0,0 +1,53 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011 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/>.
|
||||
|
||||
InClass
|
||||
Foam::collapseEdge
|
||||
|
||||
Description
|
||||
Routines to collapse small edges.
|
||||
|
||||
SourceFiles
|
||||
collapseEdge.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef collapseEdge_H
|
||||
#define collapseEdge_H
|
||||
|
||||
#include "triSurface.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
//- Keep collapsing all edges < minLen.
|
||||
// Returns number of triangles collapsed.
|
||||
label collapseEdge(triSurface& surf, const scalar minLen);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
101
applications/utilities/surface/surfaceClean/multiCollapse.stl
Normal file
101
applications/utilities/surface/surfaceClean/multiCollapse.stl
Normal file
@ -0,0 +1,101 @@
|
||||
solid patchEE80EE
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -22 1.19209e-07 0
|
||||
vertex 22 1.19209e-07 0
|
||||
vertex 6.25849e-07 -1 0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid patchEE80EE
|
||||
solid patchFFFF00
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -22 1.19209e-07 0
|
||||
vertex -6.4 1 0
|
||||
vertex 22 1.19209e-07 0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid patchFFFF00
|
||||
solid patch458674
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -22 1.19209e-07 0
|
||||
vertex -8.8 -1.1 0
|
||||
vertex 6.25849e-07 -1 0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid patch458674
|
||||
solid patchFF0000
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -6.4 1 0
|
||||
vertex 11.2 0.9 0
|
||||
vertex 22 1.19209e-07 0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid patchFF0000
|
||||
solid patchFF
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -22 1.19209e-07 0
|
||||
vertex -7.2 17.8 0
|
||||
vertex -6.4 1 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -7.2 17.8 0
|
||||
vertex 11.2 0.9 0
|
||||
vertex -6.4 1 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -7.2 17.8 0
|
||||
vertex 18.7 18.2 0
|
||||
vertex 11.2 0.9 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -0 -1
|
||||
outer loop
|
||||
vertex 18.7 18.2 0
|
||||
vertex 22 1.19209e-07 0
|
||||
vertex 11.2 0.9 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 6.25849e-07 -1 0
|
||||
vertex 11.6 -21.1 0
|
||||
vertex 22 1.19209e-07 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -8.8 -1.1 0
|
||||
vertex -8.4 -20.9 0
|
||||
vertex 11.6 -21.1 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex -8.8 -1.1 0
|
||||
vertex 11.6 -21.1 0
|
||||
vertex 6.25849e-07 -1 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -22 1.19209e-07 0
|
||||
vertex -25 -25.3 0
|
||||
vertex -8.4 -20.9 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -22 1.19209e-07 0
|
||||
vertex -8.4 -20.9 0
|
||||
vertex -8.8 -1.1 0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid patchFF
|
||||
118
applications/utilities/surface/surfaceClean/surfaceClean.C
Normal file
118
applications/utilities/surface/surfaceClean/surfaceClean.C
Normal file
@ -0,0 +1,118 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceClean
|
||||
|
||||
Description
|
||||
- removes baffles
|
||||
- collapses small edges, removing triangles.
|
||||
- converts sliver triangles into split edges by projecting point onto
|
||||
base of triangle.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "triSurface.H"
|
||||
#include "argList.H"
|
||||
#include "OFstream.H"
|
||||
|
||||
#include "collapseBase.H"
|
||||
#include "collapseEdge.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("min length");
|
||||
argList::validArgs.append("min quality");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList::addBoolOption
|
||||
(
|
||||
"noClean",
|
||||
"perform some surface checking/cleanup on the input surface"
|
||||
);
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName inFileName = args[1];
|
||||
const scalar minLen = args.argRead<scalar>(2);
|
||||
const scalar minQuality = args.argRead<scalar>(3);
|
||||
const fileName outFileName = args[4];
|
||||
|
||||
Info<< "Reading surface " << inFileName << nl
|
||||
<< "Collapsing all triangles with" << nl
|
||||
<< " edges or heights < " << minLen << nl
|
||||
<< " quality < " << minQuality << nl
|
||||
<< "Writing result to " << outFileName << nl << endl;
|
||||
|
||||
|
||||
Info<< "Reading surface from " << inFileName << " ..." << nl << endl;
|
||||
triSurface surf(inFileName);
|
||||
surf.writeStats(Info);
|
||||
|
||||
if (!args.optionFound("noClean"))
|
||||
{
|
||||
Info<< "Removing duplicate and illegal triangles ..." << nl << endl;
|
||||
surf.cleanup(true);
|
||||
}
|
||||
|
||||
Info<< "Collapsing triangles to edges ..." << nl << endl;
|
||||
|
||||
while (true)
|
||||
{
|
||||
label nEdgeCollapse = collapseEdge(surf, minLen);
|
||||
|
||||
if (nEdgeCollapse == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
label nSplitEdge = collapseBase(surf, minLen, minQuality);
|
||||
|
||||
if (nSplitEdge == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Info<< nl
|
||||
<< "Resulting surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
|
||||
Info<< nl
|
||||
<< "Writing refined surface to " << outFileName << " ..." << endl;
|
||||
surf.write(outFileName);
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
5
applications/utilities/surface/surfaceCoarsen/Make/files
Normal file
5
applications/utilities/surface/surfaceCoarsen/Make/files
Normal file
@ -0,0 +1,5 @@
|
||||
bunnylod/progmesh.C
|
||||
bunnylod/vector.C
|
||||
surfaceCoarsen.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceCoarsen
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-Ibunnylod \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ltriSurface \
|
||||
-lmeshTools
|
||||
@ -0,0 +1,12 @@
|
||||
|
||||
Polygon Reduction Demo
|
||||
By Stan Melax (c) 1998
|
||||
mailto:melax@cs.ualberta.ca
|
||||
http://www.cs.ualberta.ca/~melax
|
||||
|
||||
The PC executable bunnylod.exe should run
|
||||
on a standard PC.
|
||||
Just run it and enjoy.
|
||||
Mouse dragging spins the rabbit.
|
||||
|
||||
|
||||
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Polygon Reduction Demo by Stan Melax (c) 1998
|
||||
* Permission to use any of this code wherever you want is granted..
|
||||
* Although, please do acknowledge authorship if appropriate.
|
||||
*
|
||||
* This module initializes the bunny model data and calls
|
||||
* the polygon reduction routine. At each frame the RenderModel()
|
||||
* routine is called to draw the model. This module also
|
||||
* animates the parameters (such as number of vertices to
|
||||
* use) to show the model at various levels of detail.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <GL/gl.h>
|
||||
#pragma warning(disable : 4244)
|
||||
|
||||
#include "vector.h"
|
||||
#include "font.h"
|
||||
#include "progmesh.h"
|
||||
#include "rabdata.h"
|
||||
|
||||
extern float DeltaT; // change in time since last frame
|
||||
int render_num; // number of vertices to draw with
|
||||
float lodbase=0.5f; // the fraction of vertices used to morph toward
|
||||
float morph=1.0f; // where to render between 2 levels of detail
|
||||
List<Vector> vert; // global list of vertices
|
||||
List<tridata> tri; // global list of triangles
|
||||
List<int> collapse_map; // to which neighbor each vertex collapses
|
||||
int renderpolycount=0; // polygons rendered in the current frame
|
||||
Vector model_position; // position of bunny
|
||||
Quaternion model_orientation; // orientation of bunny
|
||||
|
||||
// Note that the use of the Map() function and the collapse_map
|
||||
// list isn't part of the polygon reduction algorithm.
|
||||
// We just set up this system here in this module
|
||||
// so that we could retrieve the model at any desired vertex count.
|
||||
// Therefore if this part of the program confuses you, then
|
||||
// dont worry about it. It might help to look over the progmesh.cpp
|
||||
// module first.
|
||||
|
||||
// Map()
|
||||
//
|
||||
// When the model is rendered using a maximum of mx vertices
|
||||
// then it is vertices 0 through mx-1 that are used.
|
||||
// We are able to do this because the vertex list
|
||||
// gets sorted according to the collapse order.
|
||||
// The Map() routine takes a vertex number 'a' and the
|
||||
// maximum number of vertices 'mx' and returns the
|
||||
// appropriate vertex in the range 0 to mx-1.
|
||||
// When 'a' is greater than 'mx' the Map() routine
|
||||
// follows the chain of edge collapses until a vertex
|
||||
// within the limit is reached.
|
||||
// An example to make this clear: assume there is
|
||||
// a triangle with vertices 1, 3 and 12. But when
|
||||
// rendering the model we limit ourselves to 10 vertices.
|
||||
// In that case we find out how vertex 12 was removed
|
||||
// by the polygon reduction algorithm. i.e. which
|
||||
// edge was collapsed. Lets say that vertex 12 was collapsed
|
||||
// to vertex number 7. This number would have been stored
|
||||
// in the collapse_map array (i.e. collapse_map[12]==7).
|
||||
// Since vertex 7 is in range (less than max of 10) we
|
||||
// will want to render the triangle 1,3,7.
|
||||
// Pretend now that we want to limit ourselves to 5 vertices.
|
||||
// and vertex 7 was collapsed to vertex 3
|
||||
// (i.e. collapse_map[7]==3). Then triangle 1,3,12 would now be
|
||||
// triangle 1,3,3. i.e. this polygon was removed by the
|
||||
// progressive mesh polygon reduction algorithm by the time
|
||||
// it had gotten down to 5 vertices.
|
||||
// No need to draw a one dimensional polygon. :-)
|
||||
int Map(int a,int mx) {
|
||||
if(mx<=0) return 0;
|
||||
while(a>=mx) {
|
||||
a=collapse_map[a];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void DrawModelTriangles() {
|
||||
assert(collapse_map.num);
|
||||
renderpolycount=0;
|
||||
int i=0;
|
||||
for(i=0;i<tri.num;i++) {
|
||||
int p0= Map(tri[i].v[0],render_num);
|
||||
int p1= Map(tri[i].v[1],render_num);
|
||||
int p2= Map(tri[i].v[2],render_num);
|
||||
// note: serious optimization opportunity here,
|
||||
// by sorting the triangles the following "continue"
|
||||
// could have been made into a "break" statement.
|
||||
if(p0==p1 || p1==p2 || p2==p0) continue;
|
||||
renderpolycount++;
|
||||
// if we are not currenly morphing between 2 levels of detail
|
||||
// (i.e. if morph=1.0) then q0,q1, and q2 are not necessary.
|
||||
int q0= Map(p0,(int)(render_num*lodbase));
|
||||
int q1= Map(p1,(int)(render_num*lodbase));
|
||||
int q2= Map(p2,(int)(render_num*lodbase));
|
||||
Vector v0,v1,v2;
|
||||
v0 = vert[p0]*morph + vert[q0]*(1-morph);
|
||||
v1 = vert[p1]*morph + vert[q1]*(1-morph);
|
||||
v2 = vert[p2]*morph + vert[q2]*(1-morph);
|
||||
glBegin(GL_POLYGON);
|
||||
// the purpose of the demo is to show polygons
|
||||
// therefore just use 1 face normal (flat shading)
|
||||
Vector nrml = (v1-v0) * (v2-v1); // cross product
|
||||
if(0<magnitude(nrml)) {
|
||||
glNormal3fv(normalize(nrml));
|
||||
}
|
||||
glVertex3fv(v0);
|
||||
glVertex3fv(v1);
|
||||
glVertex3fv(v2);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PermuteVertices(List<int> &permutation) {
|
||||
// rearrange the vertex list
|
||||
List<Vector> temp_list;
|
||||
int i;
|
||||
assert(permutation.num==vert.num);
|
||||
for(i=0;i<vert.num;i++) {
|
||||
temp_list.Add(vert[i]);
|
||||
}
|
||||
for(i=0;i<vert.num;i++) {
|
||||
vert[permutation[i]]=temp_list[i];
|
||||
}
|
||||
// update the changes in the entries in the triangle list
|
||||
for(i=0;i<tri.num;i++) {
|
||||
for(int j=0;j<3;j++) {
|
||||
tri[i].v[j] = permutation[tri[i].v[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetRabbitData(){
|
||||
// Copy the geometry from the arrays of data in rabdata.cpp into
|
||||
// the vert and tri lists which we send to the reduction routine
|
||||
int i;
|
||||
for(i=0;i<RABBIT_VERTEX_NUM;i++) {
|
||||
float *vp=rabbit_vertices[i];
|
||||
vert.Add(Vector(vp[0],vp[1],vp[2]));
|
||||
}
|
||||
for(i=0;i<RABBIT_TRIANGLE_NUM;i++) {
|
||||
tridata td;
|
||||
td.v[0]=rabbit_triangles[i][0];
|
||||
td.v[1]=rabbit_triangles[i][1];
|
||||
td.v[2]=rabbit_triangles[i][2];
|
||||
tri.Add(td);
|
||||
}
|
||||
render_num=vert.num; // by default lets use all the model to render
|
||||
}
|
||||
|
||||
|
||||
void InitModel() {
|
||||
List<int> permutation;
|
||||
GetRabbitData();
|
||||
ProgressiveMesh(vert,tri,collapse_map,permutation);
|
||||
PermuteVertices(permutation);
|
||||
model_position = Vector(0,0,-3);
|
||||
Quaternion yaw(Vector(0,1,0),-3.14f/4); // 45 degrees
|
||||
Quaternion pitch(Vector(1,0,0),3.14f/12); // 15 degrees
|
||||
model_orientation = pitch*yaw;
|
||||
}
|
||||
|
||||
void StatusDraw() {
|
||||
// Draw a slider type widget looking thing
|
||||
// to show portion of vertices being used
|
||||
float b = (float)render_num/(float)vert.num;
|
||||
float a = b*(lodbase );
|
||||
glDisable(GL_LIGHTING);
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(-0.15,15,-0.1,1.1,-0.1,100);
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glBegin(GL_POLYGON);
|
||||
glColor3f(1,0,0);
|
||||
glVertex2f(0,0);
|
||||
glVertex2f(1,0);
|
||||
glVertex2f(1,a);
|
||||
glVertex2f(0,a);
|
||||
glEnd();
|
||||
glBegin(GL_POLYGON);
|
||||
glColor3f(1,0,0);
|
||||
glVertex2f(0,a);
|
||||
glVertex2f(morph,a);
|
||||
glVertex2f(morph,b);
|
||||
glVertex2f(0,b);
|
||||
glEnd();
|
||||
glBegin(GL_POLYGON);
|
||||
glColor3f(0,0,1);
|
||||
glVertex2f(morph,a);
|
||||
glVertex2f(1,a);
|
||||
glVertex2f(1,b);
|
||||
glVertex2f(morph,b);
|
||||
glEnd();
|
||||
glBegin(GL_POLYGON);
|
||||
glColor3f(0,0,1);
|
||||
glVertex2f(0,b);
|
||||
glVertex2f(1,b);
|
||||
glVertex2f(1,1);
|
||||
glVertex2f(0,1);
|
||||
glEnd();
|
||||
glPopMatrix();
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glPopMatrix();
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
}
|
||||
|
||||
/*
|
||||
* The following is just a quick hack to animate
|
||||
* the object through various polygon reduced versions.
|
||||
*/
|
||||
struct keyframethings {
|
||||
float t; // timestamp
|
||||
float n; // portion of vertices used to start
|
||||
float dn; // rate of change in "n"
|
||||
float m; // morph value
|
||||
float dm; // rate of change in "m"
|
||||
} keys[]={
|
||||
{0 ,1 ,0 ,1, 0},
|
||||
{2 ,1 ,-1,1, 0},
|
||||
{10,0 ,1 ,1, 0},
|
||||
{18,1 ,0 ,1, 0},
|
||||
{20,1 ,0 ,1,-1},
|
||||
{24,0.5 ,0 ,1, 0},
|
||||
{26,0.5 ,0 ,1,-1},
|
||||
{30,0.25,0 ,1, 0},
|
||||
{32,0.25,0 ,1,-1},
|
||||
{36,0.125,0,1, 0},
|
||||
{38,0.25,0 ,0, 1},
|
||||
{42,0.5 ,0 ,0, 1},
|
||||
{46,1 ,0 ,0, 1},
|
||||
{50,1 ,0 ,1, 0},
|
||||
};
|
||||
void AnimateParameters() {
|
||||
static float time=0; // global time - used for animation
|
||||
time+=DeltaT;
|
||||
if(time>=50) time=0; // repeat cycle every so many seconds
|
||||
int k=0;
|
||||
while(time>keys[k+1].t) {
|
||||
k++;
|
||||
}
|
||||
float interp = (time-keys[k].t)/(keys[k+1].t-keys[k].t);
|
||||
render_num = vert.num*(keys[k].n + interp*keys[k].dn);
|
||||
morph = keys[k].m + interp*keys[k].dm;
|
||||
morph = (morph>1.0f) ? 1.0f : morph; // clamp value
|
||||
if(render_num>vert.num) render_num=vert.num;
|
||||
if(render_num<0 ) render_num=0;
|
||||
}
|
||||
|
||||
void RenderModel() {
|
||||
AnimateParameters();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glColor3f(1,1,1);
|
||||
glPushMatrix();
|
||||
glTranslatef(model_position.x,model_position.y,model_position.z);
|
||||
// Rotate by quaternion: model_orientation
|
||||
Vector axis=model_orientation.axis();
|
||||
float angle=model_orientation.angle()*180.0f/3.14f;
|
||||
glRotatef(angle,axis.x,axis.y,axis.z);
|
||||
DrawModelTriangles();
|
||||
StatusDraw();
|
||||
glPopMatrix();
|
||||
|
||||
char buf[256];
|
||||
sprintf(buf,"Polys: %d Vertices: %d ",renderpolycount,render_num);
|
||||
if(morph<1.0) {
|
||||
sprintf(buf+strlen(buf),"<-> %d morph: %4.2f ",
|
||||
(int)(lodbase *render_num),morph);
|
||||
}
|
||||
PostString(buf,0,-2,5);
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
# Microsoft Developer Studio Project File - Name="bunnylod" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 5.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Application" 0x0101
|
||||
|
||||
CFG=bunnylod - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "bunnylod.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "bunnylod.mak" CFG="bunnylod - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "bunnylod - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "bunnylod - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "bunnylod - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib winmm.lib /nologo /subsystem:windows /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "bunnylod - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "bunnylod - Win32 Release"
|
||||
# Name "bunnylod - Win32 Debug"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bunnygut.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\font.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\progmesh.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\rabdata.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\winmain.cpp
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 5.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "bunnylod"=.\bunnylod.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
void PrintString(char *s,int x=0,int y=-1);
|
||||
void PostString(char *_s,int _x,int _y,float _life=5.0);
|
||||
void RenderStrings();
|
||||
|
||||
#endif
|
||||
130
applications/utilities/surface/surfaceCoarsen/bunnylod/list.h
Normal file
130
applications/utilities/surface/surfaceCoarsen/bunnylod/list.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* A generic template list class.
|
||||
* Fairly typical of the list example you would
|
||||
* find in any c++ book.
|
||||
*/
|
||||
#ifndef GENERIC_LIST_H
|
||||
#define GENERIC_LIST_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
template <class Type> class List {
|
||||
public:
|
||||
List(int s=0);
|
||||
~List();
|
||||
void allocate(int s);
|
||||
void SetSize(int s);
|
||||
void Pack();
|
||||
void Add(Type);
|
||||
void AddUnique(Type);
|
||||
int Contains(Type);
|
||||
void Remove(Type);
|
||||
void DelIndex(int i);
|
||||
Type * element;
|
||||
int num;
|
||||
int array_size;
|
||||
Type &operator[](int i){
|
||||
assert(i>=0 && i<num);
|
||||
return element[i];}
|
||||
};
|
||||
|
||||
|
||||
template <class Type>
|
||||
List<Type>::List(int s){
|
||||
num=0;
|
||||
array_size = 0;
|
||||
element = NULL;
|
||||
if(s) {
|
||||
allocate(s);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
List<Type>::~List(){
|
||||
delete element;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::allocate(int s){
|
||||
assert(s>0);
|
||||
assert(s>=num);
|
||||
Type *old = element;
|
||||
array_size =s;
|
||||
element = new Type[array_size];
|
||||
assert(element);
|
||||
for(int i=0;i<num;i++){
|
||||
element[i]=old[i];
|
||||
}
|
||||
if(old) delete old;
|
||||
}
|
||||
template <class Type>
|
||||
void List<Type>::SetSize(int s){
|
||||
if(s==0) { if(element) delete element;}
|
||||
else { allocate(s); }
|
||||
num=s;
|
||||
}
|
||||
template <class Type>
|
||||
void List<Type>::Pack(){
|
||||
allocate(num);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::Add(Type t){
|
||||
assert(num<=array_size);
|
||||
if(num==array_size) {
|
||||
allocate((array_size)?array_size *2:16);
|
||||
}
|
||||
//int i;
|
||||
//for(i=0;i<num;i++) {
|
||||
// dissallow duplicates
|
||||
// assert(element[i] != t);
|
||||
//}
|
||||
element[num++] = t;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
int List<Type>::Contains(Type t){
|
||||
int i;
|
||||
int count=0;
|
||||
for(i=0;i<num;i++) {
|
||||
if(element[i] == t) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::AddUnique(Type t){
|
||||
if(!Contains(t)) Add(t);
|
||||
}
|
||||
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::DelIndex(int i){
|
||||
assert(i<num);
|
||||
num--;
|
||||
while(i<num){
|
||||
element[i] = element[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void List<Type>::Remove(Type t){
|
||||
int i;
|
||||
for(i=0;i<num;i++) {
|
||||
if(element[i] == t) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
DelIndex(i);
|
||||
for(i=0;i<num;i++) {
|
||||
assert(element[i] != t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Progressive Mesh type Polygon Reduction Algorithm
|
||||
* by Stan Melax (c) 1998
|
||||
* Permission to use any of this code wherever you want is granted..
|
||||
* Although, please do acknowledge authorship if appropriate.
|
||||
*
|
||||
* See the header file progmesh.h for a description of this module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
//#include <windows.h>
|
||||
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
#include "progmesh.h"
|
||||
|
||||
#define min(x,y) (((x) <= (y)) ? (x) : (y))
|
||||
#define max(x,y) (((x) >= (y)) ? (x) : (y))
|
||||
|
||||
|
||||
/*
|
||||
* For the polygon reduction algorithm we use data structures
|
||||
* that contain a little bit more information than the usual
|
||||
* indexed face set type of data structure.
|
||||
* From a vertex we wish to be able to quickly get the
|
||||
* neighboring faces and vertices.
|
||||
*/
|
||||
class Triangle;
|
||||
class Vertex;
|
||||
|
||||
class Triangle {
|
||||
public:
|
||||
Vertex * vertex[3]; // the 3 points that make this tri
|
||||
Vector normal; // unit vector othogonal to this face
|
||||
Triangle(Vertex *v0,Vertex *v1,Vertex *v2);
|
||||
~Triangle();
|
||||
void ComputeNormal();
|
||||
void ReplaceVertex(Vertex *vold,Vertex *vnew);
|
||||
int HasVertex(Vertex *v);
|
||||
};
|
||||
class Vertex {
|
||||
public:
|
||||
Vector position; // location of point in euclidean space
|
||||
int id; // place of vertex in original list
|
||||
List<Vertex *> neighbor; // adjacent vertices
|
||||
List<Triangle *> face; // adjacent triangles
|
||||
float objdist; // cached cost of collapsing edge
|
||||
Vertex * collapse; // candidate vertex for collapse
|
||||
Vertex(Vector v,int _id);
|
||||
~Vertex();
|
||||
void RemoveIfNonNeighbor(Vertex *n);
|
||||
};
|
||||
List<Vertex *> vertices;
|
||||
List<Triangle *> triangles;
|
||||
|
||||
|
||||
Triangle::Triangle(Vertex *v0,Vertex *v1,Vertex *v2){
|
||||
assert(v0!=v1 && v1!=v2 && v2!=v0);
|
||||
vertex[0]=v0;
|
||||
vertex[1]=v1;
|
||||
vertex[2]=v2;
|
||||
ComputeNormal();
|
||||
triangles.Add(this);
|
||||
for(int i=0;i<3;i++) {
|
||||
vertex[i]->face.Add(this);
|
||||
for(int j=0;j<3;j++) if(i!=j) {
|
||||
vertex[i]->neighbor.AddUnique(vertex[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Triangle::~Triangle(){
|
||||
int i;
|
||||
triangles.Remove(this);
|
||||
for(i=0;i<3;i++) {
|
||||
if(vertex[i]) vertex[i]->face.Remove(this);
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
int i2 = (i+1)%3;
|
||||
if(!vertex[i] || !vertex[i2]) continue;
|
||||
vertex[i ]->RemoveIfNonNeighbor(vertex[i2]);
|
||||
vertex[i2]->RemoveIfNonNeighbor(vertex[i ]);
|
||||
}
|
||||
}
|
||||
int Triangle::HasVertex(Vertex *v) {
|
||||
return (v==vertex[0] ||v==vertex[1] || v==vertex[2]);
|
||||
}
|
||||
void Triangle::ComputeNormal(){
|
||||
Vector v0=vertex[0]->position;
|
||||
Vector v1=vertex[1]->position;
|
||||
Vector v2=vertex[2]->position;
|
||||
normal = (v1-v0)*(v2-v1);
|
||||
if(magnitude(normal)==0)return;
|
||||
normal = normalize(normal);
|
||||
}
|
||||
void Triangle::ReplaceVertex(Vertex *vold,Vertex *vnew) {
|
||||
assert(vold && vnew);
|
||||
assert(vold==vertex[0] || vold==vertex[1] || vold==vertex[2]);
|
||||
assert(vnew!=vertex[0] && vnew!=vertex[1] && vnew!=vertex[2]);
|
||||
if(vold==vertex[0]){
|
||||
vertex[0]=vnew;
|
||||
}
|
||||
else if(vold==vertex[1]){
|
||||
vertex[1]=vnew;
|
||||
}
|
||||
else {
|
||||
assert(vold==vertex[2]);
|
||||
vertex[2]=vnew;
|
||||
}
|
||||
int i;
|
||||
vold->face.Remove(this);
|
||||
assert(!vnew->face.Contains(this));
|
||||
vnew->face.Add(this);
|
||||
for(i=0;i<3;i++) {
|
||||
vold->RemoveIfNonNeighbor(vertex[i]);
|
||||
vertex[i]->RemoveIfNonNeighbor(vold);
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
assert(vertex[i]->face.Contains(this)==1);
|
||||
for(int j=0;j<3;j++) if(i!=j) {
|
||||
vertex[i]->neighbor.AddUnique(vertex[j]);
|
||||
}
|
||||
}
|
||||
ComputeNormal();
|
||||
}
|
||||
|
||||
Vertex::Vertex(Vector v,int _id) {
|
||||
position =v;
|
||||
id=_id;
|
||||
vertices.Add(this);
|
||||
}
|
||||
|
||||
Vertex::~Vertex(){
|
||||
assert(face.num==0);
|
||||
while(neighbor.num) {
|
||||
neighbor[0]->neighbor.Remove(this);
|
||||
neighbor.Remove(neighbor[0]);
|
||||
}
|
||||
vertices.Remove(this);
|
||||
}
|
||||
void Vertex::RemoveIfNonNeighbor(Vertex *n) {
|
||||
// removes n from neighbor list if n isn't a neighbor.
|
||||
if(!neighbor.Contains(n)) return;
|
||||
for(int i=0;i<face.num;i++) {
|
||||
if(face[i]->HasVertex(n)) return;
|
||||
}
|
||||
neighbor.Remove(n);
|
||||
}
|
||||
|
||||
|
||||
float ComputeEdgeCollapseCost(Vertex *u,Vertex *v) {
|
||||
// if we collapse edge uv by moving u to v then how
|
||||
// much different will the model change, i.e. how much "error".
|
||||
// Texture, vertex normal, and border vertex code was removed
|
||||
// to keep this demo as simple as possible.
|
||||
// The method of determining cost was designed in order
|
||||
// to exploit small and coplanar regions for
|
||||
// effective polygon reduction.
|
||||
// Is is possible to add some checks here to see if "folds"
|
||||
// would be generated. i.e. normal of a remaining face gets
|
||||
// flipped. I never seemed to run into this problem and
|
||||
// therefore never added code to detect this case.
|
||||
int i;
|
||||
float edgelength = magnitude(v->position - u->position);
|
||||
float curvature=0;
|
||||
|
||||
// find the "sides" triangles that are on the edge uv
|
||||
List<Triangle *> sides;
|
||||
for(i=0;i<u->face.num;i++) {
|
||||
if(u->face[i]->HasVertex(v)){
|
||||
sides.Add(u->face[i]);
|
||||
}
|
||||
}
|
||||
// use the triangle facing most away from the sides
|
||||
// to determine our curvature term
|
||||
for(i=0;i<u->face.num;i++) {
|
||||
float mincurv=1; // curve for face i and closer side to it
|
||||
for(int j=0;j<sides.num;j++) {
|
||||
// use dot product of face normals. '^'
|
||||
// defined in vector
|
||||
float dotprod = u->face[i]->normal ^ sides[j]->normal;
|
||||
mincurv = min(mincurv,(1-dotprod)/2.0f);
|
||||
}
|
||||
curvature = max(curvature,mincurv);
|
||||
}
|
||||
// the more coplanar the lower the curvature term
|
||||
return edgelength * curvature;
|
||||
}
|
||||
|
||||
void ComputeEdgeCostAtVertex(Vertex *v) {
|
||||
// compute the edge collapse cost for all edges that start
|
||||
// from vertex v. Since we are only interested in reducing
|
||||
// the object by selecting the min cost edge at each step, we
|
||||
// only cache the cost of the least cost edge at this vertex
|
||||
// (in member variable collapse) as well as the value of the
|
||||
// cost (in member variable objdist).
|
||||
if(v->neighbor.num==0) {
|
||||
// v doesn't have neighbors so it costs nothing to collapse
|
||||
v->collapse=NULL;
|
||||
v->objdist=-0.01f;
|
||||
return;
|
||||
}
|
||||
v->objdist = 1000000;
|
||||
v->collapse=NULL;
|
||||
// search all neighboring edges for "least cost" edge
|
||||
for(int i=0;i<v->neighbor.num;i++) {
|
||||
float dist;
|
||||
dist = ComputeEdgeCollapseCost(v,v->neighbor[i]);
|
||||
if(dist<v->objdist) {
|
||||
// candidate for edge collapse
|
||||
v->collapse=v->neighbor[i];
|
||||
// cost of the collapse
|
||||
v->objdist=dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ComputeAllEdgeCollapseCosts() {
|
||||
// For all the edges, compute the difference it would make
|
||||
// to the model if it was collapsed. The least of these
|
||||
// per vertex is cached in each vertex object.
|
||||
for(int i=0;i<vertices.num;i++) {
|
||||
ComputeEdgeCostAtVertex(vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Collapse(Vertex *u,Vertex *v){
|
||||
// Collapse the edge uv by moving vertex u onto v
|
||||
// Actually remove tris on uv, then update tris that
|
||||
// have u to have v, and then remove u.
|
||||
if(!v) {
|
||||
// u is a vertex all by itself so just delete it
|
||||
delete u;
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
List<Vertex *>tmp;
|
||||
// make tmp a list of all the neighbors of u
|
||||
for(i=0;i<u->neighbor.num;i++) {
|
||||
tmp.Add(u->neighbor[i]);
|
||||
}
|
||||
// delete triangles on edge uv:
|
||||
for(i=u->face.num-1;i>=0;i--) {
|
||||
if(u->face[i]->HasVertex(v)) {
|
||||
delete(u->face[i]);
|
||||
}
|
||||
}
|
||||
// update remaining triangles to have v instead of u
|
||||
for(i=u->face.num-1;i>=0;i--) {
|
||||
u->face[i]->ReplaceVertex(u,v);
|
||||
}
|
||||
delete u;
|
||||
// recompute the edge collapse costs for neighboring vertices
|
||||
for(i=0;i<tmp.num;i++) {
|
||||
ComputeEdgeCostAtVertex(tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AddVertex(List<Vector> &vert){
|
||||
for(int i=0;i<vert.num;i++) {
|
||||
new Vertex(vert[i],i);
|
||||
}
|
||||
}
|
||||
void AddFaces(List<tridata> &tri){
|
||||
for(int i=0;i<tri.num;i++) {
|
||||
new Triangle(
|
||||
vertices[tri[i].v[0]],
|
||||
vertices[tri[i].v[1]],
|
||||
vertices[tri[i].v[2]] );
|
||||
}
|
||||
}
|
||||
|
||||
Vertex *MinimumCostEdge(){
|
||||
// Find the edge that when collapsed will affect model the least.
|
||||
// This funtion actually returns a Vertex, the second vertex
|
||||
// of the edge (collapse candidate) is stored in the vertex data.
|
||||
// Serious optimization opportunity here: this function currently
|
||||
// does a sequential search through an unsorted list :-(
|
||||
// Our algorithm could be O(n*lg(n)) instead of O(n*n)
|
||||
Vertex *mn=vertices[0];
|
||||
for(int i=0;i<vertices.num;i++) {
|
||||
if(vertices[i]->objdist < mn->objdist) {
|
||||
mn = vertices[i];
|
||||
}
|
||||
}
|
||||
return mn;
|
||||
}
|
||||
|
||||
void ProgressiveMesh(List<Vector> &vert, List<tridata> &tri,
|
||||
List<int> &map, List<int> &permutation)
|
||||
{
|
||||
AddVertex(vert); // put input data into our data structures
|
||||
AddFaces(tri);
|
||||
ComputeAllEdgeCollapseCosts(); // cache all edge collapse costs
|
||||
permutation.SetSize(vertices.num); // allocate space
|
||||
map.SetSize(vertices.num); // allocate space
|
||||
// reduce the object down to nothing:
|
||||
while(vertices.num > 0) {
|
||||
// get the next vertex to collapse
|
||||
Vertex *mn = MinimumCostEdge();
|
||||
// keep track of this vertex, i.e. the collapse ordering
|
||||
permutation[mn->id]=vertices.num-1;
|
||||
// keep track of vertex to which we collapse to
|
||||
map[vertices.num-1] = (mn->collapse)?mn->collapse->id:-1;
|
||||
// Collapse this edge
|
||||
Collapse(mn,mn->collapse);
|
||||
}
|
||||
// reorder the map list based on the collapse ordering
|
||||
for(int i=0;i<map.num;i++) {
|
||||
map[i] = (map[i]==-1)?0:permutation[map[i]];
|
||||
}
|
||||
// The caller of this function should reorder their vertices
|
||||
// according to the returned "permutation".
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Progressive Mesh type Polygon Reduction Algorithm
|
||||
* by Stan Melax (c) 1998
|
||||
*
|
||||
* The function ProgressiveMesh() takes a model in an "indexed face
|
||||
* set" sort of way. i.e. list of vertices and list of triangles.
|
||||
* The function then does the polygon reduction algorithm
|
||||
* internally and reduces the model all the way down to 0
|
||||
* vertices and then returns the order in which the
|
||||
* vertices are collapsed and to which neighbor each vertex
|
||||
* is collapsed to. More specifically the returned "permutation"
|
||||
* indicates how to reorder your vertices so you can render
|
||||
* an object by using the first n vertices (for the n
|
||||
* vertex version). After permuting your vertices, the
|
||||
* map list indicates to which vertex each vertex is collapsed to.
|
||||
*/
|
||||
|
||||
#ifndef PROGRESSIVE_MESH_H
|
||||
#define PROGRESSIVE_MESH_H
|
||||
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
|
||||
class tridata {
|
||||
public:
|
||||
int v[3]; // indices to vertex list
|
||||
// texture and vertex normal info removed for this demo
|
||||
};
|
||||
|
||||
void ProgressiveMesh(List<Vector> &vert, List<tridata> &tri,
|
||||
List<int> &map, List<int> &permutation );
|
||||
|
||||
#endif
|
||||
117
applications/utilities/surface/surfaceCoarsen/bunnylod/vector.C
Normal file
117
applications/utilities/surface/surfaceCoarsen/bunnylod/vector.C
Normal file
@ -0,0 +1,117 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
float sqr(float a) {return a*a;}
|
||||
|
||||
// vector (floating point) implementation
|
||||
|
||||
float magnitude(Vector v) {
|
||||
return float(sqrt(sqr(v.x) + sqr( v.y)+ sqr(v.z)));
|
||||
}
|
||||
Vector normalize(Vector v) {
|
||||
float d=magnitude(v);
|
||||
if (d==0) {
|
||||
printf("Cant normalize ZERO vector\n");
|
||||
assert(0);
|
||||
d=0.1f;
|
||||
}
|
||||
v.x/=d;
|
||||
v.y/=d;
|
||||
v.z/=d;
|
||||
return v;
|
||||
}
|
||||
|
||||
Vector operator+(Vector v1,Vector v2)
|
||||
{
|
||||
return Vector(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z);
|
||||
}
|
||||
Vector operator-(Vector v1,Vector v2)
|
||||
{
|
||||
return Vector(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z);
|
||||
}
|
||||
Vector operator-(Vector v) {return Vector(-v.x,-v.y,-v.z);}
|
||||
Vector operator*(Vector v1,float s) {return Vector(v1.x*s,v1.y*s,v1.z*s);}
|
||||
Vector operator*(float s, Vector v1) {return Vector(v1.x*s,v1.y*s,v1.z*s);}
|
||||
Vector operator/(Vector v1,float s) {return v1*(1.0f/s);}
|
||||
float operator^(Vector v1,Vector v2)
|
||||
{
|
||||
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
|
||||
}
|
||||
Vector operator*(Vector v1,Vector v2) {
|
||||
return Vector(
|
||||
v1.y * v2.z - v1.z*v2.y,
|
||||
v1.z * v2.x - v1.x*v2.z,
|
||||
v1.x * v2.y - v1.y*v2.x);
|
||||
}
|
||||
Vector planelineintersection(Vector n,float d,Vector p1,Vector p2){
|
||||
// returns the point where the line p1-p2 intersects the plane n&d
|
||||
Vector dif = p2-p1;
|
||||
float dn= n^dif;
|
||||
float t = -(d+(n^p1) )/dn;
|
||||
return p1 + (dif*t);
|
||||
}
|
||||
int concurrent(Vector a,Vector b) {
|
||||
return(a.x==b.x && a.y==b.y && a.z==b.z);
|
||||
}
|
||||
|
||||
|
||||
// Matrix Implementation
|
||||
matrix transpose(matrix m) {
|
||||
return matrix( Vector(m.x.x,m.y.x,m.z.x),
|
||||
Vector(m.x.y,m.y.y,m.z.y),
|
||||
Vector(m.x.z,m.y.z,m.z.z));
|
||||
}
|
||||
Vector operator*(matrix m,Vector v){
|
||||
m=transpose(m); // since column ordered
|
||||
return Vector(m.x^v,m.y^v,m.z^v);
|
||||
}
|
||||
matrix operator*(matrix m1,matrix m2){
|
||||
m1=transpose(m1);
|
||||
return matrix(m1*m2.x,m1*m2.y,m1*m2.z);
|
||||
}
|
||||
|
||||
//Quaternion Implementation
|
||||
Quaternion operator*(Quaternion a,Quaternion b) {
|
||||
Quaternion c;
|
||||
c.r = a.r*b.r - a.x*b.x - a.y*b.y - a.z*b.z;
|
||||
c.x = a.r*b.x + a.x*b.r + a.y*b.z - a.z*b.y;
|
||||
c.y = a.r*b.y - a.x*b.z + a.y*b.r + a.z*b.x;
|
||||
c.z = a.r*b.z + a.x*b.y - a.y*b.x + a.z*b.r;
|
||||
return c;
|
||||
}
|
||||
Quaternion operator-(Quaternion q) {
|
||||
return Quaternion(q.r*-1,q.x,q.y,q.z);
|
||||
}
|
||||
Quaternion operator*(Quaternion a,float b) {
|
||||
return Quaternion(a.r*b, a.x*b, a.y*b, a.z*b);
|
||||
}
|
||||
Vector operator*(Quaternion q,Vector v) {
|
||||
return q.getmatrix() * v;
|
||||
}
|
||||
Vector operator*(Vector v,Quaternion q){
|
||||
assert(0); // must multiply with the quat on the left
|
||||
return Vector(0.0f,0.0f,0.0f);
|
||||
}
|
||||
|
||||
Quaternion operator+(Quaternion a,Quaternion b) {
|
||||
return Quaternion(a.r+b.r, a.x+b.x, a.y+b.y, a.z+b.z);
|
||||
}
|
||||
float operator^(Quaternion a,Quaternion b) {
|
||||
return (a.r*b.r + a.x*b.x + a.y*b.y + a.z*b.z);
|
||||
}
|
||||
Quaternion slerp(Quaternion a,Quaternion b,float interp){
|
||||
if((a^b) <0.0) {
|
||||
a.r=-a.r;
|
||||
a.x=-a.x;
|
||||
a.y=-a.y;
|
||||
a.z=-a.z;
|
||||
}
|
||||
float theta = float(acos(a^b));
|
||||
if(theta==0.0f) { return(a);}
|
||||
return
|
||||
a*float(sin(theta-interp*theta)/sin(theta))
|
||||
+ b*float(sin(interp*theta)/sin(theta));
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
//
|
||||
// This module contains a bunch of well understood functions
|
||||
// I apologise if the conventions used here are slightly
|
||||
// different than what you are used to.
|
||||
//
|
||||
|
||||
#ifndef GENERIC_VECTOR_H
|
||||
#define GENERIC_VECTOR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
class Vector {
|
||||
public:
|
||||
float x,y,z;
|
||||
Vector(float _x=0.0,float _y=0.0,float _z=0.0){x=_x;y=_y;z=_z;};
|
||||
operator float *() { return &x;};
|
||||
};
|
||||
|
||||
float magnitude(Vector v);
|
||||
Vector normalize(Vector v);
|
||||
|
||||
Vector operator+(Vector v1,Vector v2);
|
||||
Vector operator-(Vector v);
|
||||
Vector operator-(Vector v1,Vector v2);
|
||||
Vector operator*(Vector v1,float s) ;
|
||||
Vector operator*(float s,Vector v1) ;
|
||||
Vector operator/(Vector v1,float s) ;
|
||||
float operator^(Vector v1,Vector v2); // DOT product
|
||||
Vector operator*(Vector v1,Vector v2); // CROSS product
|
||||
Vector planelineintersection(Vector n,float d,Vector p1,Vector p2);
|
||||
|
||||
class matrix{
|
||||
public:
|
||||
Vector x,y,z;
|
||||
matrix(){x=Vector(1.0f,0.0f,0.0f);
|
||||
y=Vector(0.0f,1.0f,0.0f);
|
||||
z=Vector(0.0f,0.0f,1.0f);};
|
||||
matrix(Vector _x,Vector _y,Vector _z){x=_x;y=_y;z=_z;};
|
||||
};
|
||||
matrix transpose(matrix m);
|
||||
Vector operator*(matrix m,Vector v);
|
||||
matrix operator*(matrix m1,matrix m2);
|
||||
|
||||
class Quaternion{
|
||||
public:
|
||||
float r,x,y,z;
|
||||
Quaternion(){x=y=z=0.0f;r=1.0f;};
|
||||
Quaternion(Vector v,float t){
|
||||
v=normalize(v);
|
||||
r=float(cos(t/2.0));
|
||||
v=v*float(sin(t/2.0));
|
||||
x=v.x;
|
||||
y=v.y;
|
||||
z=v.z;
|
||||
};
|
||||
Quaternion(float _r,float _x,float _y,float _z){r=_r;x=_x;y=_y;z=_z;};
|
||||
float angle(){return float(acos(r)*2.0);}
|
||||
Vector axis(){Vector a(x,y,z); return a*float(1/sin(angle()/2.0));}
|
||||
Vector xdir(){
|
||||
return Vector(1-2*(y*y+z*z), 2*(x*y+r*z), 2*(x*z-r*y));
|
||||
}
|
||||
Vector ydir(){
|
||||
return Vector( 2*(x*y-r*z),1-2*(x*x+z*z), 2*(y*z+r*x));
|
||||
}
|
||||
Vector zdir(){
|
||||
return Vector( 2*(x*z+r*y), 2*(y*z-r*x),1-2*(x*x+y*y));
|
||||
}
|
||||
matrix getmatrix(){return matrix(xdir(),ydir(),zdir());}
|
||||
//operator matrix(){return getmatrix();}
|
||||
};
|
||||
Quaternion operator-(Quaternion q);
|
||||
Quaternion operator*(Quaternion a,Quaternion b);
|
||||
Vector operator*(Quaternion q,Vector v);
|
||||
Vector operator*(Vector v,Quaternion q);
|
||||
Quaternion slerp(Quaternion a,Quaternion b,float interp);
|
||||
|
||||
#endif
|
||||
453
applications/utilities/surface/surfaceCoarsen/bunnylod/winmain.C
Normal file
453
applications/utilities/surface/surfaceCoarsen/bunnylod/winmain.C
Normal file
@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Polygon Reduction Demo by Stan Melax (c) 1998
|
||||
* Permission to use any of this code wherever you want is granted..
|
||||
* Although, please do acknowledge authorship if appropriate.
|
||||
*
|
||||
* This module contains the window setup code, mouse input, timing
|
||||
* routines, and that sort of stuff. The interesting modules
|
||||
* to see are bunnygut.cpp and progmesh.cpp.
|
||||
*
|
||||
* The windows 95 specific code for this application was taken from
|
||||
* an example of processing mouse events in an OpenGL program using
|
||||
* the Win32 API from the www.opengl.org web site.
|
||||
*
|
||||
* Under Project->Settings, Link Options, General Category
|
||||
* Add:
|
||||
* Opengl32.lib glu32.lib winmm.lib
|
||||
* to the Object/Library Modules
|
||||
*
|
||||
* You will need have OpenGL libs and include files to compile this
|
||||
* Go to the www.opengl.org web site if you need help with this.
|
||||
*/
|
||||
|
||||
|
||||
#include <windows.h> /* must include this before GL/gl.h */
|
||||
#include <GL/gl.h> /* OpenGL header file */
|
||||
#include <GL/glu.h> /* OpenGL utilities header file */
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "vector.h"
|
||||
#include "font.h"
|
||||
|
||||
// Functions and Variables from bunny module
|
||||
extern void InitModel();
|
||||
extern void RenderModel();
|
||||
extern Vector model_position; // position of bunny
|
||||
extern Quaternion model_orientation; // orientation of bunny
|
||||
|
||||
// Global Variables
|
||||
float DeltaT = 0.1f;
|
||||
float FPS;
|
||||
int Width = 512;
|
||||
int Height = 512;
|
||||
int MouseX = 0;
|
||||
int MouseY = 0;
|
||||
Vector MouseVector; // 3D direction mouse points
|
||||
Vector OldMouseVector;
|
||||
int MouseState=0; // true iff left button down
|
||||
float ViewAngle=45.0f;
|
||||
|
||||
HDC hDC; /* device context */
|
||||
HPALETTE hPalette = 0; /* custom palette (if needed) */
|
||||
|
||||
|
||||
void CalcFPSDeltaT(){
|
||||
static int timeinit=0;
|
||||
static int start,start2,current,last;
|
||||
static int frame=0, frame2=0;
|
||||
if(!timeinit){
|
||||
frame=0;
|
||||
start=timeGetTime();
|
||||
timeinit=1;
|
||||
}
|
||||
frame++;
|
||||
frame2++;
|
||||
current=timeGetTime(); // found in winmm.lib
|
||||
double dif=(double)(current-start)/CLOCKS_PER_SEC;
|
||||
double rv = (dif)? (double)frame/(double)dif:-1.0;
|
||||
if(dif>2.0 && frame >10) {
|
||||
start = start2;
|
||||
frame = frame2;
|
||||
start2 = timeGetTime();
|
||||
frame2 = 0;
|
||||
}
|
||||
DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
|
||||
if(current==last) {
|
||||
DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
|
||||
}
|
||||
// if(DeltaT>1.0) DeltaT=1.0;
|
||||
FPS = (float)rv;
|
||||
last = current;
|
||||
}
|
||||
|
||||
|
||||
void ComputeMouseVector(){
|
||||
OldMouseVector=MouseVector;
|
||||
float spread = (float)tan(ViewAngle/2*3.14/180);
|
||||
float y = spread * ((Height-MouseY)-Height/2.0f) /(Height/2.0f);
|
||||
float x = spread * (MouseX-Width/2.0f) /(Height/2.0f);
|
||||
Vector v(x ,y,-1);
|
||||
// v=UserOrientation *v;
|
||||
v=normalize(v);
|
||||
MouseVector = v;
|
||||
}
|
||||
|
||||
Quaternion VirtualTrackBall(Vector cop,Vector cor,Vector dir1,Vector dir2) {
|
||||
// Implement track ball functionality to spin stuf on the screen
|
||||
// cop center of projection
|
||||
// cor center of rotation
|
||||
// dir1 old mouse direction
|
||||
// dir2 new mouse direction
|
||||
// pretend there is a sphere around cor. Then find the points
|
||||
// where dir1 and dir2 intersect that sphere. Find the
|
||||
// rotation that takes the first point to the second.
|
||||
float m;
|
||||
// compute plane
|
||||
Vector nrml = cor - cop;
|
||||
// since trackball proportional to distance from cop
|
||||
float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f);
|
||||
nrml = normalize(nrml);
|
||||
float dist = -(nrml^cor);
|
||||
Vector u= planelineintersection(nrml,dist,cop,cop+dir1);
|
||||
u=u-cor;
|
||||
u=u*fudgefactor;
|
||||
m= magnitude(u);
|
||||
if(m>1) {u=u*1.0f/m;}
|
||||
else {
|
||||
u=u - (nrml * (float)sqrt(1-m*m));
|
||||
}
|
||||
Vector v= planelineintersection(nrml,dist,cop,cop+dir2);
|
||||
v=v-cor;
|
||||
v=v*fudgefactor;
|
||||
m= magnitude(v);
|
||||
if(m>1) {v=v*1.0f/m;}
|
||||
else {
|
||||
v=v - (nrml * (float)sqrt(1-m*m));
|
||||
}
|
||||
Vector axis = u*v;
|
||||
float angle;
|
||||
m=magnitude(axis);
|
||||
if(m>1)m=1; // avoid potential floating point error
|
||||
Quaternion q(Vector(1.0f,0.0f,0.0f),0.0f);
|
||||
if(m>0 && (angle=(float)asin(m))>3.14/180) {
|
||||
axis = normalize(axis);
|
||||
q=Quaternion(axis,angle);
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void SpinIt(){
|
||||
// Change the orientation of the bunny according to mouse drag
|
||||
Quaternion q=VirtualTrackBall(Vector(0,0,0),model_position,
|
||||
OldMouseVector,MouseVector);
|
||||
model_orientation=q*model_orientation;
|
||||
}
|
||||
|
||||
void Reshape(int width, int height){
|
||||
// called initially and when the window changes size
|
||||
Width=width;
|
||||
Height=height;
|
||||
glViewport(0, 0, width, height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(ViewAngle, (float)width/height, 0.1, 50.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void PrintStats(){
|
||||
char buf[1024];buf[0]='\0';
|
||||
sprintf(buf,"FPS: %5.2f ",FPS);
|
||||
PostString(buf,0,-1,0);
|
||||
}
|
||||
|
||||
void Display(){
|
||||
// main drawing routine - called every frame
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
// camera at default (zero) position and orientation
|
||||
RenderModel();
|
||||
PrintStats();
|
||||
glLoadIdentity();
|
||||
RenderStrings();
|
||||
glPopMatrix();
|
||||
glFlush();
|
||||
SwapBuffers(hDC); /* nop if singlebuffered */
|
||||
}
|
||||
|
||||
|
||||
LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static PAINTSTRUCT ps;
|
||||
static GLboolean left = GL_FALSE; /* left button currently down? */
|
||||
static GLboolean right = GL_FALSE; /* right button currently down? */
|
||||
static int omx, omy, mx, my;
|
||||
|
||||
switch(uMsg) {
|
||||
case WM_PAINT:
|
||||
BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
case WM_SIZE:
|
||||
Reshape(LOWORD(lParam), HIWORD(lParam));
|
||||
PostMessage(hWnd, WM_PAINT, 0, 0);
|
||||
return 0;
|
||||
case WM_CHAR:
|
||||
switch (wParam) {
|
||||
case 27: /* ESC key */
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
/* if we don't set the capture we won't get mouse move
|
||||
messages when the mouse moves outside the window. */
|
||||
SetCapture(hWnd);
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
ComputeMouseVector();
|
||||
MouseState = 1;
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
if(MouseX & 1 << 15) MouseX -= (1 << 16);
|
||||
if(MouseY & 1 << 15) MouseY -= (1 << 16);
|
||||
ComputeMouseVector();
|
||||
if(MouseState) SpinIt();
|
||||
MouseState=0;
|
||||
/* remember to release the capture when we are finished. */
|
||||
ReleaseCapture();
|
||||
return 0;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
MouseX = LOWORD(lParam);
|
||||
MouseY = HIWORD(lParam);
|
||||
/* Win32 is pretty braindead about the x, y position that
|
||||
it returns when the mouse is off the left or top edge
|
||||
of the window (due to them being unsigned). therefore,
|
||||
roll the Win32's 0..2^16 pointer co-ord range to the
|
||||
more amenable (and useful) 0..+/-2^15. */
|
||||
if(MouseX & 1 << 15) MouseX -= (1 << 16);
|
||||
if(MouseY & 1 << 15) MouseY -= (1 << 16);
|
||||
ComputeMouseVector();
|
||||
if(MouseState) SpinIt();
|
||||
return 0;
|
||||
|
||||
case WM_PALETTECHANGED:
|
||||
if (hWnd == (HWND)wParam) break;
|
||||
/* fall through to WM_QUERYNEWPALETTE */
|
||||
case WM_QUERYNEWPALETTE:
|
||||
if (hPalette) {
|
||||
UnrealizeObject(hPalette);
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
HWND CreateOpenGLWindow(char* title)
|
||||
{
|
||||
// make a double-buffered, rgba, opengl window
|
||||
int n, pf;
|
||||
HWND hWnd;
|
||||
WNDCLASS wc;
|
||||
LOGPALETTE* lpPal;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
static HINSTANCE hInstance = 0;
|
||||
|
||||
/* only register the window class once - use hInstance as a flag. */
|
||||
if (!hInstance) {
|
||||
hInstance = GetModuleHandle(NULL);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = (WNDPROC)WindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "OpenGL";
|
||||
|
||||
if (!RegisterClass(&wc)) {
|
||||
MessageBox(NULL, "RegisterClass() failed: "
|
||||
"Cannot register window class.",
|
||||
"Error", MB_OK);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||
0,0,Width,Height, NULL, NULL, hInstance, NULL);
|
||||
|
||||
if (hWnd == NULL) {
|
||||
MessageBox(NULL,
|
||||
"CreateWindow() failed: Cannot create a window.",
|
||||
"Error", MB_OK);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
|
||||
/* there is no guarantee that the contents of the stack that become
|
||||
the pfd are zeroed, therefore _make sure_ to clear these bits. */
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW
|
||||
| PFD_SUPPORT_OPENGL
|
||||
| PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cDepthBits = 32;
|
||||
pfd.cColorBits = 32;
|
||||
|
||||
pf = ChoosePixelFormat(hDC, &pfd);
|
||||
if (pf == 0) {
|
||||
MessageBox(NULL, "ChoosePixelFormat() failed: "
|
||||
"Cannot find a suitable pixel format.",
|
||||
"Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
|
||||
MessageBox(NULL, "SetPixelFormat() failed: "
|
||||
"Cannot set format specified.", "Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
||||
|
||||
if (pfd.dwFlags & PFD_NEED_PALETTE ||
|
||||
pfd.iPixelType == PFD_TYPE_COLORINDEX) {
|
||||
|
||||
n = 1 << pfd.cColorBits;
|
||||
if (n > 256) n = 256;
|
||||
|
||||
lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
|
||||
sizeof(PALETTEENTRY) * n);
|
||||
memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
|
||||
lpPal->palVersion = 0x300;
|
||||
lpPal->palNumEntries = n;
|
||||
|
||||
GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
|
||||
|
||||
/* if the pixel type is RGBA, then we want to make an RGB ramp,
|
||||
otherwise (color index) set individual colors. */
|
||||
if (pfd.iPixelType == PFD_TYPE_RGBA) {
|
||||
int redMask = (1 << pfd.cRedBits) - 1;
|
||||
int greenMask = (1 << pfd.cGreenBits) - 1;
|
||||
int blueMask = (1 << pfd.cBlueBits) - 1;
|
||||
int i;
|
||||
|
||||
/* fill in the entries with an RGB color ramp. */
|
||||
for (i = 0; i < n; ++i) {
|
||||
lpPal->palPalEntry[i].peRed =
|
||||
(((i >> pfd.cRedShift) & redMask) * 255)
|
||||
/redMask;
|
||||
lpPal->palPalEntry[i].peGreen =
|
||||
(((i >> pfd.cGreenShift) & greenMask) * 255)
|
||||
/greenMask;
|
||||
lpPal->palPalEntry[i].peBlue =
|
||||
(((i >> pfd.cBlueShift) & blueMask) * 255)
|
||||
/blueMask;
|
||||
lpPal->palPalEntry[i].peFlags = 0;
|
||||
}
|
||||
} else {
|
||||
lpPal->palPalEntry[0].peRed = 0;
|
||||
lpPal->palPalEntry[0].peGreen = 0;
|
||||
lpPal->palPalEntry[0].peBlue = 0;
|
||||
lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[1].peRed = 255;
|
||||
lpPal->palPalEntry[1].peGreen = 0;
|
||||
lpPal->palPalEntry[1].peBlue = 0;
|
||||
lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[2].peRed = 0;
|
||||
lpPal->palPalEntry[2].peGreen = 255;
|
||||
lpPal->palPalEntry[2].peBlue = 0;
|
||||
lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
|
||||
lpPal->palPalEntry[3].peRed = 0;
|
||||
lpPal->palPalEntry[3].peGreen = 0;
|
||||
lpPal->palPalEntry[3].peBlue = 255;
|
||||
lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
|
||||
}
|
||||
|
||||
hPalette = CreatePalette(lpPal);
|
||||
if (hPalette) {
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
}
|
||||
|
||||
free(lpPal);
|
||||
}
|
||||
|
||||
ReleaseDC(hDC, hWnd);
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
|
||||
LPSTR lpszCmdLine, int nCmdShow)
|
||||
{
|
||||
HGLRC hRC; /* opengl context */
|
||||
HWND hWnd; /* window */
|
||||
MSG msg; /* message */
|
||||
|
||||
// InitModel() initializes some data structures and
|
||||
// does the progressive mesh polygon reduction algorithm
|
||||
// on the model.
|
||||
CalcFPSDeltaT(); // to time the algorithm
|
||||
InitModel();
|
||||
CalcFPSDeltaT();
|
||||
|
||||
hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
|
||||
if (hWnd == NULL) exit(1);
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
hRC = wglCreateContext(hDC);
|
||||
wglMakeCurrent(hDC, hRC);
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
PostString("Demo by Stan Melax (c)1998",5,-5,20);
|
||||
PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
|
||||
char buf[128];
|
||||
PostString("Mesh Reduction Algorithm (non-optimized)",1,0,5);
|
||||
sprintf(buf,"was executed in %5.3f seconds",DeltaT);
|
||||
PostString(buf,2,1,6);
|
||||
|
||||
while (1) {
|
||||
while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
|
||||
if(GetMessage(&msg, hWnd, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
} else {
|
||||
// This 'goto' was in the sample code
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
CalcFPSDeltaT();
|
||||
Display();
|
||||
}
|
||||
|
||||
quit:
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
ReleaseDC(hDC, hWnd);
|
||||
wglDeleteContext(hRC);
|
||||
DestroyWindow(hWnd);
|
||||
if (hPalette) DeleteObject(hPalette);
|
||||
return msg.wParam;
|
||||
}
|
||||
211
applications/utilities/surface/surfaceCoarsen/surfaceCoarsen.C
Normal file
211
applications/utilities/surface/surfaceCoarsen/surfaceCoarsen.C
Normal file
@ -0,0 +1,211 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceCoarsen
|
||||
|
||||
Description
|
||||
Surface coarsening using 'bunnylod':
|
||||
|
||||
Polygon Reduction Demo
|
||||
By Stan Melax (c) 1998
|
||||
mailto:melax@cs.ualberta.ca
|
||||
http://www.cs.ualberta.ca/~melax
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "fileName.H"
|
||||
#include "triSurface.H"
|
||||
#include "OFstream.H"
|
||||
#include "triFace.H"
|
||||
#include "triFaceList.H"
|
||||
|
||||
// From bunnylod
|
||||
#include "progmesh.h"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int mapVertex(::List<int>& collapse_map, int a, int mx)
|
||||
{
|
||||
if (mx <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
while (a >= mx)
|
||||
{
|
||||
a = collapse_map[a];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("reductionFactor");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName inFileName = args[1];
|
||||
const scalar reduction = args.argRead<scalar>(2);
|
||||
const fileName outFileName = args[3];
|
||||
|
||||
if (reduction <= 0 || reduction > 1)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Reduction factor " << reduction
|
||||
<< " should be within 0..1" << endl
|
||||
<< "(it is the reduction in number of vertices)"
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
Info<< "Input surface :" << inFileName << endl
|
||||
<< "Reduction factor:" << reduction << endl
|
||||
<< "Output surface :" << outFileName << endl << endl;
|
||||
|
||||
const triSurface surf(inFileName);
|
||||
|
||||
Info<< "Surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
|
||||
::List< ::Vector> vert; // global list of vertices
|
||||
::List< ::tridata> tri; // global list of triangles
|
||||
|
||||
|
||||
// Convert triSurface to progmesh format. Note: can use global point
|
||||
// numbering since surface read in from file.
|
||||
const pointField& pts = surf.points();
|
||||
|
||||
forAll(pts, ptI)
|
||||
{
|
||||
const point& pt = pts[ptI];
|
||||
|
||||
vert.Add( ::Vector(pt.x(), pt.y(), pt.z()));
|
||||
}
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
const labelledTri& f = surf[faceI];
|
||||
|
||||
tridata td;
|
||||
td.v[0]=f[0];
|
||||
td.v[1]=f[1];
|
||||
td.v[2]=f[2];
|
||||
tri.Add(td);
|
||||
}
|
||||
|
||||
::List<int> collapse_map; // to which neighbor each vertex collapses
|
||||
::List<int> permutation;
|
||||
|
||||
::ProgressiveMesh(vert,tri,collapse_map,permutation);
|
||||
|
||||
// rearrange the vertex list
|
||||
::List< ::Vector> temp_list;
|
||||
for (int i=0;i<vert.num;i++)
|
||||
{
|
||||
temp_list.Add(vert[i]);
|
||||
}
|
||||
for (int i=0;i<vert.num;i++)
|
||||
{
|
||||
vert[permutation[i]]=temp_list[i];
|
||||
}
|
||||
|
||||
// update the changes in the entries in the triangle list
|
||||
for (int i=0;i<tri.num;i++)
|
||||
{
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
tri[i].v[j] = permutation[tri[i].v[j]];
|
||||
}
|
||||
}
|
||||
|
||||
// Only get triangles with non-collapsed edges.
|
||||
int render_num = int(reduction * surf.nPoints());
|
||||
|
||||
Info<< "Reducing to " << render_num << " vertices" << endl;
|
||||
|
||||
|
||||
// Storage for new surface.
|
||||
Foam::List<labelledTri> newTris(surf.size());
|
||||
|
||||
label newI = 0;
|
||||
|
||||
for (int i=0; i<tri.num; i++)
|
||||
{
|
||||
int p0 = mapVertex(collapse_map, tri[i].v[0], render_num);
|
||||
int p1 = mapVertex(collapse_map, tri[i].v[1], render_num);
|
||||
int p2 = mapVertex(collapse_map, tri[i].v[2], render_num);
|
||||
|
||||
// note: serious optimization opportunity here,
|
||||
// by sorting the triangles the following "continue"
|
||||
// could have been made into a "break" statement.
|
||||
if (p0 == p1 || p1 == p2 || p2 == p0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newTris[newI++] = labelledTri(p0, p1, p2, 0);
|
||||
}
|
||||
newTris.setSize(newI);
|
||||
|
||||
// Convert vert into pointField.
|
||||
pointField newPoints(vert.num);
|
||||
|
||||
for (int i=0; i<vert.num; i++)
|
||||
{
|
||||
const ::Vector & v = vert[i];
|
||||
|
||||
newPoints[i] = point(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
triSurface surf2(newTris, newPoints);
|
||||
|
||||
triSurface outSurf
|
||||
(
|
||||
surf2.localFaces(),
|
||||
surf2.patches(),
|
||||
surf2.localPoints()
|
||||
);
|
||||
|
||||
Info<< "Coarsened surface:" << endl;
|
||||
surf2.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
Info<< "Writing to file " << outFileName << endl << endl;
|
||||
|
||||
surf2.write(outFileName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/utilities/surface/surfaceConvert/Make/files
Normal file
3
applications/utilities/surface/surfaceConvert/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceConvert.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceConvert
|
||||
@ -0,0 +1,6 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
159
applications/utilities/surface/surfaceConvert/surfaceConvert.C
Normal file
159
applications/utilities/surface/surfaceConvert/surfaceConvert.C
Normal file
@ -0,0 +1,159 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceConvert
|
||||
|
||||
Description
|
||||
Converts from one surface mesh format to another.
|
||||
|
||||
Usage
|
||||
- surfaceConvert inputFile outputFile [OPTION]
|
||||
|
||||
\param -clean \n
|
||||
Perform some surface checking/cleanup on the input surface
|
||||
|
||||
\param -scale \<scale\> \n
|
||||
Specify a scaling factor for writing the files
|
||||
|
||||
\param -group \n
|
||||
Orders faces by region
|
||||
|
||||
Note
|
||||
The filename extensions are used to determine the file format type.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "fileName.H"
|
||||
#include "triSurface.H"
|
||||
#include "OFstream.H"
|
||||
#include "OSspecific.H"
|
||||
#include "Time.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"convert between surface formats"
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("inputFile");
|
||||
argList::validArgs.append("outputFile");
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"clean",
|
||||
"perform some surface checking/cleanup on the input surface"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"group",
|
||||
"reorder faces into groups; one per region"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scale",
|
||||
"factor",
|
||||
"geometry scaling factor - default is 1"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"writePrecision",
|
||||
"label",
|
||||
"write to output with the specified precision"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
if (args.optionFound("writePrecision"))
|
||||
{
|
||||
label writePrecision = args.optionRead<label>("writePrecision");
|
||||
|
||||
IOstream::defaultPrecision(writePrecision);
|
||||
Sout.precision(writePrecision);
|
||||
|
||||
Info<< "Output write precision set to " << writePrecision << endl;
|
||||
}
|
||||
|
||||
const fileName importName = args[1];
|
||||
const fileName exportName = args[2];
|
||||
|
||||
if (importName == exportName)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Output file " << exportName << " would overwrite input file."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
Info<< "Reading : " << importName << endl;
|
||||
triSurface surf(importName);
|
||||
|
||||
Info<< "Read surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
Info<< "Cleaning up surface" << endl;
|
||||
surf.cleanup(true);
|
||||
|
||||
Info<< "After cleaning up surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
const bool sortByRegion = args.optionFound("group");
|
||||
if (sortByRegion)
|
||||
{
|
||||
Info<< "Reordering faces into groups; one per region." << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Maintaining face ordering" << endl;
|
||||
}
|
||||
|
||||
Info<< "writing " << exportName;
|
||||
|
||||
scalar scaleFactor = 0;
|
||||
if (args.optionReadIfPresent("scale", scaleFactor) && scaleFactor > 0)
|
||||
{
|
||||
Info<< " with scaling " << scaleFactor;
|
||||
surf.scalePoints(scaleFactor);
|
||||
}
|
||||
Info<< endl;
|
||||
|
||||
surf.write(exportName, sortByRegion);
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceFeatureConvert.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceFeatureConvert
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/edgeMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ledgeMesh
|
||||
@ -0,0 +1,110 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceFeatureConvert
|
||||
|
||||
Description
|
||||
Convert between edgeMesh formats.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
|
||||
#include "edgeMesh.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"Convert between edgeMesh formats"
|
||||
);
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("inputFile");
|
||||
argList::validArgs.append("outputFile");
|
||||
argList::addOption
|
||||
(
|
||||
"scale",
|
||||
"factor",
|
||||
"geometry scaling factor - default is 1"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
Time runTime(args.rootPath(), args.caseName());
|
||||
|
||||
const fileName importName = args[1];
|
||||
const fileName exportName = args[2];
|
||||
|
||||
// disable inplace editing
|
||||
if (importName == exportName)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Output file " << exportName << " would overwrite input file."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// check that reading/writing is supported
|
||||
if
|
||||
(
|
||||
!edgeMesh::canReadType(importName.ext(), true)
|
||||
|| !edgeMesh::canWriteType(exportName.ext(), true)
|
||||
)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
edgeMesh mesh(importName);
|
||||
|
||||
Info<< "\nRead edgeMesh " << importName << nl;
|
||||
mesh.writeStats(Info);
|
||||
Info<< nl
|
||||
<< "\nwriting " << exportName;
|
||||
|
||||
scalar scaleFactor = 0;
|
||||
if (args.optionReadIfPresent("scale", scaleFactor) && scaleFactor > 0)
|
||||
{
|
||||
Info<< " with scaling " << scaleFactor << endl;
|
||||
mesh.scalePoints(scaleFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< " without scaling" << endl;
|
||||
}
|
||||
|
||||
mesh.write(exportName);
|
||||
mesh.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceFeatureExtract.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceFeatureExtract
|
||||
@ -0,0 +1,13 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/edgeMesh/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude \
|
||||
-I$(LIB_SRC)/sampling/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ledgeMesh \
|
||||
-ltriSurface \
|
||||
-lsampling
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,117 @@
|
||||
/*--------------------------------*- 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;
|
||||
object surfaceFeatureExtractDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
surface1.stl
|
||||
{
|
||||
// How to obtain raw features (extractFromFile || extractFromSurface)
|
||||
extractionMethod extractFromSurface;
|
||||
|
||||
extractFromSurfaceCoeffs
|
||||
{
|
||||
// Mark edges whose adjacent surface normals are at an angle less
|
||||
// than includedAngle as features
|
||||
// - 0 : selects no edges
|
||||
// - 180: selects all edges
|
||||
includedAngle 120;
|
||||
|
||||
// Do not mark region edges
|
||||
geometricTestOnly yes;
|
||||
}
|
||||
|
||||
// Write options
|
||||
|
||||
// Write features to obj format for postprocessing
|
||||
writeObj yes;
|
||||
}
|
||||
|
||||
|
||||
surface2.nas
|
||||
{
|
||||
// How to obtain raw features (extractFromFile || extractFromSurface)
|
||||
extractionMethod extractFromFile;
|
||||
|
||||
extractFromFileCoeffs
|
||||
{
|
||||
// Load from an existing feature edge file
|
||||
featureEdgeFile "constant/triSurface/featureEdges.nas";
|
||||
}
|
||||
|
||||
trimFeatures
|
||||
{
|
||||
// Remove features with fewer than the specified number of edges
|
||||
minElem 0;
|
||||
|
||||
// Remove features shorter than the specified cumulative length
|
||||
minLen 0.0;
|
||||
}
|
||||
|
||||
subsetFeatures
|
||||
{
|
||||
// Use a plane to select feature edges
|
||||
// (normal)(basePoint)
|
||||
// Keep only edges that intersect the plane will be included
|
||||
plane (1 0 0)(0 0 0);
|
||||
|
||||
// Select feature edges using a box
|
||||
// (minPt)(maxPt)
|
||||
// Keep edges inside the box:
|
||||
insideBox (0 0 0)(1 1 1);
|
||||
// Keep edges outside the box:
|
||||
outsideBox (0 0 0)(1 1 1);
|
||||
|
||||
// Keep nonManifold edges (edges with >2 connected faces where
|
||||
// the faces form more than two different normal planes)
|
||||
nonManifoldEdges yes;
|
||||
|
||||
// Keep open edges (edges with 1 connected face)
|
||||
openEdges yes;
|
||||
}
|
||||
|
||||
addFeatures
|
||||
{
|
||||
// Add (without merging) another extendedFeatureEdgeMesh
|
||||
name axZ.extendedFeatureEdgeMesh;
|
||||
|
||||
// Optionally flip features (invert all normals, making
|
||||
// convex<->concave etc)
|
||||
//flip false;
|
||||
}
|
||||
|
||||
// Output the curvature of the surface
|
||||
curvature no;
|
||||
|
||||
// Output the proximity of feature points and edges to each other
|
||||
featureProximity no;
|
||||
|
||||
// The maximum search distance to use when looking for other feature
|
||||
// points and edges
|
||||
maxFeatureProximity 1;
|
||||
|
||||
// Out put the closeness of surface elements to other surface elements.
|
||||
closeness no;
|
||||
|
||||
// Write options
|
||||
|
||||
// Write features to obj format for postprocessing
|
||||
writeObj yes;
|
||||
|
||||
// Write surface proximity and curvature fields to vtk format
|
||||
// for postprocessing
|
||||
writeVTK no;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/utilities/surface/surfaceFind/Make/files
Normal file
3
applications/utilities/surface/surfaceFind/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceFind.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceFind
|
||||
6
applications/utilities/surface/surfaceFind/Make/options
Normal file
6
applications/utilities/surface/surfaceFind/Make/options
Normal file
@ -0,0 +1,6 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-lsurfMesh
|
||||
131
applications/utilities/surface/surfaceFind/surfaceFind.C
Normal file
131
applications/utilities/surface/surfaceFind/surfaceFind.C
Normal file
@ -0,0 +1,131 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceFind
|
||||
|
||||
Description
|
||||
Finds nearest face and vertex.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "OFstream.H"
|
||||
|
||||
#include "MeshedSurfaces.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::addOption("x", "X", "The point x-coordinate (if non-zero)");
|
||||
argList::addOption("y", "Y", "The point y-coordinate (if non-zero)");
|
||||
argList::addOption("z", "Z", "The point y-coordinate (if non-zero)");
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
const point samplePt
|
||||
(
|
||||
args.optionLookupOrDefault<scalar>("x", 0),
|
||||
args.optionLookupOrDefault<scalar>("y", 0),
|
||||
args.optionLookupOrDefault<scalar>("z", 0)
|
||||
);
|
||||
Info<< "Looking for nearest face/vertex to " << samplePt << endl;
|
||||
|
||||
|
||||
Info<< "Reading surf ..." << endl;
|
||||
meshedSurface surf1(args[1]);
|
||||
|
||||
//
|
||||
// Nearest vertex
|
||||
//
|
||||
|
||||
const pointField& localPoints = surf1.localPoints();
|
||||
|
||||
label minIndex = -1;
|
||||
scalar minDist = GREAT;
|
||||
|
||||
forAll(localPoints, pointI)
|
||||
{
|
||||
const scalar dist = mag(localPoints[pointI] - samplePt);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
minIndex = pointI;
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "Nearest vertex:" << nl
|
||||
<< " index :" << minIndex << " (in localPoints)" << nl
|
||||
<< " index :" << surf1.meshPoints()[minIndex]
|
||||
<< " (in points)" << nl
|
||||
<< " coordinates:" << localPoints[minIndex] << nl
|
||||
<< endl;
|
||||
|
||||
//
|
||||
// Nearest face
|
||||
//
|
||||
|
||||
const pointField& points = surf1.points();
|
||||
|
||||
minIndex = -1;
|
||||
minDist = GREAT;
|
||||
|
||||
forAll(surf1, faceI)
|
||||
{
|
||||
const point centre = surf1[faceI].centre(points);
|
||||
|
||||
const scalar dist = mag(centre - samplePt);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
minIndex = faceI;
|
||||
}
|
||||
}
|
||||
|
||||
const face& f = surf1[minIndex];
|
||||
|
||||
Info<< "Face with nearest centre:" << nl
|
||||
<< " index :" << minIndex << nl
|
||||
<< " centre :" << f.centre(points) << nl
|
||||
<< " face :" << f << nl
|
||||
<< " vertex coords:\n";
|
||||
forAll(f, fp)
|
||||
{
|
||||
Info<< " " << points[f[fp]] << "\n";
|
||||
}
|
||||
|
||||
Info<< endl;
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
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
|
||||
597
applications/utilities/surface/surfaceHookUp/surfaceHookUp.C
Normal file
597
applications/utilities/surface/surfaceHookUp/surfaceHookUp.C
Normal file
@ -0,0 +1,597 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2014 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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class findNearestOpSubset
|
||||
{
|
||||
const indexedOctree<treeDataEdge>& tree_;
|
||||
|
||||
DynamicList<label>& shapeMask_;
|
||||
|
||||
public:
|
||||
|
||||
findNearestOpSubset
|
||||
(
|
||||
const indexedOctree<treeDataEdge>& tree,
|
||||
DynamicList<label>& shapeMask
|
||||
)
|
||||
:
|
||||
tree_(tree),
|
||||
shapeMask_(shapeMask)
|
||||
{}
|
||||
|
||||
void operator()
|
||||
(
|
||||
const labelUList& indices,
|
||||
const point& sample,
|
||||
|
||||
scalar& nearestDistSqr,
|
||||
label& minIndex,
|
||||
point& nearestPoint
|
||||
) const
|
||||
{
|
||||
const treeDataEdge& shape = tree_.shapes();
|
||||
|
||||
forAll(indices, i)
|
||||
{
|
||||
const label index = indices[i];
|
||||
const label edgeIndex = shape.edgeLabels()[index];
|
||||
|
||||
if
|
||||
(
|
||||
!shapeMask_.empty()
|
||||
&& findIndex(shapeMask_, edgeIndex) != -1
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const edge& e = shape.edges()[edgeIndex];
|
||||
|
||||
pointHit nearHit = e.line(shape.points()).nearestDist(sample);
|
||||
|
||||
// Only register hit if closest point is not an edge point
|
||||
if (nearHit.hit())
|
||||
{
|
||||
scalar distSqr = sqr(nearHit.distance());
|
||||
|
||||
if (distSqr < nearestDistSqr)
|
||||
{
|
||||
nearestDistSqr = distSqr;
|
||||
minIndex = index;
|
||||
nearestPoint = nearHit.rawPoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
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(max(1e-6*dist, SMALL));
|
||||
const label maxIters = 100;
|
||||
|
||||
Info<< "Hooking distance = " << dist << endl;
|
||||
|
||||
searchableSurfaces surfs
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"surfacesToHook",
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime
|
||||
),
|
||||
dict,
|
||||
true // assume single-region names get surface name
|
||||
);
|
||||
|
||||
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 = 1;
|
||||
|
||||
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),
|
||||
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++;
|
||||
|
||||
label newPointI = -1;
|
||||
|
||||
// Keep the points in the same place and move the edge
|
||||
if (hitSurfI == surfI)
|
||||
{
|
||||
newPointI = pointI;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPoints[hitSurfI].append(newPoints[surfI][pointI]);
|
||||
newPointI = newPoints[hitSurfI].size() - 1;
|
||||
}
|
||||
|
||||
// Split the other face.
|
||||
greenRefine
|
||||
(
|
||||
hitSurf,
|
||||
faceI,
|
||||
eIndex,
|
||||
newPointI,
|
||||
newFacesFromSplit
|
||||
);
|
||||
|
||||
visitedFace[hitSurfI][faceI] = true;
|
||||
|
||||
forAll(newFacesFromSplit, newFaceI)
|
||||
{
|
||||
const labelledTri& fN = newFacesFromSplit[newFaceI];
|
||||
|
||||
if (newFaceI == 0)
|
||||
{
|
||||
newFaces[hitSurfI][faceI] = fN;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFaces[hitSurfI].append(fN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 && nIters <= maxIters);
|
||||
|
||||
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;}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/utilities/surface/surfaceInertia/Make/files
Normal file
3
applications/utilities/surface/surfaceInertia/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceInertia.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceInertia
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
415
applications/utilities/surface/surfaceInertia/surfaceInertia.C
Normal file
415
applications/utilities/surface/surfaceInertia/surfaceInertia.C
Normal file
@ -0,0 +1,415 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceInertia
|
||||
|
||||
Description
|
||||
Calculates the inertia tensor, principal axes and moments of a
|
||||
command line specified triSurface. Inertia can either be of the
|
||||
solid body or of a thin shell.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "ListOps.H"
|
||||
#include "triSurface.H"
|
||||
#include "OFstream.H"
|
||||
#include "meshTools.H"
|
||||
#include "Random.H"
|
||||
#include "transform.H"
|
||||
#include "IOmanip.H"
|
||||
#include "Pair.H"
|
||||
#include "momentOfInertia.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"Calculates the inertia tensor and principal axes and moments "
|
||||
"of the specified surface.\n"
|
||||
"Inertia can either be of the solid body or of a thin shell."
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::addBoolOption
|
||||
(
|
||||
"shellProperties",
|
||||
"inertia of a thin shell"
|
||||
);
|
||||
|
||||
argList::addOption
|
||||
(
|
||||
"density",
|
||||
"scalar",
|
||||
"Specify density, "
|
||||
"kg/m3 for solid properties, kg/m2 for shell properties"
|
||||
);
|
||||
|
||||
argList::addOption
|
||||
(
|
||||
"referencePoint",
|
||||
"vector",
|
||||
"Inertia relative to this point, not the centre of mass"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const scalar density = args.optionLookupOrDefault("density", 1.0);
|
||||
|
||||
vector refPt = vector::zero;
|
||||
bool calcAroundRefPt = args.optionReadIfPresent("referencePoint", refPt);
|
||||
|
||||
triSurface surf(surfFileName);
|
||||
|
||||
scalar m = 0.0;
|
||||
vector cM = vector::zero;
|
||||
tensor J = tensor::zero;
|
||||
|
||||
if (args.optionFound("shellProperties"))
|
||||
{
|
||||
momentOfInertia::massPropertiesShell(surf, density, m, cM, J);
|
||||
}
|
||||
else
|
||||
{
|
||||
momentOfInertia::massPropertiesSolid(surf, density, m, cM, J);
|
||||
}
|
||||
|
||||
if (m < 0)
|
||||
{
|
||||
WarningIn(args.executable() + "::main")
|
||||
<< "Negative mass detected, the surface may be inside-out." << endl;
|
||||
}
|
||||
|
||||
vector eVal = eigenValues(J);
|
||||
|
||||
tensor eVec = eigenVectors(J);
|
||||
|
||||
label pertI = 0;
|
||||
|
||||
Random rand(57373);
|
||||
|
||||
while ((magSqr(eVal) < VSMALL) && pertI < 10)
|
||||
{
|
||||
WarningIn(args.executable() + "::main")
|
||||
<< "No eigenValues found, shape may have symmetry, "
|
||||
<< "perturbing inertia tensor diagonal" << endl;
|
||||
|
||||
J.xx() *= 1.0 + SMALL*rand.scalar01();
|
||||
J.yy() *= 1.0 + SMALL*rand.scalar01();
|
||||
J.zz() *= 1.0 + SMALL*rand.scalar01();
|
||||
|
||||
eVal = eigenValues(J);
|
||||
|
||||
eVec = eigenVectors(J);
|
||||
|
||||
pertI++;
|
||||
}
|
||||
|
||||
bool showTransform = true;
|
||||
|
||||
if
|
||||
(
|
||||
(mag(eVec.x() ^ eVec.y()) > (1.0 - SMALL))
|
||||
&& (mag(eVec.y() ^ eVec.z()) > (1.0 - SMALL))
|
||||
&& (mag(eVec.z() ^ eVec.x()) > (1.0 - SMALL))
|
||||
)
|
||||
{
|
||||
// Make the eigenvectors a right handed orthogonal triplet
|
||||
eVec = tensor
|
||||
(
|
||||
eVec.x(),
|
||||
eVec.y(),
|
||||
eVec.z() * sign((eVec.x() ^ eVec.y()) & eVec.z())
|
||||
);
|
||||
|
||||
// Finding the most natural transformation. Using Lists
|
||||
// rather than tensors to allow indexed permutation.
|
||||
|
||||
// Cartesian basis vectors - right handed orthogonal triplet
|
||||
List<vector> cartesian(3);
|
||||
|
||||
cartesian[0] = vector(1, 0, 0);
|
||||
cartesian[1] = vector(0, 1, 0);
|
||||
cartesian[2] = vector(0, 0, 1);
|
||||
|
||||
// Principal axis basis vectors - right handed orthogonal
|
||||
// triplet
|
||||
List<vector> principal(3);
|
||||
|
||||
principal[0] = eVec.x();
|
||||
principal[1] = eVec.y();
|
||||
principal[2] = eVec.z();
|
||||
|
||||
scalar maxMagDotProduct = -GREAT;
|
||||
|
||||
// Matching axis indices, first: cartesian, second:principal
|
||||
|
||||
Pair<label> match(-1, -1);
|
||||
|
||||
forAll(cartesian, cI)
|
||||
{
|
||||
forAll(principal, pI)
|
||||
{
|
||||
scalar magDotProduct = mag(cartesian[cI] & principal[pI]);
|
||||
|
||||
if (magDotProduct > maxMagDotProduct)
|
||||
{
|
||||
maxMagDotProduct = magDotProduct;
|
||||
|
||||
match.first() = cI;
|
||||
|
||||
match.second() = pI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scalar sense = sign
|
||||
(
|
||||
cartesian[match.first()] & principal[match.second()]
|
||||
);
|
||||
|
||||
if (sense < 0)
|
||||
{
|
||||
// Invert the best match direction and swap the order of
|
||||
// the other two vectors
|
||||
|
||||
List<vector> tPrincipal = principal;
|
||||
|
||||
tPrincipal[match.second()] *= -1;
|
||||
|
||||
tPrincipal[(match.second() + 1) % 3] =
|
||||
principal[(match.second() + 2) % 3];
|
||||
|
||||
tPrincipal[(match.second() + 2) % 3] =
|
||||
principal[(match.second() + 1) % 3];
|
||||
|
||||
principal = tPrincipal;
|
||||
|
||||
vector tEVal = eVal;
|
||||
|
||||
tEVal[(match.second() + 1) % 3] = eVal[(match.second() + 2) % 3];
|
||||
|
||||
tEVal[(match.second() + 2) % 3] = eVal[(match.second() + 1) % 3];
|
||||
|
||||
eVal = tEVal;
|
||||
}
|
||||
|
||||
label permutationDelta = match.second() - match.first();
|
||||
|
||||
if (permutationDelta != 0)
|
||||
{
|
||||
// Add 3 to the permutationDelta to avoid negative indices
|
||||
|
||||
permutationDelta += 3;
|
||||
|
||||
List<vector> tPrincipal = principal;
|
||||
|
||||
vector tEVal = eVal;
|
||||
|
||||
for (label i = 0; i < 3; i++)
|
||||
{
|
||||
tPrincipal[i] = principal[(i + permutationDelta) % 3];
|
||||
|
||||
tEVal[i] = eVal[(i + permutationDelta) % 3];
|
||||
}
|
||||
|
||||
principal = tPrincipal;
|
||||
|
||||
eVal = tEVal;
|
||||
}
|
||||
|
||||
label matchedAlready = match.first();
|
||||
|
||||
match =Pair<label>(-1, -1);
|
||||
|
||||
maxMagDotProduct = -GREAT;
|
||||
|
||||
forAll(cartesian, cI)
|
||||
{
|
||||
if (cI == matchedAlready)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
forAll(principal, pI)
|
||||
{
|
||||
if (pI == matchedAlready)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
scalar magDotProduct = mag(cartesian[cI] & principal[pI]);
|
||||
|
||||
if (magDotProduct > maxMagDotProduct)
|
||||
{
|
||||
maxMagDotProduct = magDotProduct;
|
||||
|
||||
match.first() = cI;
|
||||
|
||||
match.second() = pI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sense = sign
|
||||
(
|
||||
cartesian[match.first()] & principal[match.second()]
|
||||
);
|
||||
|
||||
if (sense < 0 || (match.second() - match.first()) != 0)
|
||||
{
|
||||
principal[match.second()] *= -1;
|
||||
|
||||
List<vector> tPrincipal = principal;
|
||||
|
||||
tPrincipal[(matchedAlready + 1) % 3] =
|
||||
principal[(matchedAlready + 2) % 3]*-sense;
|
||||
|
||||
tPrincipal[(matchedAlready + 2) % 3] =
|
||||
principal[(matchedAlready + 1) % 3]*-sense;
|
||||
|
||||
principal = tPrincipal;
|
||||
|
||||
vector tEVal = eVal;
|
||||
|
||||
tEVal[(matchedAlready + 1) % 3] = eVal[(matchedAlready + 2) % 3];
|
||||
|
||||
tEVal[(matchedAlready + 2) % 3] = eVal[(matchedAlready + 1) % 3];
|
||||
|
||||
eVal = tEVal;
|
||||
}
|
||||
|
||||
eVec = tensor(principal[0], principal[1], principal[2]);
|
||||
|
||||
// {
|
||||
// tensor R = rotationTensor(vector(1, 0, 0), eVec.x());
|
||||
|
||||
// R = rotationTensor(R & vector(0, 1, 0), eVec.y()) & R;
|
||||
|
||||
// Info<< "R = " << nl << R << endl;
|
||||
|
||||
// Info<< "R - eVec.T() " << R - eVec.T() << endl;
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
WarningIn(args.executable() + "::main")
|
||||
<< "Non-unique eigenvectors, cannot compute transformation "
|
||||
<< "from Cartesian axes" << endl;
|
||||
|
||||
showTransform = false;
|
||||
}
|
||||
|
||||
// calculate the total surface area
|
||||
|
||||
scalar surfaceArea = 0;
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
const labelledTri& f = surf[faceI];
|
||||
|
||||
if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
|
||||
{
|
||||
WarningIn(args.executable())
|
||||
<< "Illegal triangle " << faceI << " vertices " << f
|
||||
<< " coords " << f.points(surf.points()) << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
surfaceArea += triPointRef
|
||||
(
|
||||
surf.points()[f[0]],
|
||||
surf.points()[f[1]],
|
||||
surf.points()[f[2]]
|
||||
).mag();
|
||||
}
|
||||
}
|
||||
|
||||
Info<< nl << setprecision(12)
|
||||
<< "Density: " << density << nl
|
||||
<< "Mass: " << m << nl
|
||||
<< "Centre of mass: " << cM << nl
|
||||
<< "Surface area: " << surfaceArea << nl
|
||||
<< "Inertia tensor around centre of mass: " << nl << J << nl
|
||||
<< "eigenValues (principal moments): " << eVal << nl
|
||||
<< "eigenVectors (principal axes): " << nl
|
||||
<< eVec.x() << nl << eVec.y() << nl << eVec.z() << endl;
|
||||
|
||||
if (showTransform)
|
||||
{
|
||||
Info<< "Transform tensor from reference state (orientation):" << nl
|
||||
<< eVec.T() << nl
|
||||
<< "Rotation tensor required to transform "
|
||||
"from the body reference frame to the global "
|
||||
"reference frame, i.e.:" << nl
|
||||
<< "globalVector = orientation & bodyLocalVector"
|
||||
<< endl;
|
||||
|
||||
Info<< nl
|
||||
<< "Entries for sixDoFRigidBodyDisplacement boundary condition:"
|
||||
<< nl
|
||||
<< " mass " << m << token::END_STATEMENT << nl
|
||||
<< " centreOfMass " << cM << token::END_STATEMENT << nl
|
||||
<< " momentOfInertia " << eVal << token::END_STATEMENT << nl
|
||||
<< " orientation " << eVec.T() << token::END_STATEMENT
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (calcAroundRefPt)
|
||||
{
|
||||
Info<< nl << "Inertia tensor relative to " << refPt << ": " << nl
|
||||
<< momentOfInertia::applyParallelAxisTheorem(m, cM, J, refPt)
|
||||
<< endl;
|
||||
}
|
||||
|
||||
OFstream str("axes.obj");
|
||||
|
||||
Info<< nl << "Writing scaled principal axes at centre of mass of "
|
||||
<< surfFileName << " to " << str.name() << endl;
|
||||
|
||||
scalar scale = mag(cM - surf.points()[0])/eVal.component(findMin(eVal));
|
||||
|
||||
meshTools::writeOBJ(str, cM);
|
||||
meshTools::writeOBJ(str, cM + scale*eVal.x()*eVec.x());
|
||||
meshTools::writeOBJ(str, cM + scale*eVal.y()*eVec.y());
|
||||
meshTools::writeOBJ(str, cM + scale*eVal.z()*eVec.z());
|
||||
|
||||
for (label i = 1; i < 4; i++)
|
||||
{
|
||||
str << "l " << 1 << ' ' << i + 1 << endl;
|
||||
}
|
||||
|
||||
Info<< nl << "End" << nl << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceLambdaMuSmooth.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceLambdaMuSmooth
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude \
|
||||
-I$(LIB_SRC)/edgeMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ledgeMesh \
|
||||
-lsurfMesh
|
||||
@ -0,0 +1,237 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceLambdaMuSmooth
|
||||
|
||||
Description
|
||||
Smooths a surface using lambda/mu smoothing.
|
||||
|
||||
To get laplacian smoothing, set lambda to the relaxation factor and mu to
|
||||
zero.
|
||||
|
||||
Provide an edgeMesh file containing points that are not to be moved during
|
||||
smoothing in order to preserve features.
|
||||
|
||||
lambda/mu smoothing: G. Taubin, IBM Research report Rc-19923 (02/01/95)
|
||||
"A signal processing approach to fair surface design"
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "boundBox.H"
|
||||
#include "edgeMesh.H"
|
||||
#include "matchPoints.H"
|
||||
#include "MeshedSurfaces.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
tmp<pointField> avg
|
||||
(
|
||||
const meshedSurface& s,
|
||||
const PackedBoolList& fixedPoints
|
||||
)
|
||||
{
|
||||
const labelListList& pointEdges = s.pointEdges();
|
||||
|
||||
tmp<pointField> tavg(new pointField(s.nPoints(), vector::zero));
|
||||
pointField& avg = tavg();
|
||||
|
||||
forAll(pointEdges, vertI)
|
||||
{
|
||||
vector& avgPos = avg[vertI];
|
||||
|
||||
if (fixedPoints[vertI])
|
||||
{
|
||||
avgPos = s.localPoints()[vertI];
|
||||
}
|
||||
else
|
||||
{
|
||||
const labelList& pEdges = pointEdges[vertI];
|
||||
|
||||
forAll(pEdges, myEdgeI)
|
||||
{
|
||||
const edge& e = s.edges()[pEdges[myEdgeI]];
|
||||
|
||||
label otherVertI = e.otherVertex(vertI);
|
||||
|
||||
avgPos += s.localPoints()[otherVertI];
|
||||
}
|
||||
|
||||
avgPos /= pEdges.size();
|
||||
}
|
||||
}
|
||||
|
||||
return tavg;
|
||||
}
|
||||
|
||||
|
||||
void getFixedPoints
|
||||
(
|
||||
const edgeMesh& feMesh,
|
||||
const pointField& points,
|
||||
PackedBoolList& fixedPoints
|
||||
)
|
||||
{
|
||||
scalarList matchDistance(feMesh.points().size(), 1e-1);
|
||||
labelList from0To1;
|
||||
|
||||
bool matchedAll = matchPoints
|
||||
(
|
||||
feMesh.points(),
|
||||
points,
|
||||
matchDistance,
|
||||
false,
|
||||
from0To1
|
||||
);
|
||||
|
||||
if (!matchedAll)
|
||||
{
|
||||
WarningIn("getFixedPoints(const edgeMesh&, const pointField&)")
|
||||
<< "Did not match all feature points to points on the surface"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
forAll(from0To1, fpI)
|
||||
{
|
||||
if (from0To1[fpI] != -1)
|
||||
{
|
||||
fixedPoints[from0To1[fpI]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validOptions.clear();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("lambda (0..1)");
|
||||
argList::validArgs.append("mu (0..1)");
|
||||
argList::validArgs.append("iterations");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList::addOption
|
||||
(
|
||||
"featureFile",
|
||||
"fix points from a file containing feature points and edges"
|
||||
);
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const scalar lambda = args.argRead<scalar>(2);
|
||||
const scalar mu = args.argRead<scalar>(3);
|
||||
const label iters = args.argRead<label>(4);
|
||||
const fileName outFileName = args[5];
|
||||
|
||||
if (lambda < 0 || lambda > 1)
|
||||
{
|
||||
FatalErrorIn(args.executable()) << "Illegal relaxation factor "
|
||||
<< lambda << endl
|
||||
<< "0: no change 1: move vertices to average of neighbours"
|
||||
<< exit(FatalError);
|
||||
}
|
||||
if (mu < 0 || mu > 1)
|
||||
{
|
||||
FatalErrorIn(args.executable()) << "Illegal relaxation factor "
|
||||
<< mu << endl
|
||||
<< "0: no change 1: move vertices to average of neighbours"
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
Info<< "lambda : " << lambda << nl
|
||||
<< "mu : " << mu << nl
|
||||
<< "Iters : " << iters << nl
|
||||
<< "Reading surface from " << surfFileName << " ..." << endl;
|
||||
|
||||
meshedSurface surf1(surfFileName);
|
||||
|
||||
Info<< "Faces : " << surf1.size() << nl
|
||||
<< "Vertices : " << surf1.nPoints() << nl
|
||||
<< "Bounding Box: " << boundBox(surf1.localPoints()) << endl;
|
||||
|
||||
PackedBoolList fixedPoints(surf1.localPoints().size(), false);
|
||||
|
||||
if (args.optionFound("featureFile"))
|
||||
{
|
||||
const fileName featureFileName(args.option("featureFile"));
|
||||
Info<< "Reading features from " << featureFileName << " ..." << endl;
|
||||
|
||||
edgeMesh feMesh(featureFileName);
|
||||
|
||||
getFixedPoints(feMesh, surf1.localPoints(), fixedPoints);
|
||||
|
||||
Info<< "Number of fixed points on surface = " << fixedPoints.count()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
pointField newPoints(surf1.localPoints());
|
||||
|
||||
for (label iter = 0; iter < iters; iter++)
|
||||
{
|
||||
// Lambda
|
||||
{
|
||||
pointField newLocalPoints
|
||||
(
|
||||
(1 - lambda)*surf1.localPoints()
|
||||
+ lambda*avg(surf1, fixedPoints)
|
||||
);
|
||||
|
||||
pointField newPoints(surf1.points());
|
||||
UIndirectList<point>(newPoints, surf1.meshPoints()) =
|
||||
newLocalPoints;
|
||||
|
||||
surf1.movePoints(newPoints);
|
||||
}
|
||||
|
||||
// Mu
|
||||
if (mu != 0)
|
||||
{
|
||||
pointField newLocalPoints
|
||||
(
|
||||
(1 + mu)*surf1.localPoints()
|
||||
- mu*avg(surf1, fixedPoints)
|
||||
);
|
||||
|
||||
pointField newPoints(surf1.points());
|
||||
UIndirectList<point>(newPoints, surf1.meshPoints()) =
|
||||
newLocalPoints;
|
||||
|
||||
surf1.movePoints(newPoints);
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "Writing surface to " << outFileName << " ..." << endl;
|
||||
surf1.write(outFileName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceMeshConvert.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceMeshConvert
|
||||
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = -lmeshTools -lsurfMesh
|
||||
@ -0,0 +1,83 @@
|
||||
/*--------------------------------*- 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 IOPtrList<coordinateSystem>;
|
||||
object coordinateSystems;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
7
|
||||
(
|
||||
system_9
|
||||
{
|
||||
type cartesian;
|
||||
origin (1.03291515 -0.114391257 -0.0826236662);
|
||||
e3 (1 0 0);
|
||||
e1 (0 1 0);
|
||||
// STARCDRotation (0 90 90);
|
||||
}
|
||||
|
||||
system_10
|
||||
{
|
||||
type cartesian;
|
||||
origin (0.623151719 -0.286472935 -0.113933262);
|
||||
e3 (0.99508851 0.09829095 0.01173645);
|
||||
e1 (0.01179356 0 -0.99993045);
|
||||
// STARCDRotation (5.6403745 -0.0664172952 89.3275351);
|
||||
}
|
||||
|
||||
system_15
|
||||
{
|
||||
type cartesian;
|
||||
origin (0.644772231 -0.240036493 0.155972187);
|
||||
e3 (-0.01346388 -0.90616979 -0.42269969);
|
||||
e1 (0.00627978 0.42265304 -0.90626981);
|
||||
// STARCDRotation (-90.8512386 0 115.005148);
|
||||
}
|
||||
|
||||
system_16
|
||||
{
|
||||
type cartesian;
|
||||
origin (0.540824938 -0.240036415 0.15928296);
|
||||
e3 (-0.01346388 -0.90616979 -0.42269969);
|
||||
e1 (0.00627978 0.42265304 -0.90626981);
|
||||
// STARCDRotation (-90.8512386 0 115.005148);
|
||||
}
|
||||
|
||||
system_17
|
||||
{
|
||||
type cartesian;
|
||||
origin (0.436877646 -0.240036339 0.162593737);
|
||||
e3 (-0.01346388 -0.90616979 -0.42269969);
|
||||
e1 (0.00627978 0.42265304 -0.90626981);
|
||||
// STARCDRotation (-90.8512386 0 115.005148);
|
||||
}
|
||||
|
||||
system_18
|
||||
{
|
||||
type cartesian;
|
||||
origin (0.332930354 -0.240036261 0.16590451);
|
||||
e3 (-0.01346388 -0.90616979 -0.42269969);
|
||||
e1 (0.00627978 0.42265304 -0.90626981);
|
||||
// STARCDRotation (-90.8512386 0 115.005148);
|
||||
}
|
||||
|
||||
system_21
|
||||
{
|
||||
type cartesian;
|
||||
origin (0.55863733 -0.300866705 0.00317260982);
|
||||
e3 (0.42110287 0.02470132 -0.90667647);
|
||||
e1 (0.90646036 0.02342535 0.42164069);
|
||||
// STARCDRotation (-178.185897 -0.71772221 -155.059695);
|
||||
}
|
||||
)
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
@ -0,0 +1,302 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceMeshConvert
|
||||
|
||||
Description
|
||||
Converts between surface formats with optional scaling or
|
||||
transformations (rotate/translate) on a coordinateSystem.
|
||||
|
||||
Usage
|
||||
- surfaceMeshConvert inputFile outputFile [OPTION]
|
||||
|
||||
\param -clean \n
|
||||
Perform some surface checking/cleanup on the input surface.
|
||||
|
||||
\param -scaleIn \<scale\> \n
|
||||
Specify a scaling factor when reading files.
|
||||
|
||||
\param -scaleOut \<scale\> \n
|
||||
Specify a scaling factor when writing files.
|
||||
|
||||
\param -dict \<dictionary\> \n
|
||||
Specify an alternative dictionary for constant/coordinateSystems.
|
||||
|
||||
\param -from \<coordinateSystem\> \n
|
||||
Specify a coordinate System when reading files.
|
||||
|
||||
\param -to \<coordinateSystem\> \n
|
||||
Specify a coordinate System when writing files.
|
||||
|
||||
\param -tri \n
|
||||
Triangulate surface.
|
||||
|
||||
Note
|
||||
The filename extensions are used to determine the file format type.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
|
||||
#include "MeshedSurfaces.H"
|
||||
#include "coordinateSystems.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"convert between surface formats"
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("inputFile");
|
||||
argList::validArgs.append("outputFile");
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"clean",
|
||||
"perform some surface checking/cleanup on the input surface"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scaleIn",
|
||||
"factor",
|
||||
"geometry scaling factor on input"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scaleOut",
|
||||
"factor",
|
||||
"geometry scaling factor on output"
|
||||
);
|
||||
#include "addDictOption.H"
|
||||
argList::addOption
|
||||
(
|
||||
"from",
|
||||
"system",
|
||||
"specify the source coordinate system, applied after '-scaleIn'"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"to",
|
||||
"system",
|
||||
"specify the target coordinate system, applied before '-scaleOut'"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"tri",
|
||||
"triangulate surface"
|
||||
);
|
||||
|
||||
|
||||
argList args(argc, argv);
|
||||
Time runTime(args.rootPath(), args.caseName());
|
||||
|
||||
const fileName importName = args[1];
|
||||
const fileName exportName = args[2];
|
||||
|
||||
// disable inplace editing
|
||||
if (importName == exportName)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Output file " << exportName << " would overwrite input file."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// check that reading/writing is supported
|
||||
if
|
||||
(
|
||||
!MeshedSurface<face>::canRead(importName, true)
|
||||
|| !MeshedSurface<face>::canWriteType(exportName.ext(), true)
|
||||
)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// get the coordinate transformations
|
||||
autoPtr<coordinateSystem> fromCsys;
|
||||
autoPtr<coordinateSystem> toCsys;
|
||||
|
||||
if (args.optionFound("from") || args.optionFound("to"))
|
||||
{
|
||||
autoPtr<IOobject> csDictIoPtr;
|
||||
|
||||
const word dictName("coordinateSystems::typeName");
|
||||
|
||||
// Note: cannot use setSystemRunTimeDictionaryIO.H since dictionary
|
||||
// is in constant
|
||||
|
||||
fileName dictPath = "";
|
||||
if (args.optionFound("dict"))
|
||||
{
|
||||
dictPath = args["dict"];
|
||||
if (isDir(dictPath))
|
||||
{
|
||||
dictPath = dictPath / dictName;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictPath.size())
|
||||
{
|
||||
csDictIoPtr.set
|
||||
(
|
||||
new IOobject
|
||||
(
|
||||
dictPath,
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
csDictIoPtr.set
|
||||
(
|
||||
new IOobject
|
||||
(
|
||||
dictName,
|
||||
runTime.constant(),
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!csDictIoPtr->headerOk())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot open coordinateSystems file\n "
|
||||
<< csDictIoPtr->objectPath() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
coordinateSystems csLst(csDictIoPtr());
|
||||
|
||||
if (args.optionFound("from"))
|
||||
{
|
||||
const word csName = args["from"];
|
||||
|
||||
const label csIndex = csLst.findIndex(csName);
|
||||
if (csIndex < 0)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot find -from " << csName << nl
|
||||
<< "available coordinateSystems: " << csLst.toc() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
fromCsys.reset(new coordinateSystem(csLst[csIndex]));
|
||||
}
|
||||
|
||||
if (args.optionFound("to"))
|
||||
{
|
||||
const word csName = args["to"];
|
||||
|
||||
const label csIndex = csLst.findIndex(csName);
|
||||
if (csIndex < 0)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot find -to " << csName << nl
|
||||
<< "available coordinateSystems: " << csLst.toc() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
toCsys.reset(new coordinateSystem(csLst[csIndex]));
|
||||
}
|
||||
|
||||
|
||||
// maybe fix this later
|
||||
if (fromCsys.valid() && toCsys.valid())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Only allowed '-from' or '-to' option at the moment."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
MeshedSurface<face> surf(importName);
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
surf.cleanup(true);
|
||||
}
|
||||
|
||||
scalar scaleIn = 0;
|
||||
if (args.optionReadIfPresent("scaleIn", scaleIn) && scaleIn > 0)
|
||||
{
|
||||
Info<< " -scaleIn " << scaleIn << endl;
|
||||
surf.scalePoints(scaleIn);
|
||||
}
|
||||
|
||||
|
||||
if (fromCsys.valid())
|
||||
{
|
||||
Info<< " -from " << fromCsys().name() << endl;
|
||||
tmp<pointField> tpf = fromCsys().localPosition(surf.points());
|
||||
surf.movePoints(tpf());
|
||||
}
|
||||
|
||||
if (toCsys.valid())
|
||||
{
|
||||
Info<< " -to " << toCsys().name() << endl;
|
||||
tmp<pointField> tpf = toCsys().globalPosition(surf.points());
|
||||
surf.movePoints(tpf());
|
||||
}
|
||||
|
||||
scalar scaleOut = 0;
|
||||
if (args.optionReadIfPresent("scaleOut", scaleOut) && scaleOut > 0)
|
||||
{
|
||||
Info<< " -scaleOut " << scaleOut << endl;
|
||||
surf.scalePoints(scaleOut);
|
||||
}
|
||||
|
||||
if (args.optionFound("tri"))
|
||||
{
|
||||
Info<< "triangulate" << endl;
|
||||
surf.triangulate();
|
||||
}
|
||||
|
||||
Info<< "writing " << exportName;
|
||||
surf.write(exportName);
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceMeshConvertTesting.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceMeshConvertTesting
|
||||
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = -ltriSurface -lsurfMesh
|
||||
@ -0,0 +1,424 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceMeshConvertTesting
|
||||
|
||||
Description
|
||||
Converts from one surface mesh format to another, but primarily
|
||||
used for testing functionality.
|
||||
|
||||
Usage
|
||||
- surfaceMeshConvertTesting inputFile outputFile [OPTION]
|
||||
|
||||
\param -clean \n
|
||||
Perform some surface checking/cleanup on the input surface
|
||||
|
||||
\param -orient \n
|
||||
Check face orientation on the input surface
|
||||
|
||||
\param -scale \<scale\> \n
|
||||
Specify a scaling factor for writing the files
|
||||
|
||||
\param -triSurface \n
|
||||
Use triSurface library for input/output
|
||||
|
||||
\param -keyed \n
|
||||
Use keyedSurface for input/output
|
||||
|
||||
Note
|
||||
The filename extensions are used to determine the file format type.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "polyMesh.H"
|
||||
#include "triSurface.H"
|
||||
#include "surfMesh.H"
|
||||
#include "surfFields.H"
|
||||
#include "surfPointFields.H"
|
||||
#include "PackedBoolList.H"
|
||||
|
||||
#include "MeshedSurfaces.H"
|
||||
#include "UnsortedMeshedSurfaces.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"convert between surface formats, "
|
||||
"but primarily for testing functionality\n"
|
||||
"Normally use surfaceMeshConvert instead."
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("inputFile");
|
||||
argList::validArgs.append("outputFile");
|
||||
|
||||
argList::addBoolOption("clean");
|
||||
argList::addBoolOption("orient");
|
||||
argList::addBoolOption("surfMesh");
|
||||
argList::addBoolOption("triSurface");
|
||||
argList::addBoolOption("unsorted");
|
||||
argList::addBoolOption("triFace");
|
||||
|
||||
argList::addOption
|
||||
(
|
||||
"scale",
|
||||
"factor",
|
||||
"geometry scaling factor - default is 1"
|
||||
);
|
||||
|
||||
# include "setRootCase.H"
|
||||
|
||||
const scalar scaleFactor = args.optionLookupOrDefault("scale", 0.0);
|
||||
|
||||
const fileName importName = args[1];
|
||||
const fileName exportName = args[2];
|
||||
|
||||
if (importName == exportName)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Output file " << exportName << " would overwrite input file."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
!MeshedSurface<face>::canRead(importName, true)
|
||||
|| !MeshedSurface<face>::canWriteType(exportName.ext(), true)
|
||||
)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (args.optionFound("triSurface"))
|
||||
{
|
||||
triSurface surf(importName);
|
||||
|
||||
Info<< "Read surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
if (args.optionFound("orient"))
|
||||
{
|
||||
Info<< "Checking surface orientation" << endl;
|
||||
PatchTools::checkOrientation(surf, true);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
Info<< "Cleaning up surface" << endl;
|
||||
surf.cleanup(true);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
Info<< "writing " << exportName;
|
||||
if (scaleFactor <= 0)
|
||||
{
|
||||
Info<< " without scaling" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< " with scaling " << scaleFactor << endl;
|
||||
surf.scalePoints(scaleFactor);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
// write sorted by region
|
||||
surf.write(exportName, true);
|
||||
}
|
||||
else if (args.optionFound("unsorted"))
|
||||
{
|
||||
UnsortedMeshedSurface<face> surf(importName);
|
||||
|
||||
Info<< "Read surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
if (args.optionFound("orient"))
|
||||
{
|
||||
Info<< "Checking surface orientation" << endl;
|
||||
PatchTools::checkOrientation(surf, true);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
Info<< "Cleaning up surface" << endl;
|
||||
surf.cleanup(true);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
Info<< "writing " << exportName;
|
||||
if (scaleFactor <= 0)
|
||||
{
|
||||
Info<< " without scaling" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< " with scaling " << scaleFactor << endl;
|
||||
surf.scalePoints(scaleFactor);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
surf.write(exportName);
|
||||
}
|
||||
#if 1
|
||||
else if (args.optionFound("triFace"))
|
||||
{
|
||||
MeshedSurface<triFace> surf(importName);
|
||||
|
||||
Info<< "Read surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
if (args.optionFound("orient"))
|
||||
{
|
||||
Info<< "Checking surface orientation" << endl;
|
||||
PatchTools::checkOrientation(surf, true);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
Info<< "Cleaning up surface" << endl;
|
||||
surf.cleanup(true);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
Info<< "writing " << exportName;
|
||||
if (scaleFactor <= 0)
|
||||
{
|
||||
Info<< " without scaling" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< " with scaling " << scaleFactor << endl;
|
||||
surf.scalePoints(scaleFactor);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
surf.write(exportName);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
MeshedSurface<face> surf(importName);
|
||||
|
||||
Info<< "Read surface:" << endl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
if (args.optionFound("orient"))
|
||||
{
|
||||
Info<< "Checking surface orientation" << endl;
|
||||
PatchTools::checkOrientation(surf, true);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
Info<< "Cleaning up surface" << endl;
|
||||
surf.cleanup(true);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
|
||||
Info<< "writing " << exportName;
|
||||
if (scaleFactor <= 0)
|
||||
{
|
||||
Info<< " without scaling" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< " with scaling " << scaleFactor << endl;
|
||||
surf.scalePoints(scaleFactor);
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
}
|
||||
surf.write(exportName);
|
||||
|
||||
if (args.optionFound("surfMesh"))
|
||||
{
|
||||
Foam::Time runTime
|
||||
(
|
||||
args.rootPath(),
|
||||
args.caseName()
|
||||
);
|
||||
|
||||
// start with "constant"
|
||||
runTime.setTime(instant(0, runTime.constant()), 0);
|
||||
|
||||
Info<< "runTime.instance() = " << runTime.instance() << endl;
|
||||
Info<< "runTime.timeName() = " << runTime.timeName() << endl;
|
||||
|
||||
|
||||
Info<< "write MeshedSurface 'yetAnother' via proxy as surfMesh"
|
||||
<< endl;
|
||||
surf.write
|
||||
(
|
||||
runTime,
|
||||
"yetAnother"
|
||||
);
|
||||
|
||||
surfMesh surfIn
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"default",
|
||||
runTime.timeName(),
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
MeshedSurface<face> surfIn2(runTime, "foobar");
|
||||
|
||||
Info<<"surfIn2 = " << surfIn2.size() << endl;
|
||||
|
||||
Info<< "surfIn = " << surfIn.size() << endl;
|
||||
|
||||
|
||||
Info<< "writing surfMesh as obj = oldSurfIn.obj" << endl;
|
||||
surfIn.write("oldSurfIn.obj");
|
||||
|
||||
|
||||
Info<< "runTime.instance() = " << runTime.instance() << endl;
|
||||
|
||||
surfMesh surfOut
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"mySurf",
|
||||
runTime.instance(),
|
||||
runTime,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
surf.xfer()
|
||||
);
|
||||
|
||||
Info<< "writing surfMesh as well: " << surfOut.objectPath() << endl;
|
||||
surfOut.write();
|
||||
|
||||
surfLabelField zoneIds
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"zoneIds",
|
||||
surfOut.instance(),
|
||||
surfOut,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE
|
||||
),
|
||||
surfOut,
|
||||
dimless
|
||||
);
|
||||
|
||||
Info<<" surf name= " << surfOut.name() <<nl;
|
||||
Info<< "rename to anotherSurf" << endl;
|
||||
surfOut.rename("anotherSurf");
|
||||
|
||||
Info<<" surf name= " << surfOut.name() <<nl;
|
||||
|
||||
// advance time to 1
|
||||
runTime.setTime(instant(1), 1);
|
||||
surfOut.setInstance(runTime.timeName());
|
||||
|
||||
|
||||
|
||||
Info<< "writing surfMesh again well: " << surfOut.objectPath()
|
||||
<< endl;
|
||||
surfOut.write();
|
||||
|
||||
// write directly
|
||||
surfOut.write("someName.ofs");
|
||||
|
||||
#if 1
|
||||
const surfZoneList& zones = surfOut.surfZones();
|
||||
forAll(zones, zoneI)
|
||||
{
|
||||
SubList<label>
|
||||
(
|
||||
zoneIds,
|
||||
zones[zoneI].size(),
|
||||
zones[zoneI].start()
|
||||
) = zoneI;
|
||||
}
|
||||
|
||||
Info<< "write zoneIds (for testing only): "
|
||||
<< zoneIds.objectPath() << endl;
|
||||
zoneIds.write();
|
||||
|
||||
surfPointLabelField pointIds
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"zoneIds.",
|
||||
// "pointIds",
|
||||
surfOut.instance(),
|
||||
// "pointFields",
|
||||
surfOut,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE
|
||||
),
|
||||
surfOut,
|
||||
dimless
|
||||
);
|
||||
|
||||
forAll(pointIds, i)
|
||||
{
|
||||
pointIds[i] = i;
|
||||
}
|
||||
|
||||
Info<< "write pointIds (for testing only): "
|
||||
<< pointIds.objectPath() << endl;
|
||||
pointIds.write();
|
||||
|
||||
Info<<"surfMesh with these names: " << surfOut.names() << endl;
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceMeshExport.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceMeshExport
|
||||
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = -lmeshTools -lsurfMesh
|
||||
@ -0,0 +1,294 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceMeshExport
|
||||
|
||||
Description
|
||||
Export from surfMesh to various third-party surface formats with
|
||||
optional scaling or transformations (rotate/translate) on a
|
||||
coordinateSystem.
|
||||
|
||||
Usage
|
||||
- surfaceMeshExport outputFile [OPTION]
|
||||
|
||||
\param -clean \n
|
||||
Perform some surface checking/cleanup on the input surface.
|
||||
|
||||
\param -name \<name\> \n
|
||||
Specify an alternative surface name when writing.
|
||||
|
||||
\param -scaleIn \<scale\> \n
|
||||
Specify a scaling factor when reading files.
|
||||
|
||||
\param -scaleOut \<scale\> \n
|
||||
Specify a scaling factor when writing files.
|
||||
|
||||
\param -dict \<dictionary\> \n
|
||||
Specify an alternative dictionary for constant/coordinateSystems.
|
||||
|
||||
\param -from \<coordinateSystem\> \n
|
||||
Specify a coordinate system when reading files.
|
||||
|
||||
\param -to \<coordinateSystem\> \n
|
||||
Specify a coordinate system when writing files.
|
||||
|
||||
Note
|
||||
The filename extensions are used to determine the file format type.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
|
||||
#include "MeshedSurfaces.H"
|
||||
#include "coordinateSystems.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"export from surfMesh to various third-party surface formats"
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("outputFile");
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"clean",
|
||||
"perform some surface checking/cleanup on the input surface"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"name",
|
||||
"name",
|
||||
"specify an alternative surface name when reading - "
|
||||
"default is 'default'"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scaleIn",
|
||||
"factor",
|
||||
"geometry scaling factor on input - default is 1"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scaleOut",
|
||||
"factor",
|
||||
"geometry scaling factor on output - default is 1"
|
||||
);
|
||||
#include "addDictOption.H"
|
||||
argList::addOption
|
||||
(
|
||||
"from",
|
||||
"coordinateSystem",
|
||||
"specify the source coordinate system, applied after '-scaleIn'"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"to",
|
||||
"coordinateSystem",
|
||||
"specify the target coordinate system, applied before '-scaleOut'"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
Time runTime(args.rootPath(), args.caseName());
|
||||
|
||||
const fileName exportName = args[1];
|
||||
const word importName = args.optionLookupOrDefault<word>("name", "default");
|
||||
|
||||
// check that writing is supported
|
||||
if (!MeshedSurface<face>::canWriteType(exportName.ext(), true))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// get the coordinate transformations
|
||||
autoPtr<coordinateSystem> fromCsys;
|
||||
autoPtr<coordinateSystem> toCsys;
|
||||
|
||||
if (args.optionFound("from") || args.optionFound("to"))
|
||||
{
|
||||
autoPtr<IOobject> ioPtr;
|
||||
|
||||
if (args.optionFound("dict"))
|
||||
{
|
||||
const fileName dictPath = args["dict"];
|
||||
|
||||
ioPtr.set
|
||||
(
|
||||
new IOobject
|
||||
(
|
||||
(
|
||||
isDir(dictPath)
|
||||
? dictPath/coordinateSystems::typeName
|
||||
: dictPath
|
||||
),
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioPtr.set
|
||||
(
|
||||
new IOobject
|
||||
(
|
||||
coordinateSystems::typeName,
|
||||
runTime.constant(),
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!ioPtr->headerOk())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot open coordinateSystems file\n "
|
||||
<< ioPtr->objectPath() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
coordinateSystems csLst(ioPtr());
|
||||
|
||||
if (args.optionFound("from"))
|
||||
{
|
||||
const word csName = args["from"];
|
||||
|
||||
const label csIndex = csLst.findIndex(csName);
|
||||
if (csIndex < 0)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot find -from " << csName << nl
|
||||
<< "available coordinateSystems: " << csLst.toc() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
fromCsys.reset(new coordinateSystem(csLst[csIndex]));
|
||||
}
|
||||
|
||||
if (args.optionFound("to"))
|
||||
{
|
||||
const word csName = args["to"];
|
||||
|
||||
const label csIndex = csLst.findIndex(csName);
|
||||
if (csIndex < 0)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot find -to " << csName << nl
|
||||
<< "available coordinateSystems: " << csLst.toc() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
toCsys.reset(new coordinateSystem(csLst[csIndex]));
|
||||
}
|
||||
|
||||
|
||||
// maybe fix this later
|
||||
if (fromCsys.valid() && toCsys.valid())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Only allowed '-from' or '-to' option at the moment."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
surfMesh smesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
importName,
|
||||
runTime.constant(),
|
||||
runTime,
|
||||
IOobject::MUST_READ_IF_MODIFIED,
|
||||
IOobject::NO_WRITE
|
||||
)
|
||||
);
|
||||
|
||||
Info<< "read surfMesh:\n " << smesh.objectPath() << endl;
|
||||
|
||||
|
||||
// Simply copy for now, but really should have a separate write method
|
||||
|
||||
MeshedSurface<face> surf(smesh);
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
surf.cleanup(true);
|
||||
}
|
||||
|
||||
scalar scaleIn = 0;
|
||||
if (args.optionReadIfPresent("scaleIn", scaleIn) && scaleIn > 0)
|
||||
{
|
||||
Info<< " -scaleIn " << scaleIn << endl;
|
||||
surf.scalePoints(scaleIn);
|
||||
}
|
||||
|
||||
if (fromCsys.valid())
|
||||
{
|
||||
Info<< " -from " << fromCsys().name() << endl;
|
||||
tmp<pointField> tpf = fromCsys().localPosition(surf.points());
|
||||
surf.movePoints(tpf());
|
||||
}
|
||||
|
||||
if (toCsys.valid())
|
||||
{
|
||||
Info<< " -to " << toCsys().name() << endl;
|
||||
tmp<pointField> tpf = toCsys().globalPosition(surf.points());
|
||||
surf.movePoints(tpf());
|
||||
}
|
||||
|
||||
scalar scaleOut = 0;
|
||||
if (args.optionReadIfPresent("scaleOut", scaleOut) && scaleOut > 0)
|
||||
{
|
||||
Info<< " -scaleOut " << scaleOut << endl;
|
||||
surf.scalePoints(scaleOut);
|
||||
}
|
||||
|
||||
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
|
||||
Info<< "writing " << exportName << endl;
|
||||
surf.write(exportName);
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceMeshImport.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceMeshImport
|
||||
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = -lmeshTools -lsurfMesh
|
||||
@ -0,0 +1,300 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceMeshImport
|
||||
|
||||
Description
|
||||
Import from various third-party surface formats into surfMesh
|
||||
with optional scaling or transformations (rotate/translate)
|
||||
on a coordinateSystem.
|
||||
|
||||
Usage
|
||||
- surfaceMeshImport inputFile [OPTION]
|
||||
|
||||
\param -clean \n
|
||||
Perform some surface checking/cleanup on the input surface.
|
||||
|
||||
\param -name \<name\> \n
|
||||
Specify an alternative surface name when writing.
|
||||
|
||||
\param -scaleIn \<scale\> \n
|
||||
Specify a scaling factor when reading files.
|
||||
|
||||
\param -scaleOut \<scale\> \n
|
||||
Specify a scaling factor when writing files.
|
||||
|
||||
\param -dict \<dictionary\> \n
|
||||
Specify an alternative dictionary for constant/coordinateSystems.
|
||||
|
||||
\param -from \<coordinateSystem\> \n
|
||||
Specify a coordinate system when reading files.
|
||||
|
||||
\param -to \<coordinateSystem\> \n
|
||||
Specify a coordinate system when writing files.
|
||||
|
||||
Note
|
||||
The filename extensions are used to determine the file format type.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
|
||||
#include "MeshedSurfaces.H"
|
||||
#include "coordinateSystems.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"import from various third-party surface formats into surfMesh"
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("inputFile");
|
||||
|
||||
argList::addBoolOption
|
||||
(
|
||||
"clean",
|
||||
"perform some surface checking/cleanup on the input surface"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"name",
|
||||
"name",
|
||||
"specify an alternative surface name when writing - "
|
||||
"default is 'default'"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scaleIn",
|
||||
"factor",
|
||||
"geometry scaling factor on input - default is 1"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"scaleOut",
|
||||
"factor",
|
||||
"geometry scaling factor on output - default is 1"
|
||||
);
|
||||
#include "addDictOption.H"
|
||||
argList::addOption
|
||||
(
|
||||
"from",
|
||||
"coordinateSystem",
|
||||
"specify a local coordinate system when reading files."
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"to",
|
||||
"coordinateSystem",
|
||||
"specify a local coordinate system when writing files."
|
||||
);
|
||||
|
||||
#include "setRootCase.H"
|
||||
#include "createTime.H"
|
||||
|
||||
// try for the latestTime, but create "constant" as needed
|
||||
instantList Times = runTime.times();
|
||||
if (Times.size())
|
||||
{
|
||||
label startTime = Times.size()-1;
|
||||
runTime.setTime(Times[startTime], startTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
runTime.setTime(instant(0, runTime.constant()), 0);
|
||||
}
|
||||
|
||||
|
||||
const fileName importName = args[1];
|
||||
const word exportName = args.optionLookupOrDefault<word>("name", "default");
|
||||
|
||||
// check that reading is supported
|
||||
if (!MeshedSurface<face>::canRead(importName, true))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// get the coordinate transformations
|
||||
autoPtr<coordinateSystem> fromCsys;
|
||||
autoPtr<coordinateSystem> toCsys;
|
||||
|
||||
if (args.optionFound("from") || args.optionFound("to"))
|
||||
{
|
||||
autoPtr<IOobject> ioPtr;
|
||||
|
||||
if (args.optionFound("dict"))
|
||||
{
|
||||
const fileName dictPath = args["dict"];
|
||||
|
||||
ioPtr.set
|
||||
(
|
||||
new IOobject
|
||||
(
|
||||
(
|
||||
isDir(dictPath)
|
||||
? dictPath/coordinateSystems::typeName
|
||||
: dictPath
|
||||
),
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioPtr.set
|
||||
(
|
||||
new IOobject
|
||||
(
|
||||
coordinateSystems::typeName,
|
||||
runTime.constant(),
|
||||
runTime,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!ioPtr->headerOk())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot open coordinateSystems file\n "
|
||||
<< ioPtr->objectPath() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
coordinateSystems csLst(ioPtr());
|
||||
|
||||
if (args.optionFound("from"))
|
||||
{
|
||||
const word csName = args["from"];
|
||||
|
||||
const label csIndex = csLst.findIndex(csName);
|
||||
if (csIndex < 0)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot find -from " << csName << nl
|
||||
<< "available coordinateSystems: " << csLst.toc() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
fromCsys.reset(new coordinateSystem(csLst[csIndex]));
|
||||
}
|
||||
|
||||
if (args.optionFound("to"))
|
||||
{
|
||||
const word csName = args["to"];
|
||||
|
||||
const label csIndex = csLst.findIndex(csName);
|
||||
if (csIndex < 0)
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Cannot find -to " << csName << nl
|
||||
<< "available coordinateSystems: " << csLst.toc() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
toCsys.reset(new coordinateSystem(csLst[csIndex]));
|
||||
}
|
||||
|
||||
|
||||
// maybe fix this later
|
||||
if (fromCsys.valid() && toCsys.valid())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Only allowed '-from' or '-to' option at the moment."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MeshedSurface<face> surf(importName);
|
||||
|
||||
if (args.optionFound("clean"))
|
||||
{
|
||||
surf.cleanup(true);
|
||||
}
|
||||
|
||||
|
||||
scalar scaleIn = 0;
|
||||
if (args.optionReadIfPresent("scaleIn", scaleIn) && scaleIn > 0)
|
||||
{
|
||||
Info<< " -scaleIn " << scaleIn << endl;
|
||||
surf.scalePoints(scaleIn);
|
||||
}
|
||||
|
||||
if (fromCsys.valid())
|
||||
{
|
||||
Info<< " -from " << fromCsys().name() << endl;
|
||||
tmp<pointField> tpf = fromCsys().localPosition(surf.points());
|
||||
surf.movePoints(tpf());
|
||||
}
|
||||
|
||||
if (toCsys.valid())
|
||||
{
|
||||
Info<< " -to " << toCsys().name() << endl;
|
||||
tmp<pointField> tpf = toCsys().globalPosition(surf.points());
|
||||
surf.movePoints(tpf());
|
||||
}
|
||||
|
||||
scalar scaleOut = 0;
|
||||
if (args.optionReadIfPresent("scaleOut", scaleOut) && scaleOut > 0)
|
||||
{
|
||||
Info<< " -scaleOut " << scaleOut << endl;
|
||||
surf.scalePoints(scaleOut);
|
||||
}
|
||||
|
||||
surfMesh smesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
exportName,
|
||||
runTime.constant(),
|
||||
runTime
|
||||
),
|
||||
surf.xfer()
|
||||
);
|
||||
|
||||
|
||||
Info<< "writing surfMesh:\n " << smesh.objectPath() << endl;
|
||||
smesh.write();
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceMeshInfo.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceMeshInfo
|
||||
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = -lmeshTools -lsurfMesh
|
||||
175
applications/utilities/surface/surfaceMeshInfo/surfaceMeshInfo.C
Normal file
175
applications/utilities/surface/surfaceMeshInfo/surfaceMeshInfo.C
Normal file
@ -0,0 +1,175 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceMeshInfo
|
||||
|
||||
Description
|
||||
Miscellaneous information about surface meshes.
|
||||
|
||||
Usage
|
||||
- surfaceMeshInfo surfaceFile [OPTION]
|
||||
|
||||
\param -areas \n
|
||||
Report area for each face.
|
||||
|
||||
\param -scale \<scale\> \n
|
||||
Specify a scaling factor when reading files.
|
||||
|
||||
\param -xml \n
|
||||
Write output in XML format.
|
||||
|
||||
Note
|
||||
The filename extensions are used to determine the file format type.
|
||||
|
||||
The XML-like output can be useful for extraction with other tools,
|
||||
but either output format can be easily extracted with a simple sed
|
||||
command:
|
||||
\verbatim
|
||||
surfaceMeshInfo surfaceFile -areas | \
|
||||
sed -ne '/areas/,/:/{ /:/!p }'
|
||||
|
||||
surfaceMeshInfo surfaceFile -areas -xml | \
|
||||
sed -ne '/<areas/,/</{ /</!p }'
|
||||
\endverbatim
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
|
||||
#include "UnsortedMeshedSurfaces.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"information about surface meshes"
|
||||
);
|
||||
|
||||
argList::noBanner();
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
|
||||
argList::addOption
|
||||
(
|
||||
"scale",
|
||||
"factor",
|
||||
"geometry scaling factor - default is 1"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"areas",
|
||||
"display area of each face"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"xml",
|
||||
"write output in XML format"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
Time runTime(args.rootPath(), args.caseName());
|
||||
|
||||
const fileName importName = args[1];
|
||||
|
||||
// check that reading is supported
|
||||
if (!UnsortedMeshedSurface<face>::canRead(importName, true))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const bool writeXML = args.optionFound("xml");
|
||||
const bool writeAreas = args.optionFound("areas");
|
||||
|
||||
|
||||
// use UnsortedMeshedSurface, not MeshedSurface to maintain ordering
|
||||
UnsortedMeshedSurface<face> surf(importName);
|
||||
|
||||
scalar scaling = 0;
|
||||
if (args.optionReadIfPresent("scale", scaling) && scaling > 0)
|
||||
{
|
||||
Info<< " -scale " << scaling << endl;
|
||||
surf.scalePoints(scaling);
|
||||
}
|
||||
|
||||
scalar areaTotal = 0;
|
||||
|
||||
if (writeXML)
|
||||
{
|
||||
Info<<"<?xml version='1.0' encoding='utf-8'?>" << nl
|
||||
<<"<surfaceMeshInfo>" << nl
|
||||
<< "<npoints>" << surf.nPoints() << "</npoints>" << nl
|
||||
<< "<nfaces>" << surf.size() << "</nfaces>" << nl;
|
||||
|
||||
if (writeAreas)
|
||||
{
|
||||
Info<<"<areas size='" << surf.size() << "'>" << nl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "nPoints : " << surf.nPoints() << nl
|
||||
<< "nFaces : " << surf.size() << nl;
|
||||
|
||||
if (writeAreas)
|
||||
{
|
||||
Info<< "areas : " << nl;
|
||||
}
|
||||
}
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
const scalar fArea(surf[faceI].mag(surf.points()));
|
||||
areaTotal += fArea;
|
||||
|
||||
if (writeAreas)
|
||||
{
|
||||
Info<< fArea << nl;
|
||||
}
|
||||
}
|
||||
|
||||
if (writeXML)
|
||||
{
|
||||
if (writeAreas)
|
||||
{
|
||||
Info<<"</areas>" << nl;
|
||||
}
|
||||
|
||||
Info<< "<area>" << areaTotal << "</area>" << nl
|
||||
<< "</surfaceMeshInfo>" << nl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "area : " << areaTotal << nl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceMeshTriangulate.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceMeshTriangulate
|
||||
@ -0,0 +1,8 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-lsurfMesh
|
||||
|
||||
@ -0,0 +1,377 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceMeshTriangulate
|
||||
|
||||
Description
|
||||
Extracts surface from a polyMesh. Depending on output surface format
|
||||
triangulates faces.
|
||||
|
||||
Region numbers on faces cannot be guaranteed to be the same as the patch
|
||||
indices.
|
||||
|
||||
Optionally only triangulates named patches.
|
||||
|
||||
If run in parallel the processor patches get filtered out by default and
|
||||
the mesh gets merged (based on topology).
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "MeshedSurface.H"
|
||||
#include "UnsortedMeshedSurface.H"
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "polyMesh.H"
|
||||
#include "processorPolyPatch.H"
|
||||
#include "ListListOps.H"
|
||||
#include "uindirectPrimitivePatch.H"
|
||||
#include "globalMeshData.H"
|
||||
#include "globalIndex.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"extract surface from a polyMesh"
|
||||
);
|
||||
argList::validArgs.append("output file");
|
||||
#include "addRegionOption.H"
|
||||
argList::addBoolOption
|
||||
(
|
||||
"excludeProcPatches",
|
||||
"exclude processor patches"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"patches",
|
||||
"(patch0 .. patchN)",
|
||||
"only triangulate selected patches (wildcards supported)"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"faceZones",
|
||||
"(fz0 .. fzN)",
|
||||
"triangulate selected faceZones (wildcards supported)"
|
||||
);
|
||||
|
||||
#include "setRootCase.H"
|
||||
#include "createTime.H"
|
||||
|
||||
const fileName outFileName(args[1]);
|
||||
|
||||
Info<< "Extracting surface from boundaryMesh ..."
|
||||
<< endl << endl;
|
||||
|
||||
const bool includeProcPatches =
|
||||
!(
|
||||
args.optionFound("excludeProcPatches")
|
||||
|| Pstream::parRun()
|
||||
);
|
||||
|
||||
if (includeProcPatches)
|
||||
{
|
||||
Info<< "Including all processor patches." << nl << endl;
|
||||
}
|
||||
else if (Pstream::parRun())
|
||||
{
|
||||
Info<< "Excluding all processor patches." << nl << endl;
|
||||
}
|
||||
|
||||
Info<< "Reading mesh from time " << runTime.value() << endl;
|
||||
|
||||
#include "createNamedPolyMesh.H"
|
||||
|
||||
|
||||
// Create local surface from:
|
||||
// - explicitly named patches only (-patches (at your option)
|
||||
// - all patches (default in sequential mode)
|
||||
// - all non-processor patches (default in parallel mode)
|
||||
// - all non-processor patches (sequential mode, -excludeProcPatches
|
||||
// (at your option)
|
||||
|
||||
// Construct table of patches to include.
|
||||
const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
|
||||
|
||||
labelHashSet includePatches(bMesh.size());
|
||||
|
||||
if (args.optionFound("patches"))
|
||||
{
|
||||
includePatches = bMesh.patchSet
|
||||
(
|
||||
wordReList(args.optionLookup("patches")())
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
forAll(bMesh, patchI)
|
||||
{
|
||||
const polyPatch& patch = bMesh[patchI];
|
||||
|
||||
if (includeProcPatches || !isA<processorPolyPatch>(patch))
|
||||
{
|
||||
includePatches.insert(patchI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const faceZoneMesh& fzm = mesh.faceZones();
|
||||
labelHashSet includeFaceZones(fzm.size());
|
||||
|
||||
if (args.optionFound("faceZones"))
|
||||
{
|
||||
wordReList zoneNames(args.optionLookup("faceZones")());
|
||||
const wordList allZoneNames(fzm.names());
|
||||
forAll(zoneNames, i)
|
||||
{
|
||||
const wordRe& zoneName = zoneNames[i];
|
||||
|
||||
labelList zoneIDs = findStrings(zoneName, allZoneNames);
|
||||
|
||||
forAll(zoneIDs, j)
|
||||
{
|
||||
includeFaceZones.insert(zoneIDs[j]);
|
||||
}
|
||||
|
||||
if (zoneIDs.empty())
|
||||
{
|
||||
WarningIn(args.executable())
|
||||
<< "Cannot find any faceZone name matching "
|
||||
<< zoneName << endl;
|
||||
}
|
||||
|
||||
}
|
||||
Info<< "Additionally triangulating faceZones "
|
||||
<< UIndirectList<word>(allZoneNames, includeFaceZones.sortedToc())
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// From (name of) patch to compact 'zone' index
|
||||
HashTable<label> compactZoneID(1000);
|
||||
// Mesh face and compact zone indx
|
||||
DynamicList<label> faceLabels;
|
||||
DynamicList<label> compactZones;
|
||||
|
||||
{
|
||||
// Collect sizes. Hash on names to handle local-only patches (e.g.
|
||||
// processor patches)
|
||||
HashTable<label> patchSize(1000);
|
||||
label nFaces = 0;
|
||||
forAllConstIter(labelHashSet, includePatches, iter)
|
||||
{
|
||||
const polyPatch& pp = bMesh[iter.key()];
|
||||
patchSize.insert(pp.name(), pp.size());
|
||||
nFaces += pp.size();
|
||||
}
|
||||
|
||||
HashTable<label> zoneSize(1000);
|
||||
forAllConstIter(labelHashSet, includeFaceZones, iter)
|
||||
{
|
||||
const faceZone& pp = fzm[iter.key()];
|
||||
zoneSize.insert(pp.name(), pp.size());
|
||||
nFaces += pp.size();
|
||||
}
|
||||
|
||||
|
||||
Pstream::mapCombineGather(patchSize, plusEqOp<label>());
|
||||
Pstream::mapCombineGather(zoneSize, plusEqOp<label>());
|
||||
|
||||
|
||||
// Allocate compact numbering for all patches/faceZones
|
||||
forAllConstIter(HashTable<label>, patchSize, iter)
|
||||
{
|
||||
label sz = compactZoneID.size();
|
||||
compactZoneID.insert(iter.key(), sz);
|
||||
}
|
||||
|
||||
forAllConstIter(HashTable<label>, zoneSize, iter)
|
||||
{
|
||||
label sz = compactZoneID.size();
|
||||
//Info<< "For faceZone " << iter.key() << " allocating zoneID "
|
||||
// << sz << endl;
|
||||
compactZoneID.insert(iter.key(), sz);
|
||||
}
|
||||
|
||||
|
||||
Pstream::mapCombineScatter(compactZoneID);
|
||||
|
||||
|
||||
// Rework HashTable into labelList just for speed of conversion
|
||||
labelList patchToCompactZone(bMesh.size(), -1);
|
||||
labelList faceZoneToCompactZone(bMesh.size(), -1);
|
||||
forAllConstIter(HashTable<label>, compactZoneID, iter)
|
||||
{
|
||||
label patchI = bMesh.findPatchID(iter.key());
|
||||
if (patchI != -1)
|
||||
{
|
||||
patchToCompactZone[patchI] = iter();
|
||||
}
|
||||
else
|
||||
{
|
||||
label zoneI = fzm.findZoneID(iter.key());
|
||||
faceZoneToCompactZone[zoneI] = iter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
faceLabels.setCapacity(nFaces);
|
||||
compactZones.setCapacity(nFaces);
|
||||
|
||||
// Collect faces on patches
|
||||
forAllConstIter(labelHashSet, includePatches, iter)
|
||||
{
|
||||
const polyPatch& pp = bMesh[iter.key()];
|
||||
forAll(pp, i)
|
||||
{
|
||||
faceLabels.append(pp.start()+i);
|
||||
compactZones.append(patchToCompactZone[pp.index()]);
|
||||
}
|
||||
}
|
||||
// Collect faces on faceZones
|
||||
forAllConstIter(labelHashSet, includeFaceZones, iter)
|
||||
{
|
||||
const faceZone& pp = fzm[iter.key()];
|
||||
forAll(pp, i)
|
||||
{
|
||||
faceLabels.append(pp[i]);
|
||||
compactZones.append(faceZoneToCompactZone[pp.index()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Addressing engine for all faces
|
||||
uindirectPrimitivePatch allBoundary
|
||||
(
|
||||
UIndirectList<face>(mesh.faces(), faceLabels),
|
||||
mesh.points()
|
||||
);
|
||||
|
||||
|
||||
// Find correspondence to master points
|
||||
labelList pointToGlobal;
|
||||
labelList uniqueMeshPoints;
|
||||
autoPtr<globalIndex> globalNumbers = mesh.globalData().mergePoints
|
||||
(
|
||||
allBoundary.meshPoints(),
|
||||
allBoundary.meshPointMap(),
|
||||
pointToGlobal,
|
||||
uniqueMeshPoints
|
||||
);
|
||||
|
||||
// Gather all unique points on master
|
||||
List<pointField> gatheredPoints(Pstream::nProcs());
|
||||
gatheredPoints[Pstream::myProcNo()] = pointField
|
||||
(
|
||||
mesh.points(),
|
||||
uniqueMeshPoints
|
||||
);
|
||||
Pstream::gatherList(gatheredPoints);
|
||||
|
||||
// Gather all faces
|
||||
List<faceList> gatheredFaces(Pstream::nProcs());
|
||||
gatheredFaces[Pstream::myProcNo()] = allBoundary.localFaces();
|
||||
forAll(gatheredFaces[Pstream::myProcNo()], i)
|
||||
{
|
||||
inplaceRenumber(pointToGlobal, gatheredFaces[Pstream::myProcNo()][i]);
|
||||
}
|
||||
Pstream::gatherList(gatheredFaces);
|
||||
|
||||
// Gather all ZoneIDs
|
||||
List<labelList> gatheredZones(Pstream::nProcs());
|
||||
gatheredZones[Pstream::myProcNo()] = compactZones.xfer();
|
||||
Pstream::gatherList(gatheredZones);
|
||||
|
||||
// On master combine all points, faces, zones
|
||||
if (Pstream::master())
|
||||
{
|
||||
pointField allPoints = ListListOps::combine<pointField>
|
||||
(
|
||||
gatheredPoints,
|
||||
accessOp<pointField>()
|
||||
);
|
||||
gatheredPoints.clear();
|
||||
|
||||
faceList allFaces = ListListOps::combine<faceList>
|
||||
(
|
||||
gatheredFaces,
|
||||
accessOp<faceList>()
|
||||
);
|
||||
gatheredFaces.clear();
|
||||
|
||||
labelList allZones = ListListOps::combine<labelList>
|
||||
(
|
||||
gatheredZones,
|
||||
accessOp<labelList>()
|
||||
);
|
||||
gatheredZones.clear();
|
||||
|
||||
|
||||
// Zones
|
||||
surfZoneIdentifierList surfZones(compactZoneID.size());
|
||||
forAllConstIter(HashTable<label>, compactZoneID, iter)
|
||||
{
|
||||
surfZones[iter()] = surfZoneIdentifier(iter.key(), iter());
|
||||
Info<< "surfZone " << iter() << " : " << surfZones[iter()].name()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
UnsortedMeshedSurface<face> unsortedFace
|
||||
(
|
||||
xferMove(allPoints),
|
||||
xferMove(allFaces),
|
||||
xferMove(allZones),
|
||||
xferMove(surfZones)
|
||||
);
|
||||
|
||||
|
||||
MeshedSurface<face> sortedFace(unsortedFace);
|
||||
|
||||
fileName globalCasePath
|
||||
(
|
||||
runTime.processorCase()
|
||||
? runTime.path()/".."/outFileName
|
||||
: runTime.path()/outFileName
|
||||
);
|
||||
|
||||
Info<< "Writing merged surface to " << globalCasePath << endl;
|
||||
|
||||
sortedFace.write(globalCasePath);
|
||||
}
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/utilities/surface/surfaceOrient/Make/files
Normal file
3
applications/utilities/surface/surfaceOrient/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceOrient.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceOrient
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
135
applications/utilities/surface/surfaceOrient/surfaceOrient.C
Normal file
135
applications/utilities/surface/surfaceOrient/surfaceOrient.C
Normal file
@ -0,0 +1,135 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceOrient
|
||||
|
||||
Description
|
||||
Set normal consistent with respect to a user provided 'outside' point.
|
||||
If the -inside option is used the point is considered inside.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "triSurfaceSearch.H"
|
||||
#include "orientedSurface.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"set face normals consistent with a user-provided 'outside' point"
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("visiblePoint");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList::addBoolOption
|
||||
(
|
||||
"inside",
|
||||
"treat provided point as being inside"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"usePierceTest",
|
||||
"determine orientation by counting number of intersections"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const point visiblePoint = args.argRead<point>(2);
|
||||
const fileName outFileName = args[3];
|
||||
|
||||
const bool orientInside = args.optionFound("inside");
|
||||
const bool usePierceTest = args.optionFound("usePierceTest");
|
||||
|
||||
Info<< "Reading surface from " << surfFileName << nl
|
||||
<< "Orienting surface such that visiblePoint " << visiblePoint
|
||||
<< " is ";
|
||||
|
||||
if (orientInside)
|
||||
{
|
||||
Info<< "inside" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "outside" << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Load surface
|
||||
triSurface surf(surfFileName);
|
||||
|
||||
|
||||
bool anyFlipped = false;
|
||||
|
||||
if (usePierceTest)
|
||||
{
|
||||
triSurfaceSearch surfSearches(surf);
|
||||
|
||||
anyFlipped = orientedSurface::orient
|
||||
(
|
||||
surf,
|
||||
surfSearches,
|
||||
visiblePoint,
|
||||
!orientInside
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
anyFlipped = orientedSurface::orient
|
||||
(
|
||||
surf,
|
||||
visiblePoint,
|
||||
!orientInside
|
||||
);
|
||||
}
|
||||
|
||||
if (anyFlipped)
|
||||
{
|
||||
Info<< "Flipped orientation of (part of) surface." << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Did not flip orientation of any triangle of surface." << endl;
|
||||
}
|
||||
|
||||
Info<< "Writing new surface to " << outFileName << endl;
|
||||
|
||||
surf.write(outFileName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfacePointMerge.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfacePointMerge
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
@ -0,0 +1,92 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfacePointMerge
|
||||
|
||||
Description
|
||||
Merges points on surface if they are within absolute distance.
|
||||
Since absolute distance use with care!
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "triSurface.H"
|
||||
#include "triSurfaceTools.H"
|
||||
#include "argList.H"
|
||||
#include "OFstream.H"
|
||||
#include "boundBox.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("merge distance");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const scalar mergeTol = args.argRead<scalar>(2);
|
||||
const fileName outFileName = args[3];
|
||||
|
||||
Info<< "Reading surface from " << surfFileName << " ..." << endl;
|
||||
Info<< "Merging points within " << mergeTol << " metre." << endl;
|
||||
|
||||
triSurface surf1(surfFileName);
|
||||
|
||||
Info<< "Original surface:" << endl;
|
||||
|
||||
surf1.writeStats(Info);
|
||||
|
||||
|
||||
triSurface cleanSurf(surf1);
|
||||
|
||||
while (true)
|
||||
{
|
||||
label nOldVert = cleanSurf.nPoints();
|
||||
|
||||
cleanSurf = triSurfaceTools::mergePoints(cleanSurf, mergeTol);
|
||||
|
||||
Info<< "After merging points:" << endl;
|
||||
|
||||
cleanSurf.writeStats(Info);
|
||||
|
||||
if (nOldVert == cleanSurf.nPoints())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cleanSurf.write(outFileName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceRedistributePar.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceRedistributePar
|
||||
@ -0,0 +1,9 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/parallel/distributed/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldistributed \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
@ -0,0 +1,301 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceRedistributePar
|
||||
|
||||
Description
|
||||
(Re)distribution of triSurface. Either takes an undecomposed surface
|
||||
or an already decomposed surface and redistributes it so that each
|
||||
processor has all triangles that overlap its mesh.
|
||||
|
||||
Note
|
||||
- best decomposition option is hierarchGeomDecomp since
|
||||
guarantees square decompositions.
|
||||
- triangles might be present on multiple processors.
|
||||
- merging uses geometric tolerance so take care with writing precision.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "treeBoundBox.H"
|
||||
#include "FixedList.H"
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "polyMesh.H"
|
||||
#include "distributedTriSurfaceMesh.H"
|
||||
#include "mapDistribute.H"
|
||||
#include "triSurfaceFields.H"
|
||||
#include "Pair.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Print on master all the per-processor surface stats.
|
||||
void writeProcStats
|
||||
(
|
||||
const triSurface& s,
|
||||
const List<List<treeBoundBox> >& meshBb
|
||||
)
|
||||
{
|
||||
// Determine surface bounding boxes, faces, points
|
||||
List<treeBoundBox> surfBb(Pstream::nProcs());
|
||||
{
|
||||
surfBb[Pstream::myProcNo()] = treeBoundBox(s.points());
|
||||
Pstream::gatherList(surfBb);
|
||||
Pstream::scatterList(surfBb);
|
||||
}
|
||||
|
||||
labelList nPoints(Pstream::nProcs());
|
||||
nPoints[Pstream::myProcNo()] = s.points().size();
|
||||
Pstream::gatherList(nPoints);
|
||||
Pstream::scatterList(nPoints);
|
||||
|
||||
labelList nFaces(Pstream::nProcs());
|
||||
nFaces[Pstream::myProcNo()] = s.size();
|
||||
Pstream::gatherList(nFaces);
|
||||
Pstream::scatterList(nFaces);
|
||||
|
||||
forAll(surfBb, procI)
|
||||
{
|
||||
const List<treeBoundBox>& bbs = meshBb[procI];
|
||||
|
||||
Info<< "processor" << procI << nl
|
||||
<< "\tMesh bounds : " << bbs[0] << nl;
|
||||
for (label i = 1; i < bbs.size(); i++)
|
||||
{
|
||||
Info<< "\t " << bbs[i]<< nl;
|
||||
}
|
||||
Info<< "\tSurface bounding box : " << surfBb[procI] << nl
|
||||
<< "\tTriangles : " << nFaces[procI] << nl
|
||||
<< "\tVertices : " << nPoints[procI]
|
||||
<< endl;
|
||||
}
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"redistribute a triSurface"
|
||||
);
|
||||
|
||||
argList::validArgs.append("triSurfaceMesh");
|
||||
argList::validArgs.append("distributionType");
|
||||
argList::addBoolOption
|
||||
(
|
||||
"keepNonMapped",
|
||||
"preserve surface outside of mesh bounds"
|
||||
);
|
||||
|
||||
#include "setRootCase.H"
|
||||
#include "createTime.H"
|
||||
runTime.functionObjects().off();
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const word distType = args[2];
|
||||
|
||||
Info<< "Reading surface from " << surfFileName << nl << nl
|
||||
<< "Using distribution method "
|
||||
<< distributedTriSurfaceMesh::distributionTypeNames_[distType]
|
||||
<< " " << distType << nl << endl;
|
||||
|
||||
const bool keepNonMapped = args.options().found("keepNonMapped");
|
||||
|
||||
if (keepNonMapped)
|
||||
{
|
||||
Info<< "Preserving surface outside of mesh bounds." << nl << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Removing surface outside of mesh bounds." << nl << endl;
|
||||
}
|
||||
|
||||
|
||||
if (!Pstream::parRun())
|
||||
{
|
||||
FatalErrorIn(args.executable())
|
||||
<< "Please run this program on the decomposed case."
|
||||
<< " It will read surface " << surfFileName
|
||||
<< " and decompose it such that it overlaps the mesh bounding box."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
|
||||
#include "createPolyMesh.H"
|
||||
|
||||
Random rndGen(653213);
|
||||
|
||||
// Determine mesh bounding boxes:
|
||||
List<List<treeBoundBox> > meshBb(Pstream::nProcs());
|
||||
{
|
||||
meshBb[Pstream::myProcNo()] = List<treeBoundBox>
|
||||
(
|
||||
1,
|
||||
treeBoundBox
|
||||
(
|
||||
boundBox(mesh.points(), false)
|
||||
).extend(rndGen, 1e-3)
|
||||
);
|
||||
Pstream::gatherList(meshBb);
|
||||
Pstream::scatterList(meshBb);
|
||||
}
|
||||
|
||||
IOobject io
|
||||
(
|
||||
surfFileName, // name
|
||||
//runTime.findInstance("triSurface", surfFileName), // instance
|
||||
runTime.constant(), // instance
|
||||
"triSurface", // local
|
||||
runTime, // registry
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE
|
||||
);
|
||||
|
||||
const fileName actualPath(io.filePath());
|
||||
fileName localPath(actualPath);
|
||||
localPath.replace(runTime.rootPath() + '/', "");
|
||||
|
||||
if (actualPath == io.objectPath())
|
||||
{
|
||||
Info<< "Loading local (decomposed) surface " << localPath << nl <<endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Loading undecomposed surface " << localPath << nl << endl;
|
||||
}
|
||||
|
||||
|
||||
// Create dummy dictionary for bounding boxes if does not exist.
|
||||
if (!isFile(actualPath / "Dict"))
|
||||
{
|
||||
dictionary dict;
|
||||
dict.add("bounds", meshBb[Pstream::myProcNo()]);
|
||||
dict.add("distributionType", distType);
|
||||
dict.add("mergeDistance", SMALL);
|
||||
|
||||
IOdictionary ioDict
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
io.name() + "Dict",
|
||||
io.instance(),
|
||||
io.local(),
|
||||
io.db(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
dict
|
||||
);
|
||||
|
||||
Info<< "Writing dummy bounds dictionary to " << ioDict.name()
|
||||
<< nl << endl;
|
||||
|
||||
ioDict.regIOobject::writeObject
|
||||
(
|
||||
IOstream::ASCII,
|
||||
IOstream::currentVersion,
|
||||
ioDict.time().writeCompression()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Load surface
|
||||
distributedTriSurfaceMesh surfMesh(io);
|
||||
Info<< "Loaded surface" << nl << endl;
|
||||
|
||||
|
||||
// Generate a test field
|
||||
{
|
||||
const triSurface& s = static_cast<const triSurface&>(surfMesh);
|
||||
|
||||
autoPtr<triSurfaceVectorField> fcPtr
|
||||
(
|
||||
new triSurfaceVectorField
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
surfMesh.searchableSurface::name(), // name
|
||||
surfMesh.searchableSurface::instance(), // instance
|
||||
surfMesh.searchableSurface::local(), // local
|
||||
surfMesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::AUTO_WRITE
|
||||
),
|
||||
surfMesh,
|
||||
dimLength
|
||||
)
|
||||
);
|
||||
triSurfaceVectorField& fc = fcPtr();
|
||||
|
||||
forAll(fc, triI)
|
||||
{
|
||||
fc[triI] = s[triI].centre(s.points());
|
||||
}
|
||||
|
||||
// Steal pointer and store object on surfMesh
|
||||
fcPtr.ptr()->store();
|
||||
}
|
||||
|
||||
|
||||
// Write per-processor stats
|
||||
Info<< "Before redistribution:" << endl;
|
||||
writeProcStats(surfMesh, meshBb);
|
||||
|
||||
|
||||
// Do redistribution
|
||||
Info<< "Redistributing surface" << nl << endl;
|
||||
autoPtr<mapDistribute> faceMap;
|
||||
autoPtr<mapDistribute> pointMap;
|
||||
surfMesh.distribute
|
||||
(
|
||||
meshBb[Pstream::myProcNo()],
|
||||
keepNonMapped,
|
||||
faceMap,
|
||||
pointMap
|
||||
);
|
||||
faceMap.clear();
|
||||
pointMap.clear();
|
||||
|
||||
Info<< endl;
|
||||
|
||||
|
||||
// Write per-processor stats
|
||||
Info<< "After redistribution:" << endl;
|
||||
writeProcStats(surfMesh, meshBb);
|
||||
|
||||
|
||||
Info<< "Writing surface." << nl << endl;
|
||||
surfMesh.searchableSurface::write();
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceRefineRedGreen.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceRefineRedGreen
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
@ -0,0 +1,85 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceRefineRedGreen
|
||||
|
||||
Description
|
||||
Refine by splitting all three edges of triangle ('red' refinement).
|
||||
Neighbouring triangles (which are not marked for refinement get split
|
||||
in half ('green' refinement). (R. Verfuerth, "A review of a posteriori
|
||||
error estimation and adaptive mesh refinement techniques",
|
||||
Wiley-Teubner, 1996)
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "triSurface.H"
|
||||
#include "triSurfaceTools.H"
|
||||
#include "argList.H"
|
||||
#include "OFstream.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfFileName = args[1];
|
||||
const fileName outFileName = args[2];
|
||||
|
||||
Info<< "Reading surface from " << surfFileName << " ..." << endl;
|
||||
|
||||
triSurface surf1(surfFileName);
|
||||
|
||||
// Refine
|
||||
triSurface surf2 = triSurfaceTools::redGreenRefine
|
||||
(
|
||||
surf1,
|
||||
identity(surf1.size()) //Hack: refine all
|
||||
);
|
||||
|
||||
Info<< "Original surface:" << endl
|
||||
<< " triangles :" << surf1.size() << endl
|
||||
<< " vertices(used):" << surf1.nPoints() << endl
|
||||
<< "Refined surface:" << endl
|
||||
<< " triangles :" << surf2.size() << endl
|
||||
<< " vertices(used):" << surf2.nPoints() << endl << endl;
|
||||
|
||||
|
||||
Info<< "Writing refined surface to " << outFileName << " ..." << endl;
|
||||
|
||||
surf2.write(outFileName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceSplitByPatch.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceSplitByPatch
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
|
||||
@ -0,0 +1,119 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceSplitByPatch
|
||||
|
||||
Description
|
||||
Writes regions of triSurface to separate files.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "triSurface.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"write surface mesh regions to separate files"
|
||||
);
|
||||
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("input surfaceFile");
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName surfName = args[1];
|
||||
|
||||
Info<< "Reading surf from " << surfName << " ..." << nl << endl;
|
||||
|
||||
fileName surfBase = surfName.lessExt();
|
||||
|
||||
word extension = surfName.ext();
|
||||
|
||||
triSurface surf(surfName);
|
||||
|
||||
Info<< "Writing regions to separate files ..."
|
||||
<< nl << endl;
|
||||
|
||||
|
||||
const geometricSurfacePatchList& patches = surf.patches();
|
||||
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const geometricSurfacePatch& pp = patches[patchI];
|
||||
|
||||
word patchName = pp.name();
|
||||
|
||||
if (patchName.empty())
|
||||
{
|
||||
patchName = "patch" + Foam::name(patchI);
|
||||
}
|
||||
|
||||
fileName outFile(surfBase + '_' + patchName + '.' + extension);
|
||||
|
||||
Info<< " Writing patch " << patchName << " to file " << outFile
|
||||
<< endl;
|
||||
|
||||
|
||||
// Collect faces of region
|
||||
boolList includeMap(surf.size(), false);
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
const labelledTri& f = surf[faceI];
|
||||
|
||||
if (f.region() == patchI)
|
||||
{
|
||||
includeMap[faceI] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Subset triSurface
|
||||
labelList pointMap;
|
||||
labelList faceMap;
|
||||
|
||||
triSurface subSurf
|
||||
(
|
||||
surf.subsetMesh
|
||||
(
|
||||
includeMap,
|
||||
pointMap,
|
||||
faceMap
|
||||
)
|
||||
);
|
||||
|
||||
subSurf.write(outFile);
|
||||
}
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
|
||||
surfaceSplitByTopology.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceSplitByTopology
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
|
||||
@ -0,0 +1,220 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2012 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/>.
|
||||
|
||||
Description
|
||||
|
||||
Strips any baffle parts of a surface. A baffle region is one which is
|
||||
reached by walking from an open edge, and stopping when a multiply connected
|
||||
edge is reached.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "triSurface.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noParallel();
|
||||
argList::validOptions.clear();
|
||||
argList::validArgs.append("input surface file");
|
||||
argList::validArgs.append("output surface file");
|
||||
argList args(argc, argv);
|
||||
|
||||
fileName surfFileName(args.additionalArgs()[0]);
|
||||
Info<< "Reading surface from " << surfFileName << endl;
|
||||
|
||||
fileName outFileName(args.additionalArgs()[1]);
|
||||
fileName outFileBaseName = outFileName.lessExt();
|
||||
word outExtension = outFileName.ext();
|
||||
|
||||
// Load surface
|
||||
triSurface surf(surfFileName);
|
||||
|
||||
bool anyZoneRemoved = false;
|
||||
|
||||
label iterationNo = 0;
|
||||
label iterationLimit = 10;
|
||||
|
||||
Info<< "Splitting off baffle parts " << endl;
|
||||
|
||||
do
|
||||
{
|
||||
anyZoneRemoved = false;
|
||||
|
||||
labelList faceZone;
|
||||
|
||||
const labelListList& edFaces = surf.edgeFaces();
|
||||
const labelListList& faceEds = surf.faceEdges();
|
||||
|
||||
boolList multipleEdges(edFaces.size(), false);
|
||||
|
||||
forAll(multipleEdges, i)
|
||||
{
|
||||
if (edFaces[i].size() > 2)
|
||||
{
|
||||
multipleEdges[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
label nZones = surf.markZones(multipleEdges, faceZone);
|
||||
|
||||
if (nZones < 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
boolList nonBaffle(faceZone.size(), true);
|
||||
boolList baffle(faceZone.size(), true);
|
||||
labelList pointMap;
|
||||
labelList faceMap;
|
||||
|
||||
|
||||
for (label z = 0; z < nZones; z++)
|
||||
{
|
||||
bool keepZone = true;
|
||||
|
||||
forAll(faceZone, f)
|
||||
{
|
||||
if (faceZone[f] == z)
|
||||
{
|
||||
forAll (faceEds[f], fe)
|
||||
{
|
||||
if (edFaces[faceEds[f][fe]].size() < 2)
|
||||
{
|
||||
keepZone = false;
|
||||
|
||||
anyZoneRemoved = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepZone)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
forAll(faceZone, f)
|
||||
{
|
||||
if (faceZone[f] == z)
|
||||
{
|
||||
nonBaffle[f] = keepZone;
|
||||
baffle[f] = !keepZone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< " Iteration " << iterationNo << endl;
|
||||
|
||||
triSurface baffleSurf = surf.subsetMesh(baffle, pointMap, faceMap);
|
||||
|
||||
if (baffleSurf.size())
|
||||
{
|
||||
fileName bafflePartFileName =
|
||||
outFileBaseName
|
||||
+ "_bafflePart_"
|
||||
+ name(iterationNo)
|
||||
+ "." + outExtension;
|
||||
|
||||
Info<< " Writing baffle part to " << bafflePartFileName << endl;
|
||||
|
||||
baffleSurf.write(bafflePartFileName);
|
||||
}
|
||||
|
||||
surf = surf.subsetMesh(nonBaffle, pointMap, faceMap);
|
||||
|
||||
if (iterationNo == iterationLimit)
|
||||
{
|
||||
WarningIn("surfaceSplitByTopology")
|
||||
<< "Iteration limit of " << iterationLimit << "reached" << endl;
|
||||
}
|
||||
|
||||
iterationNo++;
|
||||
|
||||
} while (anyZoneRemoved && iterationNo < iterationLimit);
|
||||
|
||||
Info<< "Writing new surface to " << outFileName << endl;
|
||||
|
||||
surf.write(outFileName);
|
||||
|
||||
labelList faceZone;
|
||||
|
||||
const labelListList& edFaces = surf.edgeFaces();
|
||||
|
||||
boolList multipleEdges(edFaces.size(), false);
|
||||
|
||||
forAll(multipleEdges, i)
|
||||
{
|
||||
if (edFaces[i].size() > 2)
|
||||
{
|
||||
multipleEdges[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
label nZones = surf.markZones(multipleEdges, faceZone);
|
||||
|
||||
Info<< "Splitting remaining multiply connected parts" << endl;
|
||||
|
||||
for (label z = 0; z < nZones; z++)
|
||||
{
|
||||
|
||||
boolList include(faceZone.size(), false);
|
||||
labelList pointMap;
|
||||
labelList faceMap;
|
||||
|
||||
forAll(faceZone, f)
|
||||
{
|
||||
if (faceZone[f] == z)
|
||||
{
|
||||
include[f] = true;
|
||||
}
|
||||
}
|
||||
|
||||
triSurface zoneSurf = surf.subsetMesh(include, pointMap, faceMap);
|
||||
|
||||
|
||||
fileName remainingPartFileName =
|
||||
outFileBaseName
|
||||
+ "_multiplePart_"
|
||||
+ name(z)
|
||||
+ "." + outExtension;
|
||||
|
||||
Info<< " Writing mulitple part "
|
||||
<< z << " to " << remainingPartFileName << endl;
|
||||
|
||||
zoneSurf.write(remainingPartFileName);
|
||||
}
|
||||
|
||||
Info << "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
surfaceSplitNonManifolds.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceSplitNonManifolds
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/triSurface/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ltriSurface
|
||||
@ -0,0 +1,970 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-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
|
||||
surfaceSplitNonManifolds
|
||||
|
||||
Description
|
||||
Takes multiply connected surface and tries to split surface at
|
||||
multiply connected edges by duplicating points. Introduces concept of
|
||||
- borderEdge. Edge with 4 faces connected to it.
|
||||
- borderPoint. Point connected to exactly 2 borderEdges.
|
||||
- borderLine. Connected list of borderEdges.
|
||||
|
||||
By duplicating borderPoints this will split 'borderLines'. As a
|
||||
preprocessing step it can detect borderEdges without any borderPoints
|
||||
and explicitly split these triangles.
|
||||
|
||||
The problems in this algorithm are:
|
||||
- determining which two (of the four) faces form a surface. Done by walking
|
||||
face-edge-face while keeping and edge or point on the borderEdge
|
||||
borderPoint.
|
||||
- determining the outwards pointing normal to be used to slightly offset the
|
||||
duplicated point.
|
||||
|
||||
Uses sortedEdgeFaces quite a bit.
|
||||
|
||||
Is tested on simple borderLines resulting from extracting a surface
|
||||
from a hex mesh. Will quite possibly go wrong on more complicated border
|
||||
lines (i.e. ones forming a loop).
|
||||
|
||||
Dumps surface every so often since might take a long time to complete.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "triSurface.H"
|
||||
#include "OFstream.H"
|
||||
#include "ListOps.H"
|
||||
#include "triSurfaceTools.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
void writeOBJ(Ostream& os, const pointField& pts)
|
||||
{
|
||||
forAll(pts, i)
|
||||
{
|
||||
const point& pt = pts[i];
|
||||
|
||||
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dumpPoints(const triSurface& surf, const labelList& borderPoint)
|
||||
{
|
||||
fileName fName("borderPoints.obj");
|
||||
|
||||
Info<< "Dumping borderPoints as Lightwave .obj file to " << fName
|
||||
<< "\nThis can be visualized with e.g. javaview (www.javaview.de)\n\n";
|
||||
|
||||
OFstream os(fName);
|
||||
|
||||
forAll(borderPoint, pointI)
|
||||
{
|
||||
if (borderPoint[pointI] != -1)
|
||||
{
|
||||
const point& pt = surf.localPoints()[pointI];
|
||||
|
||||
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dumpEdges(const triSurface& surf, const boolList& borderEdge)
|
||||
{
|
||||
fileName fName("borderEdges.obj");
|
||||
|
||||
Info<< "Dumping borderEdges as Lightwave .obj file to " << fName
|
||||
<< "\nThis can be visualized with e.g. javaview (www.javaview.de)\n\n";
|
||||
|
||||
OFstream os(fName);
|
||||
|
||||
writeOBJ(os, surf.localPoints());
|
||||
|
||||
forAll(borderEdge, edgeI)
|
||||
{
|
||||
if (borderEdge[edgeI])
|
||||
{
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
os << "l " << e.start()+1 << ' ' << e.end()+1 << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dumpFaces
|
||||
(
|
||||
const fileName& fName,
|
||||
const triSurface& surf,
|
||||
const Map<label>& connectedFaces
|
||||
)
|
||||
{
|
||||
Info<< "Dumping connectedFaces as Lightwave .obj file to " << fName
|
||||
<< "\nThis can be visualized with e.g. javaview (www.javaview.de)\n\n";
|
||||
|
||||
OFstream os(fName);
|
||||
|
||||
forAllConstIter(Map<label>, connectedFaces, iter)
|
||||
{
|
||||
point ctr = surf.localFaces()[iter.key()].centre(surf.localPoints());
|
||||
|
||||
os << "v " << ctr.x() << ' ' << ctr.y() << ' ' << ctr.z() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void testSortedEdgeFaces(const triSurface& surf)
|
||||
{
|
||||
const labelListList& edgeFaces = surf.edgeFaces();
|
||||
const labelListList& sortedEdgeFaces = surf.sortedEdgeFaces();
|
||||
|
||||
forAll(edgeFaces, edgeI)
|
||||
{
|
||||
const labelList& myFaces = edgeFaces[edgeI];
|
||||
const labelList& sortMyFaces = sortedEdgeFaces[edgeI];
|
||||
|
||||
forAll(myFaces, i)
|
||||
{
|
||||
if (findIndex(sortMyFaces, myFaces[i]) == -1)
|
||||
{
|
||||
FatalErrorIn("testSortedEdgeFaces(..)") << abort(FatalError);
|
||||
}
|
||||
}
|
||||
forAll(sortMyFaces, i)
|
||||
{
|
||||
if (findIndex(myFaces, sortMyFaces[i]) == -1)
|
||||
{
|
||||
FatalErrorIn("testSortedEdgeFaces(..)") << abort(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mark off all border edges. Return number of border edges.
|
||||
label markBorderEdges
|
||||
(
|
||||
const bool debug,
|
||||
const triSurface& surf,
|
||||
boolList& borderEdge
|
||||
)
|
||||
{
|
||||
label nBorderEdges = 0;
|
||||
|
||||
const labelListList& edgeFaces = surf.edgeFaces();
|
||||
|
||||
forAll(edgeFaces, edgeI)
|
||||
{
|
||||
if (edgeFaces[edgeI].size() == 4)
|
||||
{
|
||||
borderEdge[edgeI] = true;
|
||||
|
||||
nBorderEdges++;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
dumpEdges(surf, borderEdge);
|
||||
}
|
||||
|
||||
return nBorderEdges;
|
||||
}
|
||||
|
||||
|
||||
// Mark off all border points. Return number of border points. Border points
|
||||
// marked by setting value to newly introduced point.
|
||||
label markBorderPoints
|
||||
(
|
||||
const bool debug,
|
||||
const triSurface& surf,
|
||||
const boolList& borderEdge,
|
||||
labelList& borderPoint
|
||||
)
|
||||
{
|
||||
label nPoints = surf.nPoints();
|
||||
|
||||
const labelListList& pointEdges = surf.pointEdges();
|
||||
|
||||
forAll(pointEdges, pointI)
|
||||
{
|
||||
const labelList& pEdges = pointEdges[pointI];
|
||||
|
||||
label nBorderEdges = 0;
|
||||
|
||||
forAll(pEdges, i)
|
||||
{
|
||||
if (borderEdge[pEdges[i]])
|
||||
{
|
||||
nBorderEdges++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nBorderEdges == 2 && borderPoint[pointI] == -1)
|
||||
{
|
||||
borderPoint[pointI] = nPoints++;
|
||||
}
|
||||
}
|
||||
|
||||
label nBorderPoints = nPoints - surf.nPoints();
|
||||
|
||||
if (debug)
|
||||
{
|
||||
dumpPoints(surf, borderPoint);
|
||||
}
|
||||
|
||||
return nBorderPoints;
|
||||
}
|
||||
|
||||
|
||||
// Get minumum length of edges connected to pointI
|
||||
// Serves to get some local length scale.
|
||||
scalar minEdgeLen(const triSurface& surf, const label pointI)
|
||||
{
|
||||
const pointField& points = surf.localPoints();
|
||||
|
||||
const labelList& pEdges = surf.pointEdges()[pointI];
|
||||
|
||||
scalar minLen = GREAT;
|
||||
|
||||
forAll(pEdges, i)
|
||||
{
|
||||
label edgeI = pEdges[i];
|
||||
|
||||
scalar len = surf.edges()[edgeI].mag(points);
|
||||
|
||||
if (len < minLen)
|
||||
{
|
||||
minLen = len;
|
||||
}
|
||||
}
|
||||
return minLen;
|
||||
}
|
||||
|
||||
|
||||
// Find edge among edgeLabels with endpoints v0,v1
|
||||
label findEdge
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& edgeLabels,
|
||||
const label v0,
|
||||
const label v1
|
||||
)
|
||||
{
|
||||
forAll(edgeLabels, i)
|
||||
{
|
||||
label edgeI = edgeLabels[i];
|
||||
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
if
|
||||
(
|
||||
(
|
||||
e.start() == v0
|
||||
&& e.end() == v1
|
||||
)
|
||||
|| (
|
||||
e.start() == v1
|
||||
&& e.end() == v0
|
||||
)
|
||||
)
|
||||
{
|
||||
return edgeI;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FatalErrorIn("findEdge(..)") << "Cannot find edge with labels " << v0
|
||||
<< ' ' << v1 << " in candidates " << edgeLabels
|
||||
<< " with vertices:" << UIndirectList<edge>(surf.edges(), edgeLabels)()
|
||||
<< abort(FatalError);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Get the other edge connected to pointI on faceI.
|
||||
label otherEdge
|
||||
(
|
||||
const triSurface& surf,
|
||||
const label faceI,
|
||||
const label otherEdgeI,
|
||||
const label pointI
|
||||
)
|
||||
{
|
||||
const labelList& fEdges = surf.faceEdges()[faceI];
|
||||
|
||||
forAll(fEdges, i)
|
||||
{
|
||||
label edgeI = fEdges[i];
|
||||
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
if
|
||||
(
|
||||
edgeI != otherEdgeI
|
||||
&& (
|
||||
e.start() == pointI
|
||||
|| e.end() == pointI
|
||||
)
|
||||
)
|
||||
{
|
||||
return edgeI;
|
||||
}
|
||||
}
|
||||
|
||||
FatalErrorIn("otherEdge(..)") << "Cannot find other edge on face " << faceI
|
||||
<< " verts:" << surf.localPoints()[faceI]
|
||||
<< " connected to point " << pointI
|
||||
<< " faceEdges:" << UIndirectList<edge>(surf.edges(), fEdges)()
|
||||
<< abort(FatalError);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Starting from startPoint on startEdge on startFace walk along border
|
||||
// and insert faces along the way. Walk keeps always one point or one edge
|
||||
// on the border line.
|
||||
void walkSplitLine
|
||||
(
|
||||
const triSurface& surf,
|
||||
const boolList& borderEdge,
|
||||
const labelList& borderPoint,
|
||||
|
||||
const label startFaceI,
|
||||
const label startEdgeI, // is border edge
|
||||
const label startPointI, // is border point
|
||||
|
||||
Map<label>& faceToEdge,
|
||||
Map<label>& faceToPoint
|
||||
)
|
||||
{
|
||||
label faceI = startFaceI;
|
||||
label edgeI = startEdgeI;
|
||||
label pointI = startPointI;
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Stick to pointI and walk face-edge-face until back on border edge.
|
||||
//
|
||||
|
||||
do
|
||||
{
|
||||
// Cross face to next edge.
|
||||
edgeI = otherEdge(surf, faceI, edgeI, pointI);
|
||||
|
||||
if (borderEdge[edgeI])
|
||||
{
|
||||
if (!faceToEdge.insert(faceI, edgeI))
|
||||
{
|
||||
// Was already visited.
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// First visit to this borderEdge. We're back on borderline.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!faceToPoint.insert(faceI, pointI))
|
||||
{
|
||||
// Was already visited.
|
||||
return;
|
||||
}
|
||||
|
||||
// Cross edge to other face
|
||||
const labelList& eFaces = surf.edgeFaces()[edgeI];
|
||||
|
||||
if (eFaces.size() != 2)
|
||||
{
|
||||
FatalErrorIn("walkSplitPoint(..)")
|
||||
<< "Can only handle edges with 2 or 4 edges for now."
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
if (eFaces[0] == faceI)
|
||||
{
|
||||
faceI = eFaces[1];
|
||||
}
|
||||
else if (eFaces[1] == faceI)
|
||||
{
|
||||
faceI = eFaces[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalErrorIn("walkSplitPoint(..)") << abort(FatalError);
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
|
||||
|
||||
//
|
||||
// Back on border edge. Cross to other point on edge.
|
||||
//
|
||||
|
||||
pointI = surf.edges()[edgeI].otherVertex(pointI);
|
||||
|
||||
if (borderPoint[pointI] == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
|
||||
// Find second face which is from same surface i.e. has points on the
|
||||
// shared edge in reverse order.
|
||||
label sharedFace
|
||||
(
|
||||
const triSurface& surf,
|
||||
const label firstFaceI,
|
||||
const label sharedEdgeI
|
||||
)
|
||||
{
|
||||
// Find ordering of face points in edge.
|
||||
|
||||
const edge& e = surf.edges()[sharedEdgeI];
|
||||
|
||||
const triSurface::FaceType& f = surf.localFaces()[firstFaceI];
|
||||
|
||||
label startIndex = findIndex(f, e.start());
|
||||
|
||||
// points in face in same order as edge
|
||||
bool edgeOrder = (f[f.fcIndex(startIndex)] == e.end());
|
||||
|
||||
// Get faces using edge in sorted order. (sorted such that walking
|
||||
// around them in anti-clockwise order corresponds to edge vector
|
||||
// acc. to right-hand rule)
|
||||
const labelList& eFaces = surf.sortedEdgeFaces()[sharedEdgeI];
|
||||
|
||||
// Get position of face in sorted edge faces
|
||||
label faceIndex = findIndex(eFaces, firstFaceI);
|
||||
|
||||
if (edgeOrder)
|
||||
{
|
||||
// Get face before firstFaceI
|
||||
return eFaces[eFaces.rcIndex(faceIndex)];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get face after firstFaceI
|
||||
return eFaces[eFaces.fcIndex(faceIndex)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate (inward pointing) normals on edges shared by faces in
|
||||
// faceToEdge and averages them to pointNormals.
|
||||
void calcPointVecs
|
||||
(
|
||||
const triSurface& surf,
|
||||
const Map<label>& faceToEdge,
|
||||
const Map<label>& faceToPoint,
|
||||
vectorField& borderPointVec
|
||||
)
|
||||
{
|
||||
const labelListList& sortedEdgeFaces = surf.sortedEdgeFaces();
|
||||
const edgeList& edges = surf.edges();
|
||||
const pointField& points = surf.localPoints();
|
||||
|
||||
boolList edgeDone(surf.nEdges(), false);
|
||||
|
||||
forAllConstIter(Map<label>, faceToEdge, iter)
|
||||
{
|
||||
const label edgeI = iter();
|
||||
|
||||
if (!edgeDone[edgeI])
|
||||
{
|
||||
edgeDone[edgeI] = true;
|
||||
|
||||
// Get the two connected faces in sorted order
|
||||
// Note: should have stored this when walking ...
|
||||
|
||||
label face0I = -1;
|
||||
label face1I = -1;
|
||||
|
||||
const labelList& eFaces = sortedEdgeFaces[edgeI];
|
||||
|
||||
forAll(eFaces, i)
|
||||
{
|
||||
label faceI = eFaces[i];
|
||||
|
||||
if (faceToEdge.found(faceI))
|
||||
{
|
||||
if (face0I == -1)
|
||||
{
|
||||
face0I = faceI;
|
||||
}
|
||||
else if (face1I == -1)
|
||||
{
|
||||
face1I = faceI;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (face0I == -1 && face1I == -1)
|
||||
{
|
||||
Info<< "Writing surface to errorSurf.obj" << endl;
|
||||
|
||||
surf.write("errorSurf.obj");
|
||||
|
||||
FatalErrorIn("calcPointVecs(..)")
|
||||
<< "Cannot find two faces using border edge " << edgeI
|
||||
<< " verts:" << edges[edgeI]
|
||||
<< " eFaces:" << eFaces << endl
|
||||
<< "face0I:" << face0I
|
||||
<< " face1I:" << face1I << nl
|
||||
<< "faceToEdge:" << faceToEdge << nl
|
||||
<< "faceToPoint:" << faceToPoint
|
||||
<< "Written surface to errorSurf.obj"
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
// Now we have edge and the two faces in counter-clockwise order
|
||||
// as seen from edge vector. Calculate normal.
|
||||
const edge& e = edges[edgeI];
|
||||
vector eVec = e.vec(points);
|
||||
|
||||
// Determine vector as average of the vectors in the two faces.
|
||||
// If there is only one face available use only one vector.
|
||||
vector midVec(vector::zero);
|
||||
|
||||
if (face0I != -1)
|
||||
{
|
||||
label v0 = triSurfaceTools::oppositeVertex(surf, face0I, edgeI);
|
||||
vector e0 = (points[v0] - points[e.start()]) ^ eVec;
|
||||
e0 /= mag(e0);
|
||||
midVec = e0;
|
||||
}
|
||||
|
||||
if (face1I != -1)
|
||||
{
|
||||
label v1 = triSurfaceTools::oppositeVertex(surf, face1I, edgeI);
|
||||
vector e1 = (points[e.start()] - points[v1]) ^ eVec;
|
||||
e1 /= mag(e1);
|
||||
midVec += e1;
|
||||
}
|
||||
|
||||
scalar magMidVec = mag(midVec);
|
||||
|
||||
if (magMidVec > SMALL)
|
||||
{
|
||||
midVec /= magMidVec;
|
||||
|
||||
// Average to pointVec
|
||||
borderPointVec[e.start()] += midVec;
|
||||
borderPointVec[e.end()] += midVec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Renumbers vertices (of triangles in faceToEdge) of which the pointMap is
|
||||
// not -1.
|
||||
void renumberFaces
|
||||
(
|
||||
const triSurface& surf,
|
||||
const labelList& pointMap,
|
||||
const Map<label>& faceToEdge,
|
||||
List<triSurface::FaceType>& newTris
|
||||
)
|
||||
{
|
||||
forAllConstIter(Map<label>, faceToEdge, iter)
|
||||
{
|
||||
const label faceI = iter.key();
|
||||
const triSurface::FaceType& f = surf.localFaces()[faceI];
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
if (pointMap[f[fp]] != -1)
|
||||
{
|
||||
newTris[faceI][fp] = pointMap[f[fp]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Split all borderEdges that don't have borderPoint. Return true if split
|
||||
// anything.
|
||||
bool splitBorderEdges
|
||||
(
|
||||
triSurface& surf,
|
||||
const boolList& borderEdge,
|
||||
const labelList& borderPoint
|
||||
)
|
||||
{
|
||||
labelList edgesToBeSplit(surf.nEdges());
|
||||
label nSplit = 0;
|
||||
|
||||
forAll(borderEdge, edgeI)
|
||||
{
|
||||
if (borderEdge[edgeI])
|
||||
{
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
if (borderPoint[e.start()] == -1 && borderPoint[e.end()] == -1)
|
||||
{
|
||||
// None of the points of the edge is borderPoint. Split edge
|
||||
// to introduce border point.
|
||||
edgesToBeSplit[nSplit++] = edgeI;
|
||||
}
|
||||
}
|
||||
}
|
||||
edgesToBeSplit.setSize(nSplit);
|
||||
|
||||
if (nSplit > 0)
|
||||
{
|
||||
Info<< "Splitting surface along " << nSplit << " borderEdges that don't"
|
||||
<< " neighbour other borderEdges" << nl << endl;
|
||||
|
||||
surf = triSurfaceTools::greenRefine(surf, edgesToBeSplit);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "No edges to be split" <<nl << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"split multiply connected surface edges by duplicating points"
|
||||
);
|
||||
argList::noParallel();
|
||||
argList::validArgs.append("surfaceFile");
|
||||
argList::validArgs.append("output surfaceFile");
|
||||
argList::addBoolOption
|
||||
(
|
||||
"debug",
|
||||
"add debugging output"
|
||||
);
|
||||
|
||||
argList args(argc, argv);
|
||||
|
||||
const fileName inSurfName = args[1];
|
||||
const fileName outSurfName = args[2];
|
||||
const bool debug = args.optionFound("debug");
|
||||
|
||||
Info<< "Reading surface from " << inSurfName << endl;
|
||||
|
||||
triSurface surf(inSurfName);
|
||||
|
||||
// Make sure sortedEdgeFaces is calculated correctly
|
||||
testSortedEdgeFaces(surf);
|
||||
|
||||
// Get all quad connected edges. These are seen as borders when walking.
|
||||
boolList borderEdge(surf.nEdges(), false);
|
||||
markBorderEdges(debug, surf, borderEdge);
|
||||
|
||||
// Points on two sides connected to borderEdges are called
|
||||
// borderPoints and will be duplicated. borderPoint contains label
|
||||
// of newly introduced vertex.
|
||||
labelList borderPoint(surf.nPoints(), -1);
|
||||
markBorderPoints(debug, surf, borderEdge, borderPoint);
|
||||
|
||||
// Split edges where there would be no borderPoint to duplicate.
|
||||
splitBorderEdges(surf, borderEdge, borderPoint);
|
||||
|
||||
|
||||
Info<< "Writing split surface to " << outSurfName << nl << endl;
|
||||
surf.write(outSurfName);
|
||||
Info<< "Finished writing surface to " << outSurfName << nl << endl;
|
||||
|
||||
|
||||
// Last iteration values.
|
||||
label nOldBorderEdges = -1;
|
||||
label nOldBorderPoints = -1;
|
||||
|
||||
label iteration = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// Redo borderEdge/borderPoint calculation.
|
||||
boolList borderEdge(surf.nEdges(), false);
|
||||
|
||||
label nBorderEdges = markBorderEdges(debug, surf, borderEdge);
|
||||
|
||||
if (nBorderEdges == 0)
|
||||
{
|
||||
Info<< "Found no border edges. Exiting." << nl << nl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Label of newly introduced duplicate.
|
||||
labelList borderPoint(surf.nPoints(), -1);
|
||||
|
||||
label nBorderPoints =
|
||||
markBorderPoints
|
||||
(
|
||||
debug,
|
||||
surf,
|
||||
borderEdge,
|
||||
borderPoint
|
||||
);
|
||||
|
||||
if (nBorderPoints == 0)
|
||||
{
|
||||
Info<< "Found no border points. Exiting." << nl << nl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Info<< "Found:\n"
|
||||
<< " border edges :" << nBorderEdges << nl
|
||||
<< " border points:" << nBorderPoints << nl
|
||||
<< endl;
|
||||
|
||||
if
|
||||
(
|
||||
nBorderPoints == nOldBorderPoints
|
||||
&& nBorderEdges == nOldBorderEdges
|
||||
)
|
||||
{
|
||||
Info<< "Stopping since number of border edges and point is same"
|
||||
<< " as in previous iteration" << nl << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Define splitLine as a series of connected borderEdges. Find start
|
||||
// of one (as edge and point on edge)
|
||||
//
|
||||
|
||||
label startEdgeI = -1;
|
||||
label startPointI = -1;
|
||||
|
||||
forAll(borderEdge, edgeI)
|
||||
{
|
||||
if (borderEdge[edgeI])
|
||||
{
|
||||
const edge& e = surf.edges()[edgeI];
|
||||
|
||||
if ((borderPoint[e[0]] != -1) && (borderPoint[e[1]] == -1))
|
||||
{
|
||||
startEdgeI = edgeI;
|
||||
startPointI = e[0];
|
||||
|
||||
break;
|
||||
}
|
||||
else if ((borderPoint[e[0]] == -1) && (borderPoint[e[1]] != -1))
|
||||
{
|
||||
startEdgeI = edgeI;
|
||||
startPointI = e[1];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startEdgeI == -1)
|
||||
{
|
||||
Info<< "Cannot find starting point of splitLine\n" << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Pick any face using edge to start from.
|
||||
const labelList& eFaces = surf.edgeFaces()[startEdgeI];
|
||||
|
||||
label firstFaceI = eFaces[0];
|
||||
|
||||
// Find second face which is from same surface i.e. has outwards
|
||||
// pointing normal as well (actually bit more complex than this)
|
||||
label secondFaceI = sharedFace(surf, firstFaceI, startEdgeI);
|
||||
|
||||
Info<< "Starting local walk from:" << endl
|
||||
<< " edge :" << startEdgeI << endl
|
||||
<< " point:" << startPointI << endl
|
||||
<< " face0:" << firstFaceI << endl
|
||||
<< " face1:" << secondFaceI << endl
|
||||
<< endl;
|
||||
|
||||
// From face on border edge to edge.
|
||||
Map<label> faceToEdge(2*nBorderEdges);
|
||||
// From face connected to border point (but not border edge) to point.
|
||||
Map<label> faceToPoint(2*nBorderPoints);
|
||||
|
||||
faceToEdge.insert(firstFaceI, startEdgeI);
|
||||
|
||||
walkSplitLine
|
||||
(
|
||||
surf,
|
||||
borderEdge,
|
||||
borderPoint,
|
||||
|
||||
firstFaceI,
|
||||
startEdgeI,
|
||||
startPointI,
|
||||
|
||||
faceToEdge,
|
||||
faceToPoint
|
||||
);
|
||||
|
||||
faceToEdge.insert(secondFaceI, startEdgeI);
|
||||
|
||||
walkSplitLine
|
||||
(
|
||||
surf,
|
||||
borderEdge,
|
||||
borderPoint,
|
||||
|
||||
secondFaceI,
|
||||
startEdgeI,
|
||||
startPointI,
|
||||
|
||||
faceToEdge,
|
||||
faceToPoint
|
||||
);
|
||||
|
||||
Info<< "Finished local walk and visited" << nl
|
||||
<< " border edges :" << faceToEdge.size() << nl
|
||||
<< " border points(but not edges):" << faceToPoint.size() << nl
|
||||
<< endl;
|
||||
|
||||
if (debug)
|
||||
{
|
||||
dumpFaces("faceToEdge.obj", surf, faceToEdge);
|
||||
dumpFaces("faceToPoint.obj", surf, faceToPoint);
|
||||
}
|
||||
|
||||
//
|
||||
// Create coordinates for borderPoints by duplicating the existing
|
||||
// point and then slightly shifting it inwards. To determine the
|
||||
// inwards direction get the average normal of both connectedFaces on
|
||||
// the edge and then interpolate this to the (border)point.
|
||||
//
|
||||
|
||||
vectorField borderPointVec(surf.nPoints(), vector(GREAT, GREAT, GREAT));
|
||||
|
||||
calcPointVecs(surf, faceToEdge, faceToPoint, borderPointVec);
|
||||
|
||||
|
||||
// New position. Start off from copy of old points.
|
||||
pointField newPoints(surf.localPoints());
|
||||
newPoints.setSize(newPoints.size() + nBorderPoints);
|
||||
|
||||
forAll(borderPoint, pointI)
|
||||
{
|
||||
label newPointI = borderPoint[pointI];
|
||||
|
||||
if (newPointI != -1)
|
||||
{
|
||||
scalar minLen = minEdgeLen(surf, pointI);
|
||||
|
||||
vector n = borderPointVec[pointI];
|
||||
n /= mag(n);
|
||||
|
||||
newPoints[newPointI] = newPoints[pointI] + 0.1 * minLen * n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Renumber all faces in connectedFaces
|
||||
//
|
||||
|
||||
// Start off from copy of faces.
|
||||
List<labelledTri> newTris(surf.size());
|
||||
|
||||
forAll(surf, faceI)
|
||||
{
|
||||
newTris[faceI] = surf.localFaces()[faceI];
|
||||
newTris[faceI].region() = surf[faceI].region();
|
||||
}
|
||||
|
||||
// Renumber all faces in faceToEdge
|
||||
renumberFaces(surf, borderPoint, faceToEdge, newTris);
|
||||
// Renumber all faces in faceToPoint
|
||||
renumberFaces(surf, borderPoint, faceToPoint, newTris);
|
||||
|
||||
|
||||
// Check if faces use unmoved points.
|
||||
forAll(newTris, faceI)
|
||||
{
|
||||
const triSurface::FaceType& f = newTris[faceI];
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
const point& pt = newPoints[f[fp]];
|
||||
|
||||
if (mag(pt) >= GREAT/2)
|
||||
{
|
||||
Info<< "newTri:" << faceI << " verts:" << f
|
||||
<< " vert:" << f[fp] << " point:" << pt << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
surf = triSurface(newTris, surf.patches(), newPoints);
|
||||
|
||||
if (debug || (iteration != 0 && (iteration % 20) == 0))
|
||||
{
|
||||
Info<< "Writing surface to " << outSurfName << nl << endl;
|
||||
|
||||
surf.write(outSurfName);
|
||||
|
||||
Info<< "Finished writing surface to " << outSurfName << nl << endl;
|
||||
}
|
||||
|
||||
// Save prev iteration values.
|
||||
nOldBorderEdges = nBorderEdges;
|
||||
nOldBorderPoints = nBorderPoints;
|
||||
|
||||
iteration++;
|
||||
}
|
||||
while (true);
|
||||
|
||||
Info<< "Writing final surface to " << outSurfName << nl << endl;
|
||||
|
||||
surf.write(outSurfName);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,164 @@
|
||||
|
||||
1
|
||||
(
|
||||
|
||||
patch0
|
||||
empty
|
||||
)
|
||||
|
||||
|
||||
49
|
||||
(
|
||||
(0 1 1)
|
||||
(0 0 1)
|
||||
(1 0 1)
|
||||
(1 1 1)
|
||||
(0 1 0)
|
||||
(0 0 0)
|
||||
(1 0 0)
|
||||
(1 1 0)
|
||||
(0 0.5 1)
|
||||
(0.5 0.5 1)
|
||||
(0.5 1 1)
|
||||
(0.5 0 1)
|
||||
(1 0.5 1)
|
||||
(1 0.5 0)
|
||||
(0.5 0.5 0)
|
||||
(0.5 1 0)
|
||||
(0.5 0 0)
|
||||
(0 0.5 0)
|
||||
(1 0.5 0.5)
|
||||
(1 1 0.5)
|
||||
(1 0 0.5)
|
||||
(0 1 0.5)
|
||||
(0.5 1 0.5)
|
||||
(0 0.5 0.5)
|
||||
(0 0 0.5)
|
||||
(0.5 0 0.5)
|
||||
(1 2 1)
|
||||
(2 1 1)
|
||||
(2 2 1)
|
||||
(1 2 0)
|
||||
(2 1 0)
|
||||
(2 2 0)
|
||||
(1 1.5 1)
|
||||
(1.5 1.5 1)
|
||||
(1.5 2 1)
|
||||
(1.5 1 1)
|
||||
(2 1.5 1)
|
||||
(2 1.5 0)
|
||||
(1.5 1.5 0)
|
||||
(1.5 2 0)
|
||||
(1.5 1 0)
|
||||
(1 1.5 0)
|
||||
(2 1.5 0.5)
|
||||
(2 2 0.5)
|
||||
(2 1 0.5)
|
||||
(1 2 0.5)
|
||||
(1.5 2 0.5)
|
||||
(1 1.5 0.5)
|
||||
(1.5 1 0.5)
|
||||
)
|
||||
|
||||
|
||||
96
|
||||
(
|
||||
((8 1 9) 0)
|
||||
((9 3 10) 0)
|
||||
((10 0 8) 0)
|
||||
((8 9 10) 0)
|
||||
((9 1 11) 0)
|
||||
((11 2 12) 0)
|
||||
((12 3 9) 0)
|
||||
((9 11 12) 0)
|
||||
((13 6 14) 0)
|
||||
((14 4 15) 0)
|
||||
((15 7 13) 0)
|
||||
((13 14 15) 0)
|
||||
((14 6 16) 0)
|
||||
((16 5 17) 0)
|
||||
((17 4 14) 0)
|
||||
((14 16 17) 0)
|
||||
((12 2 18) 0)
|
||||
((18 7 19) 0)
|
||||
((19 3 12) 0)
|
||||
((12 18 19) 0)
|
||||
((13 7 18) 0)
|
||||
((18 2 20) 0)
|
||||
((20 6 13) 0)
|
||||
((13 18 20) 0)
|
||||
((15 4 21) 0)
|
||||
((21 0 22) 0)
|
||||
((22 7 15) 0)
|
||||
((15 21 22) 0)
|
||||
((10 3 19) 0)
|
||||
((19 7 22) 0)
|
||||
((22 0 10) 0)
|
||||
((10 19 22) 0)
|
||||
((4 17 21) 0)
|
||||
((0 21 23) 0)
|
||||
((5 23 17) 0)
|
||||
((21 17 23) 0)
|
||||
((8 0 23) 0)
|
||||
((23 5 24) 0)
|
||||
((24 1 8) 0)
|
||||
((8 23 24) 0)
|
||||
((11 1 24) 0)
|
||||
((24 5 25) 0)
|
||||
((25 2 11) 0)
|
||||
((11 24 25) 0)
|
||||
((16 6 20) 0)
|
||||
((20 2 25) 0)
|
||||
((25 5 16) 0)
|
||||
((16 20 25) 0)
|
||||
((32 3 33) 0)
|
||||
((33 28 34) 0)
|
||||
((34 26 32) 0)
|
||||
((32 33 34) 0)
|
||||
((33 3 35) 0)
|
||||
((35 27 36) 0)
|
||||
((36 28 33) 0)
|
||||
((33 35 36) 0)
|
||||
((37 30 38) 0)
|
||||
((38 29 39) 0)
|
||||
((39 31 37) 0)
|
||||
((37 38 39) 0)
|
||||
((38 30 40) 0)
|
||||
((40 7 41) 0)
|
||||
((41 29 38) 0)
|
||||
((38 40 41) 0)
|
||||
((36 27 42) 0)
|
||||
((42 31 43) 0)
|
||||
((43 28 36) 0)
|
||||
((36 42 43) 0)
|
||||
((37 31 42) 0)
|
||||
((42 27 44) 0)
|
||||
((44 30 37) 0)
|
||||
((37 42 44) 0)
|
||||
((39 29 45) 0)
|
||||
((45 26 46) 0)
|
||||
((46 31 39) 0)
|
||||
((39 45 46) 0)
|
||||
((34 28 43) 0)
|
||||
((43 31 46) 0)
|
||||
((46 26 34) 0)
|
||||
((34 43 46) 0)
|
||||
((29 41 45) 0)
|
||||
((26 45 47) 0)
|
||||
((7 47 41) 0)
|
||||
((45 41 47) 0)
|
||||
((32 26 47) 0)
|
||||
((47 7 19) 0)
|
||||
((19 3 32) 0)
|
||||
((32 47 19) 0)
|
||||
((35 3 19) 0)
|
||||
((19 7 48) 0)
|
||||
((48 27 35) 0)
|
||||
((35 19 48) 0)
|
||||
((40 30 44) 0)
|
||||
((44 27 48) 0)
|
||||
((48 7 40) 0)
|
||||
((40 44 48) 0)
|
||||
)
|
||||
|
||||
|
||||
3
applications/utilities/surface/surfaceSubset/Make/files
Normal file
3
applications/utilities/surface/surfaceSubset/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
surfaceSubset.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/surfaceSubset
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user