polygonTriangulate: Added robust polygon triangulation algorithm

The new algorithm provides robust quality triangulations of non-convex
polygons. It also produces a best attempt for polygons that are badly
warped or self intersecting by minimising the area in which the local
normal is in the opposite direction to the overal polygon normal. It is
memory efficient when applied to multiple polygons as it maintains and
reuses its workspace.

This algorithm replaces implementations in the face and
faceTriangulation classes, which have been removed.

Faces can no longer be decomposed into mixtures of tris and
quadrilaterals. Polygonal faces with more than 4 sides are now
decomposed into triangles in foamToVTK and in paraFoam.
This commit is contained in:
Will Bainbridge
2021-06-15 15:34:36 +01:00
parent 01494463d0
commit 02b97a714a
36 changed files with 1777 additions and 1567 deletions

View File

@ -0,0 +1,3 @@
Test-polygonTriangulate.C
EXE = $(FOAM_USER_APPBIN)/Test-polygonTriangulate

View File

@ -0,0 +1,5 @@
EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude
EXE_LIBS = \
-lfileFormats

View File

@ -0,0 +1,121 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021 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 "argList.H"
#include "clock.H"
#include "OBJstream.H"
#include "polygonTriangulate.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::validArgs.append("number of edges");
argList::addOption
(
"error",
"value",
"polygon error - default is 0"
);
argList::addOption
(
"seed",
"value",
"random number generator seed - default is clock time"
);
argList::addBoolOption
(
"simple",
"assume polygon as no self intersections"
);
argList::addBoolOption
(
"nonOptimal",
"do not optimise the triangulation quality"
);
Foam::argList args(argc, argv);
Info<< nl;
// Get the size of the polygon
const label n = args.argRead<label>(1);
// Initialise the random number generator
label seed;
if (args.optionFound("seed"))
{
seed = args.optionRead<label>("seed");
}
else
{
seed = clock::getTime();
Info<< "Seeding random number generator with value " << seed
<< nl << endl;
}
Random rndGen(seed);
// Get controls
const bool simple = args.optionFound("simple");
const bool nonOptimal = args.optionFound("nonOptimal");
// Generate a random polygon
const List<point> polygon =
polygonTriangulate::randomPolygon
(
rndGen,
n,
args.optionLookupOrDefault<scalar>("error", 0)
);
// Write the polygon
{
OBJstream os(args[0] + "_polygon.obj");
os.write(face(identity(polygon.size())), polygon, false);
}
// Triangulate the polygon
const List<triFace> triPoints =
polygonTriangulate().triangulate(polygon, simple, !nonOptimal);
// Write the triangulation
faceList triFacePoints(triPoints.size());
forAll(triPoints, trii)
{
triFacePoints[trii] = triPoints[trii];
}
{
OBJstream os(args[0] + "_triangulation.obj");
os.write(triFacePoints, pointField(polygon), false);
}
Info<< "End" << nl << endl;
return 0;
}
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -33,6 +33,7 @@ Description
#include "cellShape.H"
#include "cellModeller.H"
#include "Swap.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -91,11 +92,14 @@ Foam::vtkTopo::vtkTopo(const polyMesh& mesh)
{
const face& f = mesh_.faces()[cFaces[cFacei]];
label nQuads = 0;
label nTris = 0;
f.nTrianglesQuads(mesh_.points(), nTris, nQuads);
nAddCells += nQuads + nTris;
if (f.size() != 4)
{
nAddCells += f.nTriangles();
}
else
{
nAddCells ++;
}
}
nAddCells--;
@ -119,6 +123,9 @@ Foam::vtkTopo::vtkTopo(const polyMesh& mesh)
// Label of vtk type
cellTypes_.setSize(cellShapes.size() + nAddCells);
// Create a triangulation engine
polygonTriangulate triEngine;
// Set counters for additional points and additional cells
label addPointi = 0, addCelli = 0;
@ -205,17 +212,24 @@ Foam::vtkTopo::vtkTopo(const polyMesh& mesh)
const face& f = mesh_.faces()[cFaces[cFacei]];
const bool isOwner = (owner[cFaces[cFacei]] == celli);
// Number of triangles and quads in decomposition
label nTris = 0;
label nQuads = 0;
f.nTrianglesQuads(mesh_.points(), nTris, nQuads);
// Do actual decomposition into triFcs and quadFcs.
faceList triFcs(nTris);
faceList quadFcs(nQuads);
label trii = 0;
label quadi = 0;
f.trianglesQuads(mesh_.points(), trii, quadi, triFcs, quadFcs);
// Do decomposition into triFcs and quadFcs.
faceList triFcs(f.size() == 4 ? 0 : f.nTriangles());
faceList quadFcs(f.size() == 4 ? 1 : 0);
if (f.size() != 4)
{
triEngine.triangulate
(
UIndirectList<point>(mesh.points(), f)
);
forAll(triEngine.triPoints(), trii)
{
triFcs[trii] = triEngine.triPoints(trii, f);
}
}
else
{
quadFcs[0] = f;
}
forAll(quadFcs, quadI)
{

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -31,6 +31,7 @@ License
#include "cellModeller.H"
#include "vtkOpenFOAMPoints.H"
#include "Swap.H"
#include "polygonTriangulate.H"
// VTK includes
#include "vtkCellArray.h"
@ -104,11 +105,14 @@ vtkUnstructuredGrid* Foam::vtkPVFoam::volumeVTKMesh
{
const face& f = mesh.faces()[cFaces[cFacei]];
label nQuads = 0;
label nTris = 0;
f.nTrianglesQuads(mesh.points(), nTris, nQuads);
nAddCells += nQuads + nTris;
if (f.size() != 4)
{
nAddCells += f.nTriangles();
}
else
{
nAddCells ++;
}
}
nAddCells--;
@ -158,6 +162,9 @@ vtkUnstructuredGrid* Foam::vtkPVFoam::volumeVTKMesh
vtkmesh->Allocate(mesh.nCells() + nAddCells);
// Create a triangulation engine
polygonTriangulate triEngine;
// Set counters for additional points and additional cells
label addPointi = 0, addCelli = 0;
@ -369,17 +376,24 @@ vtkUnstructuredGrid* Foam::vtkPVFoam::volumeVTKMesh
const face& f = mesh.faces()[cFaces[cFacei]];
const bool isOwner = (owner[cFaces[cFacei]] == celli);
// Number of triangles and quads in decomposition
label nTris = 0;
label nQuads = 0;
f.nTrianglesQuads(mesh.points(), nTris, nQuads);
// Do actual decomposition into triFcs and quadFcs.
faceList triFcs(nTris);
faceList quadFcs(nQuads);
label trii = 0;
label quadi = 0;
f.trianglesQuads(mesh.points(), trii, quadi, triFcs, quadFcs);
// Do decomposition into triFcs and quadFcs.
faceList triFcs(f.size() == 4 ? 0 : f.nTriangles());
faceList quadFcs(f.size() == 4 ? 1 : 0);
if (f.size() != 4)
{
triEngine.triangulate
(
UIndirectList<point>(mesh.points(), f)
);
forAll(triEngine.triPoints(), trii)
{
triFcs[trii] = triEngine.triPoints(trii, f);
}
}
else
{
quadFcs[0] = f;
}
forAll(quadFcs, quadI)
{

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -52,6 +52,7 @@ Description
#include "uindirectPrimitivePatch.H"
#include "DynamicField.H"
#include "scalarListIOList.H"
#include "polygonTriangulate.H"
using namespace Foam;
@ -78,31 +79,30 @@ triSurface triangulate
label newPatchi = 0;
label localTriFacei = 0;
polygonTriangulate triEngine;
forAllConstIter(labelHashSet, includePatches, iter)
{
const label patchi = iter.key();
const polyPatch& patch = bMesh[patchi];
const pointField& points = patch.points();
label nTriTotal = 0;
forAll(patch, patchFacei)
{
const face& f = patch[patchFacei];
faceList triFaces(f.nTriangles(points));
triEngine.triangulate(UIndirectList<point>(points, f));
label nTri = 0;
f.triangles(points, nTri, triFaces);
forAll(triFaces, triFacei)
forAll(triEngine.triPoints(), triFacei)
{
const face& f = triFaces[triFacei];
triangles.append(labelledTri(f[0], f[1], f[2], newPatchi));
nTriTotal++;
triangles.append
(
labelledTri
(
triEngine.triPoints(triFacei, f),
newPatchi
)
);
triSurfaceToAgglom[localTriFacei++] = globalNumbering.toGlobal
(

View File

@ -710,6 +710,7 @@ $(interpolationWeights)/splineInterpolationWeights/splineInterpolationWeights.C
algorithms/indexedOctree/indexedOctreeName.C
algorithms/indexedOctree/treeDataCell.C
algorithms/indexedOctree/volumeType.C
algorithms/polygonTriangulate/polygonTriangulate.C
algorithms/dynamicIndexedOctree/dynamicIndexedOctreeName.C

View File

@ -0,0 +1,919 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021 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 "polygonTriangulate.H"
#include "tensor2D.H"
// * * * * * * * * * * * Private Static Member Functions * * * * * * * * * * //
template<class PointField>
Foam::scalar Foam::polygonTriangulate::area
(
const triFace& triPoints,
const PointField& points,
const vector& normal
)
{
const point& o = points[triPoints[0]];
const vector ao = points[triPoints[1]] - o;
const vector ab = points[triPoints[2]] - o;
return (ao ^ ab) & normal;
}
template<class PointField>
Foam::scalar Foam::polygonTriangulate::quality
(
const triFace& triPoints,
const PointField& points,
const vector& normal
)
{
const scalar An = area(triPoints, points, normal);
scalar PSqr = 0;
forAll(triPoints, triEdgei)
{
const point& p0 = points[triPoints[triEdgei]];
const point& p1 = points[triPoints[(triEdgei + 1) % 3]];
PSqr += magSqr(p0 - p1);
}
static const scalar equilateralAnByPSqr = sqrt(scalar(3))/12;
return PSqr != 0 ? An/PSqr/equilateralAnByPSqr : 0;
}
template<class PointField>
bool Foam::polygonTriangulate::intersection
(
const edge& edgePointsA,
const edge& edgePointsB,
const PointField& points,
const vector& normal
)
{
const vector tau0 = perpendicular(normal);
const vector tau1 = normal ^ tau0;
const point& pointA0 = points[edgePointsA[0]];
const point& pointA1 = points[edgePointsA[1]];
const point& pointB0 = points[edgePointsB[0]];
const point& pointB1 = points[edgePointsB[1]];
const point2D point2DA0(tau0 & pointA0, tau1 & pointA0);
const point2D point2DA1(tau0 & pointA1, tau1 & pointA1);
const point2D point2DB0(tau0 & pointB0, tau1 & pointB0);
const point2D point2DB1(tau0 & pointB1, tau1 & pointB1);
const tensor2D M =
tensor2D(point2DA0 - point2DA1, point2DB1 - point2DB0).T();
const scalar detM = det(M);
const tensor2D detMInvM = cof(M);
const vector2D magDetMTu = sign(detM)*detMInvM & (point2DA0 - point2DB0);
return 0 <= cmptMin(magDetMTu) && cmptMax(magDetMTu) <= mag(detM);
}
template<class PointField>
Foam::label Foam::polygonTriangulate::nIntersections
(
const edge& edgePoints,
const PointField& points,
const vector& normal
)
{
label n = 0;
forAll(points, pi)
{
const edge otherEdgePoints(pi, points.fcIndex(pi));
if (edgePoints.commonVertex(otherEdgePoints) == -1)
{
n += intersection(edgePoints, otherEdgePoints, points, normal);
}
}
return n;
}
template<class PointField>
Foam::scalar Foam::polygonTriangulate::angle
(
const label pointi,
const PointField& points,
const vector& normal
)
{
const point& o = points[pointi];
const vector oa = points[points.rcIndex(pointi)] - o;
const vector ob = points[points.fcIndex(pointi)] - o;
const vector oaNegNNOa = oa - normal*(normal & oa);
const vector obNegNNOb = ob - normal*(normal & ob);
return
atan2(normal & (oaNegNNOa ^ obNegNNOb), - oaNegNNOa & obNegNNOb)
+ constant::mathematical::pi;
}
template<class PointField>
bool Foam::polygonTriangulate::ear
(
const label pointi,
const PointField& points,
const vector& normal
)
{
const point& o = points[pointi];
const vector oa = points[points.rcIndex(pointi)] - o;
const vector ob = points[points.fcIndex(pointi)] - o;
const tensor A = tensor(ob, oa, normal).T();
const tensor T(A.y() ^ A.z(), A.z() ^ A.x(), A.x() ^ A.y());
const scalar detA = det(A);
for
(
label pointj = points.fcIndex(points.fcIndex(pointi));
pointj != points.rcIndex(pointi);
pointj = points.fcIndex(pointj)
)
{
const vector detAY = (points[pointj] - o) & T;
if (detAY.x() > 0 && detAY.y() > 0 && detAY.x() + detAY.y() < detA)
{
return false;
}
}
return true;
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::List<Foam::point> Foam::polygonTriangulate::randomPolygon
(
Random& rndGen,
const label n,
const scalar error
)
{
// Get random points on a unit disk
List<point> points(n);
forAll(points, pointi)
{
const scalar theta =
2*constant::mathematical::pi*rndGen.sample01<scalar>();
const scalar r = sqrt(rndGen.sample01<scalar>());
points[pointi] = point(r*cos(theta), r*sin(theta), 0);
}
// Initialise intersected polygon
labelList pointis(identity(n));
// Reorder until non-intersected
bool incomplete = true;
while (incomplete)
{
incomplete = false;
for (label piA0 = 0; piA0 < n; ++ piA0)
{
const label piA1 = points.fcIndex(piA0);
for (label piB0 = piA0 + 2; piB0 < (piA0 == 0 ? n - 1 : n); ++ piB0)
{
const label piB1 = points.fcIndex(piB0);
if
(
intersection
(
edge(pointis[piA0], pointis[piA1]),
edge(pointis[piB0], pointis[piB1]),
points,
vector(0, 0, 1)
)
)
{
SubList<label> subOrder(pointis, piB0 + 1 - piA1, piA1);
inplaceReverseList(subOrder);
incomplete = true;
}
if (incomplete) break;
}
if (incomplete) break;
}
}
// Add noise and potential self-intersection
forAll(points, pointi)
{
const scalar theta =
2*constant::mathematical::pi*rndGen.sample01<scalar>();
const scalar r = sqrt(rndGen.sample01<scalar>());
points[pointi] =
(1 - error)*points[pointi]
+ error*point(r*cos(theta), r*sin(theta), rndGen.sample01<scalar>());
}
// Reorder and return
return List<point>(points, pointis);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class PointField>
void Foam::polygonTriangulate::optimiseTriangulation
(
const label trii,
const PointField& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris
)
{
const triFace& t = triPoints[trii];
const scalar q = quality(t, points, normal);
forAll(triEdges[trii], triEdgei)
{
const label edgei = triEdges[trii][triEdgei];
const label otherTrii = edgeTris[edgei][edgeTris[edgei][0] == trii];
if (otherTrii == -1) continue;
const label otherTriEdgei = findIndex(triEdges[otherTrii], edgei);
const triFace& otherT = triPoints[otherTrii];
const scalar otherQ = quality(otherT, points, normal);
const label piA = triPoints[trii][(triEdgei + 1) % 3];
const label piB = triPoints[trii][(triEdgei + 2) % 3];
const label piC = triPoints[otherTrii][(otherTriEdgei + 1) % 3];
const label piD = triPoints[otherTrii][(otherTriEdgei + 2) % 3];
const triFace flipT0(piA, piB, piD);
const triFace flipT1(piC, piD, piB);
if
(
triPointsSet_.found(flipT0)
|| triPointsSet_.found(flipT1)
) continue;
const scalar flipQ0 = quality(flipT0, points, normal);
const scalar flipQ1 = quality(flipT1, points, normal);
if (min(q, otherQ) < min(flipQ0, flipQ1))
{
triPointsSet_.set(t);
triPointsSet_.set(otherT);
const label eiA = triEdges[trii][(triEdgei + 1) % 3];
const label eiB = triEdges[trii][(triEdgei + 2) % 3];
const label eiC = triEdges[otherTrii][(otherTriEdgei + 1) % 3];
const label eiD = triEdges[otherTrii][(otherTriEdgei + 2) % 3];
triPoints[trii] = {piA, piB, piD};
triEdges[trii] = {eiA, edgei, eiD};
edgeTris[eiD][edgeTris[eiD][0] != otherTrii] = trii;
triPoints[otherTrii] = {piC, piD, piB};
triEdges[otherTrii] = {eiC, edgei, eiB};
edgeTris[eiB][edgeTris[eiB][0] != trii] = otherTrii;
optimiseTriangulation
(
trii,
points,
normal,
triPoints,
triEdges,
edgeTris
);
optimiseTriangulation
(
otherTrii,
points,
normal,
triPoints,
triEdges,
edgeTris
);
break;
}
}
}
void Foam::polygonTriangulate::simpleTriangulate
(
const UList<point>& allPoints,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool optimal
)
{
// Get the polygon size
const label n = allPoints.size();
// Clear the triangulation
triPoints = triFace(-1, -1, -1);
triEdges = FixedList<label, 3>({-1, -1, -1});
edgeTris = labelPair(-1, -1);
// Initialise workspace
pointis_.setSize(n);
edges_.setSize(n);
angle_.setSize(n);
ear_.setSize(n);
forAll(pointis_, i)
{
pointis_[i] = i;
edges_[i] = i;
angle_[i] = angle(i, allPoints, normal);
ear_[i] = ear(i, allPoints, normal);
}
// Create the indirect point list for the current un-triangulated polygon
UIndirectList<point> points(allPoints, pointis_);
// Generate triangles
forAll(triPoints, trii)
{
// Find the ear with the smallest angle
scalar minEarAngle = vGreat;
label minEarAnglei = -1;
for (label i = 0; i < pointis_.size(); ++ i)
{
if (ear_[i] && minEarAngle > angle_[i])
{
minEarAngle = angle_[i];
minEarAnglei = i;
}
}
// If nothing is an ear, then this face is degenerate. Default to
// the smallest angle, ignoring the ear test.
if (minEarAnglei == -1)
{
minEarAnglei = findMin(angle_);
}
// Get the adjacent points
label minEarAnglei0 = pointis_.rcIndex(minEarAnglei);
label minEarAnglei1 = pointis_.fcIndex(minEarAnglei);
// Add a triangle
triPoints[trii] = triFace
(
pointis_[minEarAnglei0],
pointis_[minEarAnglei],
pointis_[minEarAnglei1]
);
triEdges[trii] = FixedList<label, 3>
({
edges_[minEarAnglei0],
edges_[minEarAnglei],
trii == triPoints.size() - 1 ? edges_[minEarAnglei1] : n + trii
});
forAll(triEdges[trii], triEdgei)
{
const label edgei = triEdges[trii][triEdgei];
edgeTris[edgei][edgeTris[edgei][0] != -1] = trii;
}
// Remove the cut off point from the polygon
edges_[minEarAnglei0] = triEdges[trii][2];
for (label i = minEarAnglei; i < pointis_.size() - 1; ++ i)
{
pointis_[i] = pointis_[i + 1];
edges_[i] = edges_[i + 1];
angle_[i] = angle_[i + 1];
ear_[i] = ear_[i + 1];
}
pointis_.resize(pointis_.size() - 1);
edges_.resize(edges_.size() - 1);
angle_.resize(angle_.size() - 1);
ear_.resize(ear_.size() - 1);
// Update connected points
if (minEarAnglei0 > minEarAnglei) -- minEarAnglei0;
angle_[minEarAnglei0] = angle(minEarAnglei0, points, normal);
ear_[minEarAnglei0] = ear(minEarAnglei0, points, normal);
if (minEarAnglei1 > minEarAnglei) -- minEarAnglei1;
angle_[minEarAnglei1] = angle(minEarAnglei1, points, normal);
ear_[minEarAnglei1] = ear(minEarAnglei1, points, normal);
// Optimise the quality
if (optimal)
{
triPointsSet_.clear();
optimiseTriangulation
(
trii,
allPoints,
normal,
triPoints,
triEdges,
edgeTris
);
}
}
}
void Foam::polygonTriangulate::partitionTriangulate
(
const UList<point>& points,
const vector& normal,
const label spanPointi,
const label spanEdgei,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool simple,
const bool optimal
)
{
// Get the polygon size
const label n = points.size();
// Get the points of the spanning triangle
const label piA = (spanEdgei + 1) % n;
const label piP = spanPointi;
const label piB = spanEdgei;
// Determine the sizes of the polygons connected to either side of the
// spanning triangle
const label nA = (piP - piA + n) % n + 1;
const label nB = (piB - piP + n) % n + 1;
// Get the edges of the spanning triangle
const label eiA = nA >= 3 ? n : piA;
const label eiB = nB >= 3 ? n + (nA >= 3) : piP;
const label eiE = piB;
// Add the spanning triangle
triPoints[0] = triFace(piA, piP, piB);
triEdges[0] = FixedList<label, 3>({eiA, eiB, eiE});
// Rotate the point list so that it can be passed to sub-triangulations
// without indirect addressing
inplaceRotateList(const_cast<UList<point>&>(points), - piA);
// Triangulate the sub-polygon connected to edge A
if (nA >= 3)
{
// Subset the polygon and triangulate
SubList<triFace> triPointsA(triPoints, nA - 2, 1);
SubList<FixedList<label, 3>> triEdgesA(triEdges, nA - 2, 1);
SubList<labelPair> edgeTrisA(edgeTris, 2*nA - 3);
triangulate
(
SubList<point>(points, nA),
normal,
triPointsA,
triEdgesA,
edgeTrisA,
simple,
optimal
);
// Map the point labels back to the full polygon
forAll(triPointsA, triAi)
{
forAll(triPointsA[triAi], triPointAi)
{
label& pointi = triPointsA[triAi][triPointAi];
pointi = (pointi + piA) % n;
}
}
// Map the edge labels back to the full polygon
forAll(triEdgesA, triAi)
{
forAll(triEdgesA[triAi], triEdgeAi)
{
label& edgei = triEdgesA[triAi][triEdgeAi];
edgei =
edgei >= nA ? max(eiA, eiB) + edgei - nA + 1
: edgei == nA - 1 ? eiA
: (piA + edgei) % n;
}
}
// Map the tri labels back to the full polygon
forAll(edgeTrisA, edgeAi)
{
forAll(edgeTrisA[edgeAi], edgeTriAi)
{
label& trii = edgeTrisA[edgeAi][edgeTriAi];
trii = trii == -1 ? -1 : trii + 1;
}
}
}
// Triangulate the sub-polygon connected to edge B
if (nB >= 3)
{
// Subset the polygon and triangulate
SubList<triFace> triPointsB(triPoints, nB - 2, nA - 1);
SubList<FixedList<label, 3>> triEdgesB(triEdges, nB - 2, nA - 1);
SubList<labelPair> edgeTrisB(edgeTris, 2*nB - 3, 2*nA - 3);
triangulate
(
SubList<point>(points, nB, nA - 1),
normal,
triPointsB,
triEdgesB,
edgeTrisB,
simple,
optimal
);
// Map the point labels back to the full polygon
forAll(triPointsB, triBi)
{
forAll(triPointsB[triBi], triPointBi)
{
label& pointi = triPointsB[triBi][triPointBi];
pointi = (pointi + piA + nA - 1) % n;
}
}
// Map the edge labels back to the full polygon
forAll(triEdgesB, triBi)
{
forAll(triEdgesB[triBi], triEdgeBi)
{
label& edgei = triEdgesB[triBi][triEdgeBi];
edgei =
edgei >= nB ? max(eiA, eiB) + nA - 3 + edgei - nB + 1
: edgei == nB - 1 ? eiB
: (piA + nA - 1 + edgei) % n;
}
}
// Map the tri labels back to the full polygon
forAll(edgeTrisB, edgeBi)
{
forAll(edgeTrisB[edgeBi], edgeTriBi)
{
label& trii = edgeTrisB[edgeBi][edgeTriBi];
trii = trii == -1 ? -1 : trii + nA - 1;
}
}
}
// Rotate the point list back
inplaceRotateList(const_cast<UList<point>&>(points), piA);
// Reorder the edge-tris
{
// Swap the A-internal-edges and B-outer-edges to get all outer
// edges and all internal edges in contiguous blocks
SubList<labelPair> l(edgeTris, nA + nB - 3, nA - 1);
inplaceRotateList(l, - nA + 2);
}
{
// Rotate the outer edges right by one so that the intersection
// edge (currently at the end) moves adjacent to the outer edges
SubList<labelPair> l(edgeTris, nA + nB - 3, nA + nB - 2);
inplaceRotateList(l, 1);
}
{
// Rotate the outer edges so that they are in sequence with the
// original point ordering
SubList<labelPair> l(edgeTris, n);
inplaceRotateList(l, - n + piA);
}
if (nA >= 3 && nB >= 3)
{
// Move edge-B leftwards adjacent to edge-A as this is created
// before any of the other internal edges
const label fromi = n + nA - 2, toi = n + 1;
const labelPair temp = edgeTris[fromi];
for (label i = fromi; i > toi; -- i)
{
edgeTris[i] = edgeTris[i-1];
}
edgeTris[toi] = temp;
}
// Add associations to the intersection triangle
edgeTris[eiA][edgeTris[eiA][0] != -1] = 0;
edgeTris[eiB][edgeTris[eiB][0] != -1] = 0;
edgeTris[eiE] = labelPair(0, -1);
}
void Foam::polygonTriangulate::complexTriangulate
(
const UList<point>& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool optimal
)
{
// Get the polygon size
const label n = points.size();
// Detect self intersections. When one is found, remove one of the
// intersected edges by adding a spanning triangle and recurse. Pick the
// spanning triangle that results in the smallest negative area.
for (label piA0 = 0; piA0 < n; ++ piA0)
{
const label piA1 = points.fcIndex(piA0);
for (label piB0 = piA0 + 2; piB0 < (piA0 == 0 ? n - 1 : n); ++ piB0)
{
const label piB1 = points.fcIndex(piB0);
if
(
intersection
(
edge(piA0, piA1),
edge(piB0, piB1),
points,
normal
)
)
{
// Get a bunch of unique spanning triangles that remove one of
// the intersected edges
FixedList<labelPair, 8> spanPointAndEdgeis
({
labelPair(piA0, piB0),
labelPair(piA1, piB0),
labelPair(piB0, piA0),
labelPair(piB1, piA0),
labelPair(points.rcIndex(piA0), piA0),
labelPair(points.fcIndex(piA1), piA0),
labelPair(points.rcIndex(piB0), piB0),
labelPair(points.fcIndex(piB1), piB0)
});
forAll(spanPointAndEdgeis, spani)
{
for (label spanj = spani + 1; spanj < 8; ++ spanj)
{
if
(
spanPointAndEdgeis[spani]
== spanPointAndEdgeis[spanj]
)
{
spanPointAndEdgeis[spanj] = labelPair(-1, -1);
}
}
}
// Find the spanning triangle that results in the smallest
// negative triangulation area
scalar spanSumNegA = - vGreat;
label spanPointi = -1, spanEdgei = -1;
forAll(spanPointAndEdgeis, spani)
{
if (spanPointAndEdgeis[spani] == labelPair(-1, -1))
continue;
const label piP = spanPointAndEdgeis[spani].first();
const label ei = spanPointAndEdgeis[spani].second();
const label piA0 = points.rcIndex(ei);
const label piA = ei;
const label piB = points.fcIndex(ei);
const label piB1 = points.fcIndex(piB);
// Only consider this spanning triangle if it decreases
// the number of intersections
const label netNIntersections =
- nIntersections(edge(piA, piB), points, normal)
+ (piP == piA0 ? -1 : +1)
*nIntersections(edge(piP, piA), points, normal)
+ (piP == piB1 ? -1 : +1)
*nIntersections(edge(piP, piB), points, normal);
if (netNIntersections >= 0) continue;
// Triangulate
partitionTriangulate
(
points,
normal,
piP,
ei,
triPoints,
triEdges,
edgeTris,
false,
false
);
// Compute the negative area. If it is smaller than the
// previous value then update the spanning triangle. If it
// is zero then break and use this triangle.
scalar sumNegA = 0;
forAll(triPoints, trii)
{
const scalar a = area(triPoints[trii], points, normal);
sumNegA += negPart(a);
}
if (sumNegA > spanSumNegA)
{
spanSumNegA = sumNegA;
spanPointi = piP;
spanEdgei = ei;
}
if (spanSumNegA == 0)
{
break;
}
}
// If a suitable spanning triangle was found then partition the
// triangulation
if (spanPointi != -1)
{
partitionTriangulate
(
points,
normal,
spanPointi,
spanEdgei,
triPoints,
triEdges,
edgeTris,
false,
optimal
);
return;
}
}
}
}
// If there are no intersections then do simple polygon triangulation
simpleTriangulate(points, normal, triPoints, triEdges, edgeTris, optimal);
}
void Foam::polygonTriangulate::triangulate
(
const UList<point>& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool simple,
const bool optimal
)
{
if (simple)
{
simpleTriangulate
(
points,
normal,
triPoints,
triEdges,
edgeTris,
optimal
);
}
else
{
complexTriangulate
(
points,
normal,
triPoints,
triEdges,
edgeTris,
optimal
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::polygonTriangulate::polygonTriangulate()
:
pointis_(),
edges_(),
angle_(),
ear_(),
triPointsSet_(),
points_(),
triPoints_(),
triEdges_(),
edgeTris_()
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::polygonTriangulate::~polygonTriangulate()
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
const Foam::UList<Foam::triFace>& Foam::polygonTriangulate::triangulate
(
const UList<point>& points,
const vector& normal,
const bool simple,
const bool optimal
)
{
// Get the polygon size
const label n = points.size();
// Resize workspace
triPoints_.resize(n - 2);
triEdges_.resize(n - 2);
edgeTris_.resize(2*n - 3);
// Run
triangulate
(
points,
normal,
triPoints_,
triEdges_,
edgeTris_,
simple,
optimal
);
return triPoints_;
}
const Foam::UList<Foam::triFace>& Foam::polygonTriangulate::triangulate
(
const UList<point>& points,
const bool simple,
const bool optimal
)
{
return
triangulate
(
points,
normalised(face::area(points)),
simple,
optimal
);
}
// ************************************************************************* //

View File

@ -0,0 +1,351 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021 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/>.
Class
Foam::polygonTriangulate
Description
Triangulation of three-dimensional polygons
SourceFiles
polygonTriangulate.C
\*---------------------------------------------------------------------------*/
#ifndef polygonTriangulate_H
#define polygonTriangulate_H
#include "DynamicList.H"
#include "HashSet.H"
#include "labelPair.H"
#include "triFace.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class polygonTriangulate Declaration
\*---------------------------------------------------------------------------*/
class polygonTriangulate
{
// Private Data
//- Indirect addressing into point field to form the current as yet
// un-triangulated polygon
DynamicList<label> pointis_;
//- Edge indices of the un-triangulated polygon
DynamicList<label> edges_;
//- The interior angles of the vertices of the un-triangulated polygon
DynamicList<scalar> angle_;
//- Flags to denote whether points of the un-triangulated polygon are
// "ears"; i.e., that the triangle formed by adding a diagonal between
// two adjacent points contains no other point
DynamicList<bool> ear_;
//- Set of tri-faces used to mark previously considered configurations
// in optimisation and prevent unnecessary repetition
HashSet<triFace, Hash<triFace>> triPointsSet_;
//- Point array. Used if the input points cannot be SubList-d.
DynamicList<point> points_;
//- Tri-points
DynamicList<triFace> triPoints_;
//- Tri-edge associations
DynamicList<FixedList<label, 3>> triEdges_;
//- Edge-tri associations
DynamicList<labelPair> edgeTris_;
// Private Static Member Functions
// Renumber a polygon label to global indexing
static inline label renumberPolyToGlobal
(
const label triPoly,
const UList<label>& polyToGlobal
);
// Renumber a container of polygon labels to global indexing
template<class Type>
static inline Type renumberPolyToGlobal
(
const Type& triPoly,
const UList<label>& polyToGlobal
);
//- Return the area of a triangle projected in a normal direction
template<class PointField>
static scalar area
(
const triFace& triPoints,
const PointField& points,
const vector& normal
);
//- Return the quality of a triangle projected in a normal direction
template<class PointField>
static scalar quality
(
const triFace& triPoints,
const PointField& points,
const vector& normal
);
//- Return whether or not two edges intersect in the plane defined by a
// normal
template<class PointField>
static bool intersection
(
const edge& edgePointsA,
const edge& edgePointsB,
const PointField& points,
const vector& normal
);
//- Return the number of intersections of an edge within a polygon
template<class PointField>
static label nIntersections
(
const edge& edgePoints,
const PointField& points,
const vector& normal
);
//- Return the interior angle of the point in a polygon in the plane
// defined by a normal
template<class PointField>
static scalar angle
(
const label pointi,
const PointField& points,
const vector& normal
);
//- Return whether a point in a polygon is an "ear"; i.e., that the
// triangle formed by adding a diagonal between the two adjacent
// points contains no other point
template<class PointField>
static bool ear
(
const label pointi,
const PointField& points,
const vector& normal
);
// Private Member Functions
//- Optimise the triangulation quality by flipping edges
template<class PointField>
void optimiseTriangulation
(
const label trii,
const PointField& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris
);
//- Perform triangulation of a polygon by ear clipping, assuming that
// the polygon is simple/non-intersecting
void simpleTriangulate
(
const UList<point>& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool optimal
);
//- Perform triangulation of a polygon, first by adding a spanning
// triangle between a point and an edge, then recursing into the
// sub-polygons on either side
void partitionTriangulate
(
const UList<point>& points,
const vector& normal,
const label spanPointi,
const label spanEdgei,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool simple,
const bool optimal
);
//- Perform triangulation of the given polygon, detecting self
// intersections and resolving them by adding spanning triangles prior
// to simple triangulation
void complexTriangulate
(
const UList<point>& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool optimal
);
//- Perform triangulation of the given polygon
void triangulate
(
const UList<point>& points,
const vector& normal,
UList<triFace>& triPoints,
UList<FixedList<label, 3>>& triEdges,
UList<labelPair>& edgeTris,
const bool simple = false,
const bool optimal = true
);
public:
// Static Member Functions
//- Generate a random polygon for testing purposes
static List<point> randomPolygon
(
Random& rndGen,
const label n,
const scalar error
);
// Constructors
//- Construct null
polygonTriangulate();
//- Disallow default bitwise copy construction
polygonTriangulate(const polygonTriangulate&) = delete;
//- Destructor
~polygonTriangulate();
// Member Functions
// Access
//- Get the triangles' points
inline const UList<triFace>& triPoints() const;
//- Get the triangles' renumbered points
inline List<triFace> triPoints
(
const UList<label>& polyPoints
) const;
//- Get a triangle's renumbered points
inline triFace triPoints
(
const label trii,
const UList<label>& polyPoints
) const;
//- Get the triangles' edges
inline const UList<FixedList<label, 3>>& triEdges() const;
//- Get the triangles' renumbered edges
inline List<FixedList<label, 3>> triEdges
(
const UList<label>& polyEdges
) const;
//- Get a triangle's renumbered edges
inline FixedList<label, 3> triEdges
(
const label trii,
const UList<label>& polyEdges
) const;
//- Perform triangulation of the given polygon
const UList<triFace>& triangulate
(
const UList<point>& points,
const vector& normal,
const bool simple = false,
const bool optimal = true
);
//- Perform triangulation of the given polygon
const UList<triFace>& triangulate
(
const UList<point>& points,
const bool simple = false,
const bool optimal = true
);
//- Perform triangulation of the given polygon
inline const UList<triFace>& triangulate
(
const UIndirectList<point>& points,
const vector& normal,
const bool simple = false,
const bool optimal = true
);
//- Perform triangulation of the given polygon
inline const UList<triFace>& triangulate
(
const UIndirectList<point>& points,
const bool simple = false,
const bool optimal = true
);
// Member Operators
//- Disallow default bitwise assignment
void operator=(const polygonTriangulate&) = delete;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "polygonTriangulateI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,138 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021 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 "polygonTriangulate.H"
// * * * * * * * * * * * Private Static Member Functions * * * * * * * * * * //
inline Foam::label Foam::polygonTriangulate::renumberPolyToGlobal
(
const label triPoly,
const UList<label>& polyToGlobal
)
{
return triPoly < polyToGlobal.size() ? polyToGlobal[triPoly] : -1;
}
template<class Type>
inline Type Foam::polygonTriangulate::renumberPolyToGlobal
(
const Type& triPoly,
const UList<label>& polyToGlobal
)
{
Type result;
result.resize(triPoly.size());
forAll(triPoly, i)
{
result[i] = renumberPolyToGlobal(triPoly[i], polyToGlobal);
}
return result;
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
inline const Foam::UList<Foam::triFace>&
Foam::polygonTriangulate::triPoints() const
{
return triPoints_;
}
inline Foam::List<Foam::triFace> Foam::polygonTriangulate::triPoints
(
const UList<label>& polyPoints
) const
{
return renumberPolyToGlobal(triPoints_, polyPoints);
}
inline Foam::triFace Foam::polygonTriangulate::triPoints
(
const label trii,
const UList<label>& polyPoints
) const
{
return renumberPolyToGlobal(triPoints_[trii], polyPoints);
}
inline const Foam::UList<Foam::FixedList<Foam::label, 3>>&
Foam::polygonTriangulate::triEdges() const
{
return triEdges_;
}
inline Foam::List<Foam::FixedList<Foam::label, 3>>
Foam::polygonTriangulate::triEdges
(
const UList<label>& polyEdges
) const
{
return renumberPolyToGlobal(triEdges_, polyEdges);
}
inline Foam::FixedList<Foam::label, 3> Foam::polygonTriangulate::triEdges
(
const label trii,
const UList<label>& polyEdges
) const
{
return renumberPolyToGlobal(triEdges_[trii], polyEdges);
}
inline const Foam::UList<Foam::triFace>& Foam::polygonTriangulate::triangulate
(
const UIndirectList<point>& points,
const vector& normal,
const bool simple,
const bool optimal
)
{
points_ = points;
return triangulate(points_, normal, simple, optimal);
}
inline const Foam::UList<Foam::triFace>& Foam::polygonTriangulate::triangulate
(
const UIndirectList<point>& points,
const bool simple,
const bool optimal
)
{
points_ = points;
return triangulate(points_, simple, optimal);
}
// ************************************************************************* //

View File

@ -35,256 +35,6 @@ License
const char* const Foam::face::typeName = "face";
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::tmp<Foam::vectorField>
Foam::face::calcEdges(const pointField& points) const
{
tmp<vectorField> tedges(new vectorField(size()));
vectorField& edges = tedges.ref();
forAll(*this, i)
{
label ni = fcIndex(i);
point thisPt = points[operator[](i)];
point nextPt = points[operator[](ni)];
vector vec(nextPt - thisPt);
vec /= Foam::mag(vec) + vSmall;
edges[i] = vec;
}
return tedges;
}
Foam::scalar Foam::face::edgeCos
(
const vectorField& edges,
const label index
) const
{
label leftEdgeI = left(index);
label rightEdgeI = right(index);
// Note negate on left edge to get correct left-pointing edge.
return -(edges[leftEdgeI] & edges[rightEdgeI]);
}
Foam::label Foam::face::mostConcaveAngle
(
const pointField& points,
const vectorField& edges,
scalar& maxAngle
) const
{
vector a(area(points));
label index = 0;
maxAngle = -great;
forAll(edges, i)
{
label leftEdgeI = left(i);
label rightEdgeI = right(i);
vector edgeNormal = edges[rightEdgeI] ^ edges[leftEdgeI];
scalar edgeCos = edges[leftEdgeI] & edges[rightEdgeI];
scalar edgeAngle = acos(max(-1.0, min(1.0, edgeCos)));
scalar angle;
if ((edgeNormal & a) > 0)
{
// Concave angle.
angle = constant::mathematical::pi + edgeAngle;
}
else
{
// Convex angle. Note '-' to take into account that rightEdge
// and leftEdge are head-to-tail connected.
angle = constant::mathematical::pi - edgeAngle;
}
if (angle > maxAngle)
{
maxAngle = angle;
index = i;
}
}
return index;
}
Foam::label Foam::face::split
(
const face::splitMode mode,
const pointField& points,
label& triI,
label& quadI,
faceList& triFaces,
faceList& quadFaces
) const
{
label oldIndices = (triI + quadI);
if (size() <= 2)
{
FatalErrorInFunction
<< "Serious problem: asked to split a face with < 3 vertices"
<< abort(FatalError);
}
if (size() == 3)
{
// Triangle. Just copy.
if (mode == COUNTTRIANGLE || mode == COUNTQUAD)
{
triI++;
}
else
{
triFaces[triI++] = *this;
}
}
else if (size() == 4)
{
if (mode == COUNTTRIANGLE)
{
triI += 2;
}
if (mode == COUNTQUAD)
{
quadI++;
}
else if (mode == SPLITTRIANGLE)
{
// Start at point with largest internal angle.
const vectorField edges(calcEdges(points));
scalar minAngle;
label startIndex = mostConcaveAngle(points, edges, minAngle);
label nextIndex = fcIndex(startIndex);
label splitIndex = fcIndex(nextIndex);
// Create triangles
face triFace(3);
triFace[0] = operator[](startIndex);
triFace[1] = operator[](nextIndex);
triFace[2] = operator[](splitIndex);
triFaces[triI++] = triFace;
triFace[0] = operator[](splitIndex);
triFace[1] = operator[](fcIndex(splitIndex));
triFace[2] = operator[](startIndex);
triFaces[triI++] = triFace;
}
else
{
quadFaces[quadI++] = *this;
}
}
else
{
// General case. Like quad: search for largest internal angle.
const vectorField edges(calcEdges(points));
scalar minAngle = 1;
label startIndex = mostConcaveAngle(points, edges, minAngle);
scalar bisectAngle = minAngle/2;
vector rightEdge = edges[right(startIndex)];
//
// Look for opposite point which as close as possible bisects angle
//
// split candidate starts two points away.
label index = fcIndex(fcIndex(startIndex));
label minIndex = index;
scalar minDiff = constant::mathematical::pi;
for (label i = 0; i < size() - 3; i++)
{
vector splitEdge
(
points[operator[](index)]
- points[operator[](startIndex)]
);
splitEdge /= Foam::mag(splitEdge) + vSmall;
const scalar splitCos = splitEdge & rightEdge;
const scalar splitAngle = acos(max(-1.0, min(1.0, splitCos)));
const scalar angleDiff = fabs(splitAngle - bisectAngle);
if (angleDiff < minDiff)
{
minDiff = angleDiff;
minIndex = index;
}
// Go to next candidate
index = fcIndex(index);
}
// Split into two subshapes.
// face1: startIndex to minIndex
// face2: minIndex to startIndex
// Get sizes of the two subshapes
label diff = 0;
if (minIndex > startIndex)
{
diff = minIndex - startIndex;
}
else
{
// Folded around
diff = minIndex + size() - startIndex;
}
label nPoints1 = diff + 1;
label nPoints2 = size() - diff + 1;
// Collect face1 points
face face1(nPoints1);
index = startIndex;
for (label i = 0; i < nPoints1; i++)
{
face1[i] = operator[](index);
index = fcIndex(index);
}
// Collect face2 points
face face2(nPoints2);
index = minIndex;
for (label i = 0; i < nPoints2; i++)
{
face2[i] = operator[](index);
index = fcIndex(index);
}
// Split faces
face1.split(mode, points, triI, quadI, triFaces, quadFaces);
face2.split(mode, points, triI, quadI, triFaces, quadFaces);
}
return (triI + quadI - oldIndices);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::face::face(const triFace& f)
@ -714,53 +464,6 @@ int Foam::face::edgeDirection(const edge& e) const
}
Foam::label Foam::face::nTriangles(const pointField&) const
{
return nTriangles();
}
Foam::label Foam::face::triangles
(
const pointField& points,
label& triI,
faceList& triFaces
) const
{
label quadI = 0;
faceList quadFaces;
return split(SPLITTRIANGLE, points, triI, quadI, triFaces, quadFaces);
}
Foam::label Foam::face::nTrianglesQuads
(
const pointField& points,
label& triI,
label& quadI
) const
{
faceList triFaces;
faceList quadFaces;
return split(COUNTQUAD, points, triI, quadI, triFaces, quadFaces);
}
Foam::label Foam::face::trianglesQuads
(
const pointField& points,
label& triI,
label& quadI,
faceList& triFaces,
faceList& quadFaces
) const
{
return split(SPLITQUAD, points, triI, quadI, triFaces, quadFaces);
}
Foam::label Foam::longestEdge(const face& f, const pointField& pts)
{
const edgeList& eds = f.edges();

View File

@ -77,58 +77,6 @@ class face
:
public labelList
{
// Private Member Functions
//- Edge to the right of face vertex i
inline label right(const label i) const;
//- Edge to the left of face vertex i
inline label left(const label i) const;
//- Construct list of edge vectors for face
tmp<vectorField> calcEdges
(
const pointField& points
) const;
//- Cos between neighbouring edges
scalar edgeCos
(
const vectorField& edges,
const label index
) const;
//- Find index of largest internal angle on face
label mostConcaveAngle
(
const pointField& points,
const vectorField& edges,
scalar& edgeCos
) const;
//- Enumeration listing the modes for split()
enum splitMode
{
COUNTTRIANGLE, // count if split into triangles
COUNTQUAD, // count if split into triangles&quads
SPLITTRIANGLE, // split into triangles
SPLITQUAD // split into triangles&quads
};
//- Split face into triangles or triangles&quads.
// Stores results quadFaces[quadI], triFaces[triI]
// Returns number of new faces created
label split
(
const splitMode mode,
const pointField& points,
label& triI,
label& quadI,
faceList& triFaces,
faceList& quadFaces
) const;
public:
//- Return types for classify
@ -330,56 +278,8 @@ public:
// - -1: reverse (clockwise) on the face
int edgeDirection(const edge&) const;
// Face splitting utilities
//- Number of triangles after splitting
inline label nTriangles() const;
//- Number of triangles after splitting
label nTriangles(const pointField& points) const;
//- Split into triangles using existing points.
// Result in triFaces[triI..triI+nTri].
// Splits intelligently to maximise triangle quality.
// Returns number of faces created.
label triangles
(
const pointField& points,
label& triI,
faceList& triFaces
) const;
//- Split into triangles using existing points.
// Append to DynamicList.
// Returns number of faces created.
template<unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
label triangles
(
const pointField& points,
DynamicList<face, SizeInc, SizeMult, SizeDiv>& triFaces
) const;
//- Number of triangles and quads after splitting
// Returns the sum of both
label nTrianglesQuads
(
const pointField& points,
label& nTris,
label& nQuads
) const;
//- Split into triangles and quads.
// Results in triFaces (starting at triI) and quadFaces
// (starting at quadI).
// Returns number of new faces created.
label trianglesQuads
(
const pointField& points,
label& triI,
label& quadI,
faceList& triFaces,
faceList& quadFaces
) const;
//- Size of the face's triangulation
inline label nTriangles() const;
//- Compare faces
// 0: different

View File

@ -23,20 +23,6 @@ License
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
inline Foam::label Foam::face::right(const label i) const
{
return i;
}
inline Foam::label Foam::face::left(const label i) const
{
return rcIndex(i);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::face::face()

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -136,24 +136,6 @@ Foam::vector Foam::face::area(const PointField& ps)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
Foam::label Foam::face::triangles
(
const pointField& points,
DynamicList<face, SizeInc, SizeMult, SizeDiv>& triFaces
) const
{
label triI = triFaces.size();
label quadI = 0;
faceList quadFaces;
// adjust the addressable size (and allocate space if needed)
triFaces.setSize(triI + nTriangles());
return split(SPLITTRIANGLE, points, triI, quadI, triFaces, quadFaces);
}
template<class Type>
Type Foam::face::average
(

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2012-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2012-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -131,7 +131,6 @@ void Foam::ParticleCollector<CloudType>::initPolygons
label pointOffset = 0;
points_.setSize(nPoints);
faces_.setSize(polygons.size());
faceTris_.setSize(polygons.size());
area_.setSize(polygons.size());
forAll(faces_, facei)
{
@ -139,11 +138,6 @@ void Foam::ParticleCollector<CloudType>::initPolygons
face f(identity(polyPoints.size()) + pointOffset);
UIndirectList<point>(points_, f) = polyPoints;
area_[facei] = f.mag(points_);
DynamicList<face> tris;
f.triangles(points_, tris);
faceTris_[facei].transfer(tris);
faces_[facei].transfer(f);
pointOffset += polyPoints.size();
@ -527,7 +521,6 @@ Foam::ParticleCollector<CloudType>::ParticleCollector
removeCollected_(this->coeffDict().lookup("removeCollected")),
points_(),
faces_(),
faceTris_(),
nSector_(0),
radius_(),
coordSys_("coordSys", vector::zero, axesRotation(sphericalTensor::I)),
@ -613,7 +606,6 @@ Foam::ParticleCollector<CloudType>::ParticleCollector
removeCollected_(pc.removeCollected_),
points_(pc.points_),
faces_(pc.faces_),
faceTris_(pc.faceTris_),
nSector_(pc.nSector_),
radius_(pc.radius_),
coordSys_(pc.coordSys_),

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2012-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2012-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -144,11 +144,6 @@ private:
List<face> faces_;
// Polygon collector
//- Triangulation of faces
List<List<face>> faceTris_;
// Concentric circles collector
//- Number of sectors per circle

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2013-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2013-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -30,6 +30,7 @@ License
#include "triPointRef.H"
#include "volFields.H"
#include "polyMeshTetDecomposition.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -94,24 +95,25 @@ void Foam::patchInjectionBase::updateMesh(const polyMesh& mesh)
// Triangulate the patch faces and create addressing
DynamicList<label> triToFace(2*patch.size());
DynamicList<scalar> triMagSf(2*patch.size());
DynamicList<face> triFace(2*patch.size());
DynamicList<face> tris(5);
DynamicList<triFace> triFace(2*patch.size());
// Set zero value at the start of the tri area list
triMagSf.append(0.0);
// Create a triangulation engine
polygonTriangulate triEngine;
forAll(patch, facei)
{
const face& f = patch[facei];
tris.clear();
f.triangles(points, tris);
triEngine.triangulate(UIndirectList<point>(points, f));
forAll(tris, i)
forAll(triEngine.triPoints(), i)
{
triToFace.append(facei);
triFace.append(tris[i]);
triMagSf.append(tris[i].mag(points));
triFace.append(triEngine.triPoints(i, f));
triMagSf.append(triEngine.triPoints(i, f).mag(points));
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2013-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2013-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -45,6 +45,7 @@ SourceFiles
#include "scalarList.H"
#include "vectorList.H"
#include "faceList.H"
#include "triFaceList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -82,7 +83,7 @@ protected:
labelList cellOwners_;
//- Decomposed patch faces as a list of triangles
faceList triFace_;
triFaceList triFace_;
//- Addressing from per triangle to patch face
labelList triToFace_;

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -147,7 +147,7 @@ Foam::tmp<Foam::scalarField> Foam::AMIInterpolation::patchMagSf
const pointField& patchPoints = patch.localPoints();
faceList patchFaceTris;
triFaceList patchFaceTris;
forAll(result, patchFacei)
{
@ -162,12 +162,7 @@ Foam::tmp<Foam::scalarField> Foam::AMIInterpolation::patchMagSf
forAll(patchFaceTris, i)
{
result[patchFacei] +=
triPointRef
(
patchPoints[patchFaceTris[i][0]],
patchPoints[patchFaceTris[i][1]],
patchPoints[patchFaceTris[i][2]]
).mag();
patchFaceTris[i].tri(patchPoints).mag();
}
}

View File

@ -395,7 +395,7 @@ Foam::scalar Foam::sweptFaceAreaWeightAMI::interArea
// Triangulate the faces
const faceAreaIntersect::triangulationMode triMode = this->triMode_;
faceList srcFaceTris, tgtFaceTris;
triFaceList srcFaceTris, tgtFaceTris;
faceAreaIntersect::triangulate(srcFace, srcPoints, triMode, srcFaceTris);
faceAreaIntersect::triangulate(tgtFace, tgtPoints, triMode, tgtFaceTris);
@ -403,7 +403,7 @@ Foam::scalar Foam::sweptFaceAreaWeightAMI::interArea
scalar areaMag = Zero;
// Loop the target triangles
forAllConstIter(faceList, tgtFaceTris, tgtIter)
forAllConstIter(triFaceList, tgtFaceTris, tgtIter)
{
const FixedList<point, 3>
tgtTri =
@ -414,7 +414,7 @@ Foam::scalar Foam::sweptFaceAreaWeightAMI::interArea
};
// Loop the source triangles
forAllConstIter(faceList, srcFaceTris, srcIter)
forAllConstIter(triFaceList, srcFaceTris, srcIter)
{
FixedList<point, 4>
srcTri =

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "faceAreaIntersect.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -330,7 +331,7 @@ void Foam::faceAreaIntersect::triangulate
const face& f,
const pointField& points,
const triangulationMode& triMode,
faceList& faceTris
triFaceList& faceTris
)
{
faceTris.resize(f.nTriangles());
@ -341,7 +342,6 @@ void Foam::faceAreaIntersect::triangulate
{
for (label i = 0; i < f.nTriangles(); ++ i)
{
faceTris[i] = face(3);
faceTris[i][0] = f[0];
faceTris[i][1] = f[i + 1];
faceTris[i][2] = f[i + 2];
@ -351,18 +351,9 @@ void Foam::faceAreaIntersect::triangulate
}
case tmMesh:
{
const label nFaceTris = f.nTriangles();
label nFaceTris1 = 0;
const label nFaceTris2 = f.triangles(points, nFaceTris1, faceTris);
if (nFaceTris != nFaceTris1 || nFaceTris != nFaceTris2)
{
FatalErrorInFunction
<< "The numbers of reported triangles in the face do not "
<< "match that generated by the triangulation"
<< exit(FatalError);
}
polygonTriangulate triEngine;
triEngine.triangulate(UIndirectList<point>(points, f));
faceTris = triEngine.triPoints(f);
}
}
}
@ -377,7 +368,7 @@ Foam::scalar Foam::faceAreaIntersect::calc
)
{
// split faces into triangles
faceList trisA, trisB;
triFaceList trisA, trisB;
triangulate(faceA, pointsA_, triMode, trisA);
triangulate(faceB, pointsB_, triMode, trisB);

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -42,6 +42,7 @@ SourceFiles
#include "plane.H"
#include "face.H"
#include "NamedEnum.H"
#include "triFaceList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -92,7 +93,7 @@ private:
inline triPoints getTriPoints
(
const pointField& points,
const face& f,
const triFace& f,
const bool reverse
) const;
@ -162,7 +163,7 @@ public:
const face& f,
const pointField& points,
const triangulationMode& triMode,
faceList& faceTris
triFaceList& faceTris
);
//- Return area of intersection of faceA with faceB

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -44,7 +44,7 @@ inline void Foam::faceAreaIntersect::setTriPoints
inline Foam::faceAreaIntersect::triPoints Foam::faceAreaIntersect::getTriPoints
(
const pointField& points,
const face& f,
const triFace& f,
const bool reverse
) const
{

View File

@ -26,7 +26,7 @@ License
#include "intersectedSurface.H"
#include "surfaceIntersection.H"
#include "faceList.H"
#include "faceTriangulation.H"
#include "polygonTriangulate.H"
#include "treeBoundBox.H"
#include "OFstream.H"
#include "error.H"
@ -1185,6 +1185,9 @@ Foam::intersectedSurface::intersectedSurface
// Start in newTris for decomposed face.
labelList startTriI(surf.size(), 0);
// Create a triangulation engine
polygonTriangulate triEngine;
forAll(surf, facei)
{
startTriI[facei] = newTris.size();
@ -1209,56 +1212,21 @@ Foam::intersectedSurface::intersectedSurface
{
const face& newF = newFaces[newFacei];
// {
// fileName fName
// (
// "face_"
// + Foam::name(facei)
// + "_subFace_"
// + Foam::name(newFacei)
// + ".obj"
// );
// Pout<< "Writing original face:" << facei << " subFace:"
// << newFacei << " to " << fName << endl;
//
// OFstream str(fName);
//
// forAll(newF, fp)
// {
// meshTools::writeOBJ(str, eSurf.points()[newF[fp]]);
// }
// str << 'l';
// forAll(newF, fp)
// {
// str << ' ' << fp+1;
// }
// str<< " 1" << nl;
// }
const vector& n = surf.faceNormals()[facei];
const label region = surf[facei].region();
faceTriangulation tris(eSurf.points(), newF, n);
triEngine.triangulate
(
UIndirectList<point>(eSurf.points(), newF),
n
);
forAll(tris, triI)
forAll(triEngine.triPoints(), trii)
{
const triFace& t = tris[triI];
forAll(t, i)
{
if (t[i] < 0 || t[i] >= eSurf.points().size())
{
FatalErrorInFunction
<< "Face triangulation of face " << facei
<< " uses points outside range 0.."
<< eSurf.points().size()-1 << endl
<< "Triangulation:"
<< tris << abort(FatalError);
}
}
newTris.append(labelledTri(t[0], t[1], t[2], region));
newTris.append
(
labelledTri(triEngine.triPoints(trii, newF), region)
);
}
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -39,8 +39,7 @@ Description
nSurfaceEdges)
- construct face-edge addressing for above edges
- for each face do a right-handed walk to reconstruct faces (splitFace)
- retriangulate resulting faces (might be non-convex so use
faceTriangulation which does proper bisection)
- retriangulate resulting faces
The resulting surface will have the points from the surface first
in the point list (0 .. nSurfacePoints-1)

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -31,6 +31,7 @@ License
#include "polyMesh.H"
#include "plane.H"
#include "geompack.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -2342,6 +2343,8 @@ Foam::triSurface Foam::triSurfaceTools::triangulate
mesh.nFaces() - mesh.nInternalFaces()
);
polygonTriangulate triEngine;
label newPatchi = 0;
forAllConstIter(labelHashSet, includePatches, iter)
@ -2356,17 +2359,14 @@ Foam::triSurface Foam::triSurfaceTools::triangulate
{
const face& f = patch[patchFacei];
faceList triFaces(f.nTriangles(points));
triEngine.triangulate(UIndirectList<point>(points, f));
label nTri = 0;
f.triangles(points, nTri, triFaces);
forAll(triFaces, triFacei)
forAll(triEngine.triPoints(), triFacei)
{
const face& f = triFaces[triFacei];
triangles.append(labelledTri(f[0], f[1], f[2], newPatchi));
triangles.append
(
labelledTri(triEngine.triPoints(triFacei, f), newPatchi)
);
nTriTotal++;
}
@ -2429,6 +2429,8 @@ Foam::triSurface Foam::triSurfaceTools::triangulate
mesh.nFaces() - mesh.nInternalFaces()
);
polygonTriangulate triEngine;
label newPatchi = 0;
forAllConstIter(labelHashSet, includePatches, iter)
@ -2445,17 +2447,14 @@ Foam::triSurface Foam::triSurfaceTools::triangulate
if (bBox.containsAny(points, f))
{
faceList triFaces(f.nTriangles(points));
triEngine.triangulate(UIndirectList<point>(points, f));
label nTri = 0;
f.triangles(points, nTri, triFaces);
forAll(triFaces, triFacei)
forAll(triEngine.triPoints(), triFacei)
{
const face& f = triFaces[triFacei];
triangles.append(labelledTri(f[0], f[1], f[2], newPatchi));
triangles.append
(
labelledTri(triEngine.triPoints(triFacei, f), newPatchi)
);
nTriTotal++;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -27,6 +27,7 @@ License
#include "primitiveMesh.H"
#include "linePointRef.H"
#include "meshTools.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -280,6 +281,9 @@ void Foam::cuttingPlane::walkCellCuts
// scratch space for calculating the face vertices
DynamicList<label> faceVerts(10);
// Create a triangulation engine
polygonTriangulate triEngine;
forAll(cutCells_, i)
{
label celli = cutCells_[i];
@ -331,9 +335,13 @@ void Foam::cuttingPlane::walkCellCuts
// the cut faces are usually quite ugly, so optionally triangulate
if (triangulate)
{
label nTri = f.triangles(cutPoints, dynCutFaces);
while (nTri--)
triEngine.triangulate
(
UIndirectList<point>(cutPoints, f)
);
forAll(triEngine.triPoints(), i)
{
dynCutFaces.append(triEngine.triPoints(i, f));
dynCutCells.append(celli);
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,6 +25,7 @@ License
#include "thresholdCellFaces.H"
#include "emptyPolyPatch.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -86,6 +87,8 @@ void Foam::thresholdCellFaces::calculate
labelList oldToNewPoints(origPoints.size(), -1);
// Create a triangulation engine
polygonTriangulate triEngine;
// internal faces only
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
@ -149,9 +152,13 @@ void Foam::thresholdCellFaces::calculate
if (triangulate)
{
label count = surfFace.triangles(origPoints, surfFaces);
while (count-- > 0)
triEngine.triangulate
(
UIndirectList<point>(origPoints, surfFace)
);
forAll(triEngine.triPoints(), i)
{
surfFaces.append(triEngine.triPoints(i, surfFace));
surfCells.append(cellId);
}
}
@ -207,9 +214,13 @@ void Foam::thresholdCellFaces::calculate
if (triangulate)
{
label count = f.triangles(origPoints, surfFaces);
while (count-- > 0)
triEngine.triangulate
(
UIndirectList<point>(origPoints, f)
);
forAll(triEngine.triPoints(), i)
{
surfFaces.append(triEngine.triPoints(i, f));
surfCells.append(cellId);
}
}

View File

@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "nastranSurfaceWriter.H"
#include "polygonTriangulate.H"
#include "makeSurfaceWriterMethods.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -283,6 +284,8 @@ void Foam::nastranSurfaceWriter::writeGeometry
label nFace = 1;
polygonTriangulate triEngine;
forAll(faces, facei)
{
const face& f = faces[facei];
@ -300,14 +303,12 @@ void Foam::nastranSurfaceWriter::writeGeometry
else
{
// decompose poly face into tris
label nTri = 0;
faceList triFaces;
f.triangles(points, nTri, triFaces);
forAll(triFaces, triI)
triEngine.triangulate(UIndirectList<point>(points, f));
forAll(triEngine.triPoints(), triI)
{
writeFace("CTRIA3", triFaces[triI], nFace, os);
decomposedFaces[facei].append(triFaces[triI]);
const face f(triEngine.triPoints(triI, f));
writeFace("CTRIA3", f, nFace, os);
decomposedFaces[facei].append(f);
}
}
}

View File

@ -33,6 +33,7 @@ License
#include "polyMesh.H"
#include "surfMesh.H"
#include "primitivePatch.H"
#include "polygonTriangulate.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -864,22 +865,18 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
else
{
// triangulate with points
List<face> tmpTri(maxTri);
polygonTriangulate triEngine;
label newFacei = 0;
forAll(faceLst, facei)
{
// 'face' not '<Face>'
const face& f = faceLst[facei];
label nTmp = 0;
f.triangles(this->points(), nTmp, tmpTri);
for (label triI = 0; triI < nTmp; triI++)
triEngine.triangulate(UIndirectList<point>(this->points(), f));
forAll(triEngine.triPoints(), triI)
{
newFaces[newFacei] = Face
(
static_cast<labelUList&>(tmpTri[triI])
);
newFaces[newFacei] = triEngine.triPoints(triI, f);
faceMap[newFacei] = facei;
newFacei++;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,6 +25,7 @@ License
#include "STARCDsurfaceFormat.H"
#include "ListOps.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -128,6 +129,9 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
readHeader(is, "PROSTAR_CELL");
// Create a triangulation engine
polygonTriangulate triEngine;
DynamicList<Face> dynFaces;
DynamicList<label> dynZones;
DynamicList<word> dynNames;
@ -201,24 +205,14 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
SubList<label> vertices(vertexLabels, vertexLabels.size());
if (mustTriangulate && nLabels > 3)
{
face f(vertices);
triEngine.triangulate
(
UIndirectList<point>(this->points(), vertices)
);
faceList triFaces(f.nTriangles());
label nTri = 0;
f.triangles(this->points(), nTri, triFaces);
forAll(triFaces, facei)
forAll(triEngine.triPoints(), trii)
{
// a triangular face, but not yet a triFace
dynFaces.append
(
triFace
(
static_cast<labelUList&>(triFaces[facei])
)
);
dynZones.append(zoneI);
dynSizes[zoneI]++;
dynFaces.append(triEngine.triPoints(trii, vertices));
}
}
else

View File

@ -1,7 +1,6 @@
triSurfaceTools = triSurface/triSurfaceTools
geometricSurfacePatch = triSurface/geometricSurfacePatch
faceTriangulation/faceTriangulation.C
meshTriangulation/meshTriangulation.C
triSurface/triSurface.C

View File

@ -1,656 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2021 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 "faceTriangulation.H"
#include "plane.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::scalar Foam::faceTriangulation::edgeRelTol = 1e-6;
// Edge to the right of face vertex i
Foam::label Foam::faceTriangulation::right(const label, label i)
{
return i;
}
// Edge to the left of face vertex i
Foam::label Foam::faceTriangulation::left(const label size, label i)
{
return i ? i-1 : size-1;
}
// Calculate (normalised) edge vectors.
// edges[i] gives edge between point i+1 and i.
Foam::tmp<Foam::vectorField> Foam::faceTriangulation::calcEdges
(
const face& f,
const pointField& points
)
{
tmp<vectorField> tedges(new vectorField(f.size()));
vectorField& edges = tedges.ref();
forAll(f, i)
{
point thisPt = points[f[i]];
point nextPt = points[f[f.fcIndex(i)]];
vector vec(nextPt - thisPt);
vec /= mag(vec) + vSmall;
edges[i] = vec;
}
return tedges;
}
// Calculates half angle components of angle from e0 to e1
void Foam::faceTriangulation::calcHalfAngle
(
const vector& normal,
const vector& e0,
const vector& e1,
scalar& cosHalfAngle,
scalar& sinHalfAngle
)
{
// truncate cos to +-1 to prevent negative numbers
scalar cos = max(-1, min(1, e0 & e1));
scalar sin = (e0 ^ e1) & normal;
if (sin < -rootVSmall)
{
// 3rd or 4th quadrant
cosHalfAngle = - Foam::sqrt(0.5*(1 + cos));
sinHalfAngle = Foam::sqrt(0.5*(1 - cos));
}
else
{
// 1st or 2nd quadrant
cosHalfAngle = Foam::sqrt(0.5*(1 + cos));
sinHalfAngle = Foam::sqrt(0.5*(1 - cos));
}
}
// Calculate intersection point between edge p1-p2 and ray (in 2D).
// Return true and intersection point if intersection between p1 and p2.
Foam::pointHit Foam::faceTriangulation::rayEdgeIntersect
(
const vector& normal,
const point& rayOrigin,
const vector& rayDir,
const point& p1,
const point& p2,
scalar& posOnEdge
)
{
// Start off from miss
pointHit result(p1);
// Construct plane normal to rayDir and intersect
const vector y = normal ^ rayDir;
posOnEdge = plane(rayOrigin, y).normalIntersect(p1, (p2-p1));
// Check intersection to left of p1 or right of p2
if ((posOnEdge < 0) || (posOnEdge > 1))
{
// Miss
}
else
{
// Check intersection behind rayOrigin
point intersectPt = p1 + posOnEdge * (p2 - p1);
if (((intersectPt - rayOrigin) & rayDir) < 0)
{
// Miss
}
else
{
// Hit
result.setHit();
result.setPoint(intersectPt);
result.setDistance(mag(intersectPt - rayOrigin));
}
}
return result;
}
// Return true if triangle given its three points (anticlockwise ordered)
// contains point
bool Foam::faceTriangulation::triangleContainsPoint
(
const vector& n,
const point& p0,
const point& p1,
const point& p2,
const point& pt
)
{
scalar area01Pt = triPointRef(p0, p1, pt).area() & n;
scalar area12Pt = triPointRef(p1, p2, pt).area() & n;
scalar area20Pt = triPointRef(p2, p0, pt).area() & n;
if ((area01Pt > 0) && (area12Pt > 0) && (area20Pt > 0))
{
return true;
}
else if ((area01Pt < 0) && (area12Pt < 0) && (area20Pt < 0))
{
FatalErrorInFunction << abort(FatalError);
return false;
}
else
{
return false;
}
}
// Starting from startIndex find diagonal. Return in index1, index2.
// Index1 always startIndex except when convex polygon
void Foam::faceTriangulation::findDiagonal
(
const pointField& points,
const face& f,
const vectorField& edges,
const vector& normal,
const label startIndex,
label& index1,
label& index2
)
{
const point& startPt = points[f[startIndex]];
// Calculate angle at startIndex
const vector& rightE = edges[right(f.size(), startIndex)];
const vector leftE = -edges[left(f.size(), startIndex)];
// Construct ray which bisects angle
scalar cosHalfAngle = great;
scalar sinHalfAngle = great;
calcHalfAngle(normal, rightE, leftE, cosHalfAngle, sinHalfAngle);
vector rayDir
(
cosHalfAngle*rightE
+ sinHalfAngle*(normal ^ rightE)
);
// rayDir should be normalised already but is not due to rounding errors
// so normalise.
rayDir /= mag(rayDir) + vSmall;
//
// Check all edges (apart from rightE and leftE) for nearest intersection
//
label faceVertI = f.fcIndex(startIndex);
pointHit minInter(false, Zero, great, true);
label minIndex = -1;
scalar minPosOnEdge = great;
for (label i = 0; i < f.size() - 2; i++)
{
scalar posOnEdge;
pointHit inter =
rayEdgeIntersect
(
normal,
startPt,
rayDir,
points[f[faceVertI]],
points[f[f.fcIndex(faceVertI)]],
posOnEdge
);
if (inter.hit() && inter.distance() < minInter.distance())
{
minInter = inter;
minIndex = faceVertI;
minPosOnEdge = posOnEdge;
}
faceVertI = f.fcIndex(faceVertI);
}
if (minIndex == -1)
{
// WarningInFunction
// << "Could not find intersection starting from " << f[startIndex]
// << " for face " << f << endl;
index1 = -1;
index2 = -1;
return;
}
const label leftIndex = minIndex;
const label rightIndex = f.fcIndex(minIndex);
// Now ray intersects edge from leftIndex to rightIndex.
// Check for intersection being one of the edge points. Make sure never
// to return two consecutive points.
if (mag(minPosOnEdge) < edgeRelTol && f.fcIndex(startIndex) != leftIndex)
{
index1 = startIndex;
index2 = leftIndex;
return;
}
if
(
mag(minPosOnEdge - 1) < edgeRelTol
&& f.fcIndex(rightIndex) != startIndex
)
{
index1 = startIndex;
index2 = rightIndex;
return;
}
// Select visible vertex that minimises
// angle to bisection. Visibility checking by checking if inside triangle
// formed by startIndex, leftIndex, rightIndex
const point& leftPt = points[f[leftIndex]];
const point& rightPt = points[f[rightIndex]];
minIndex = -1;
scalar maxCos = -great;
// all vertices except for startIndex and ones to left and right of it.
faceVertI = f.fcIndex(f.fcIndex(startIndex));
for (label i = 0; i < f.size() - 3; i++)
{
const point& pt = points[f[faceVertI]];
if
(
(faceVertI == leftIndex)
|| (faceVertI == rightIndex)
|| (triangleContainsPoint(normal, startPt, leftPt, rightPt, pt))
)
{
// pt inside triangle (so perhaps visible)
// Select based on minimal angle (so guaranteed visible).
vector edgePt0 = pt - startPt;
edgePt0 /= mag(edgePt0);
scalar cos = rayDir & edgePt0;
if (cos > maxCos)
{
maxCos = cos;
minIndex = faceVertI;
}
}
faceVertI = f.fcIndex(faceVertI);
}
if (minIndex == -1)
{
// no vertex found. Return startIndex and one of the intersected edge
// endpoints.
index1 = startIndex;
if (f.fcIndex(startIndex) != leftIndex)
{
index2 = leftIndex;
}
else
{
index2 = rightIndex;
}
return;
}
index1 = startIndex;
index2 = minIndex;
}
// Find label of vertex to start splitting from. Is:
// 1] flattest concave angle
// 2] flattest convex angle if no concave angles.
Foam::label Foam::faceTriangulation::findStart
(
const face& f,
const vectorField& edges,
const vector& normal
)
{
const label size = f.size();
scalar minCos = great;
label minIndex = -1;
forAll(f, fp)
{
const vector& rightEdge = edges[right(size, fp)];
const vector leftEdge = -edges[left(size, fp)];
if (((rightEdge ^ leftEdge) & normal) < rootVSmall)
{
scalar cos = rightEdge & leftEdge;
if (cos < minCos)
{
minCos = cos;
minIndex = fp;
}
}
}
if (minIndex == -1)
{
// No concave angle found. Get flattest convex angle
minCos = great;
forAll(f, fp)
{
const vector& rightEdge = edges[right(size, fp)];
const vector leftEdge = -edges[left(size, fp)];
scalar cos = rightEdge & leftEdge;
if (cos < minCos)
{
minCos = cos;
minIndex = fp;
}
}
}
return minIndex;
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Split face f into triangles. Handles all simple (convex & concave)
// polygons.
bool Foam::faceTriangulation::split
(
const bool fallBack,
const pointField& points,
const face& f,
const vector& normal,
label& triI
)
{
const label size = f.size();
if (size <= 2)
{
WarningInFunction
<< "Illegal face:" << f
<< " with points " << UIndirectList<point>(points, f)()
<< endl;
return false;
}
else if (size == 3)
{
// Triangle. Just copy.
triFace& tri = operator[](triI++);
tri[0] = f[0];
tri[1] = f[1];
tri[2] = f[2];
return true;
}
else
{
// General case. Start splitting for -flattest concave angle
// -or flattest convex angle if no concave angles.
tmp<vectorField> tedges(calcEdges(f, points));
const vectorField& edges = tedges();
label startIndex = findStart(f, edges, normal);
// Find diagonal to split face across
label index1 = -1;
label index2 = -1;
forAll(f, iter)
{
findDiagonal
(
points,
f,
edges,
normal,
startIndex,
index1,
index2
);
if (index1 != -1 && index2 != -1)
{
// Found correct diagonal
break;
}
// Try splitting from next startingIndex.
startIndex = f.fcIndex(startIndex);
}
if (index1 == -1 || index2 == -1)
{
if (fallBack)
{
// Do naive triangulation. Find smallest angle to start
// triangulating from.
label maxIndex = -1;
scalar maxCos = -great;
forAll(f, fp)
{
const vector& rightEdge = edges[right(size, fp)];
const vector leftEdge = -edges[left(size, fp)];
scalar cos = rightEdge & leftEdge;
if (cos > maxCos)
{
maxCos = cos;
maxIndex = fp;
}
}
WarningInFunction
<< "Cannot find valid diagonal on face " << f
<< " with points " << UIndirectList<point>(points, f)()
<< nl
<< "Returning naive triangulation starting from "
<< f[maxIndex] << " which might not be correct for a"
<< " concave or warped face" << endl;
label fp = f.fcIndex(maxIndex);
for (label i = 0; i < size-2; i++)
{
label nextFp = f.fcIndex(fp);
triFace& tri = operator[](triI++);
tri[0] = f[maxIndex];
tri[1] = f[fp];
tri[2] = f[nextFp];
fp = nextFp;
}
return true;
}
else
{
WarningInFunction
<< "Cannot find valid diagonal on face " << f
<< " with points " << UIndirectList<point>(points, f)()
<< nl
<< "Returning empty triFaceList" << endl;
return false;
}
}
// Split into two subshapes.
// face1: index1 to index2
// face2: index2 to index1
// Get sizes of the two subshapes
label diff = 0;
if (index2 > index1)
{
diff = index2 - index1;
}
else
{
// folded round
diff = index2 + size - index1;
}
label nPoints1 = diff + 1;
label nPoints2 = size - diff + 1;
if (nPoints1 == size || nPoints2 == size)
{
FatalErrorInFunction
<< "Illegal split of face:" << f
<< " with points " << UIndirectList<point>(points, f)()
<< " at indices " << index1 << " and " << index2
<< abort(FatalError);
}
// Collect face1 points
face face1(nPoints1);
label faceVertI = index1;
for (int i = 0; i < nPoints1; i++)
{
face1[i] = f[faceVertI];
faceVertI = f.fcIndex(faceVertI);
}
// Collect face2 points
face face2(nPoints2);
faceVertI = index2;
for (int i = 0; i < nPoints2; i++)
{
face2[i] = f[faceVertI];
faceVertI = f.fcIndex(faceVertI);
}
// Decompose the split faces
// Pout<< "Split face:" << f << " into " << face1 << " and " << face2
// << endl;
// string oldPrefix(Pout.prefix());
// Pout.prefix() = " " + oldPrefix;
bool splitOk =
split(fallBack, points, face1, normal, triI)
&& split(fallBack, points, face2, normal, triI);
// Pout.prefix() = oldPrefix;
return splitOk;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::faceTriangulation::faceTriangulation()
:
triFaceList()
{}
Foam::faceTriangulation::faceTriangulation
(
const pointField& points,
const face& f,
const bool fallBack
)
:
triFaceList(f.size()-2)
{
const vector avgNormal = f.normal(points);
label triI = 0;
bool valid = split(fallBack, points, f, avgNormal, triI);
if (!valid)
{
setSize(0);
}
}
Foam::faceTriangulation::faceTriangulation
(
const pointField& points,
const face& f,
const vector& n,
const bool fallBack
)
:
triFaceList(f.size()-2)
{
label triI = 0;
bool valid = split(fallBack, points, f, n, triI);
if (!valid)
{
setSize(0);
}
}
Foam::faceTriangulation::faceTriangulation(Istream& is)
:
triFaceList(is)
{}
// ************************************************************************* //

View File

@ -1,202 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2021 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/>.
Class
Foam::faceTriangulation
Description
Triangulation of faces. Handles concave polygons as well
(inefficiently)
Works by trying to subdivide the face at the vertex with 'flattest'
internal angle (i.e. closest to 180 deg).
Based on routine 'Diagonal' in
\verbatim
"Efficient Triangulation of Simple Polygons"
Godfried Toussaint, McGill University.
\endverbatim
After construction is the list of triangles the face is decomposed into.
(Or empty list if no valid triangulation could be found).
SourceFiles
faceTriangulation.C
\*---------------------------------------------------------------------------*/
#ifndef faceTriangulation_H
#define faceTriangulation_H
#include "triFaceList.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
/*---------------------------------------------------------------------------*\
Class faceTriangulation Declaration
\*---------------------------------------------------------------------------*/
class faceTriangulation
:
public triFaceList
{
// Static Data
//- Relative tolerance on edge.
static const scalar edgeRelTol;
// Static Member Functions
//- Edge to the right of face vertex i
static label right(const label size, label i);
//- Edge to the left of face vertex i
static label left(const label size, label i);
//- Calculate normalised edge vectors
static tmp<vectorField> calcEdges(const face&, const pointField&);
//- Calculates half angle components of angle from e0 to e1
// in plane given by normal.
static void calcHalfAngle
(
const vector& normal,
const vector& e0,
const vector& e1,
scalar& cosHalfAngle,
scalar& sinHalfAngle
);
//- Calculate intersection point between edge p1-p2 and ray (in 2D).
// Return true and intersection point if intersection between p1 and p2.
static pointHit rayEdgeIntersect
(
const vector& normal,
const point& rayOrigin,
const vector& rayDir,
const point& p1,
const point& p2,
scalar& posOnEdge
);
// Return true if triangle given its three points
// (anticlockwise ordered) contains point
static bool triangleContainsPoint
(
const vector& n,
const point& p0,
const point& p1,
const point& p2,
const point& pt
);
//- Starting from startIndex find diagonal. Return in index1, index2.
// Index1 always startIndex except when convex polygon
static void findDiagonal
(
const pointField& points,
const face& f,
const vectorField& edges,
const vector& normal,
const label startIndex,
label& index1,
label& index2
);
//- Find label of vertex to start splitting from. This will be the
// vertex with edge angle:
// 1] flattest concave angle
// 2] flattest convex angle if no concave angles.
static label findStart
(
const face& f,
const vectorField& edges,
const vector& normal
);
// Private Member Functions
//- Split face f into triangles. Handles all simple (convex & concave)
// polygons. Returns false if could not produce valid split.
bool split
(
const bool fallBack,
const pointField& points,
const face& f,
const vector& normal,
label& triI
);
public:
// Constructors
//- Construct null
faceTriangulation();
//- Construct from face and points. Decomposition based on average
// normal. After construction *this is size 0 or holds the triangles.
// If fallBack and triangulation fails does naive triangulation
// and never returns 0 size.
faceTriangulation
(
const pointField& points,
const face& f,
const bool fallBack = false
);
//- Construct from face and points and user supplied (unit) normal.
// After construction *this is size 0 or holds the triangles.
// If fallBack and triangulation fails does naive triangulation
// and never returns 0 size.
faceTriangulation
(
const pointField& points,
const face& f,
const vector& n,
const bool fallBack = false
);
//- Construct from Istream
faceTriangulation(Istream&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,7 +25,7 @@ License
#include "meshTriangulation.H"
#include "polyMesh.H"
#include "faceTriangulation.H"
#include "polygonTriangulate.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -209,7 +209,7 @@ Foam::meshTriangulation::meshTriangulation
{
if (faceIsCut[facei])
{
nTotTri += faces[facei].nTriangles(points);
nTotTri += faces[facei].nTriangles();
}
}
}
@ -352,38 +352,28 @@ Foam::meshTriangulation::meshTriangulation
// Triangulation using existing vertices
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a triangulation engine
polygonTriangulate triEngine;
// Triangulate internal faces
forAll(faceIsCut, facei)
{
if (faceIsCut[facei] && isInternalFace(mesh, includedCell, facei))
{
// Face was internal to the mesh and will be 'internal' to
// the surface.
triEngine.triangulate
(
UIndirectList<point>(points, faces[facei])
);
// Triangulate face. Fall back to naive triangulation if failed.
faceTriangulation faceTris(points, faces[facei], true);
if (faceTris.empty())
{
WarningInFunction
<< "Could not find triangulation for face " << facei
<< " vertices " << faces[facei] << " coords "
<< IndirectList<point>(points, faces[facei])() << endl;
}
else
{
// Copy triangles. Make them internalFacesPatch
insertTriangles
(
faceTris,
facei,
internalFacesPatch,
false, // no reverse
triangles,
triI
);
}
insertTriangles
(
triEngine.triPoints(faces[facei]),
facei,
internalFacesPatch,
false, // no reverse
triangles,
triI
);
}
}
nInternalFaces_ = triI;
@ -423,30 +413,20 @@ Foam::meshTriangulation::meshTriangulation
reverse = false;
}
// Triangulate face
faceTriangulation faceTris(points, faces[facei], true);
triEngine.triangulate
(
UIndirectList<point>(points, faces[facei])
);
if (faceTris.empty())
{
WarningInFunction
<< "Could not find triangulation for face " << facei
<< " vertices " << faces[facei] << " coords "
<< IndirectList<point>(points, faces[facei])() << endl;
}
else
{
// Copy triangles. Optionally reverse them
insertTriangles
(
faceTris,
facei,
patchi,
reverse, // whether to reverse
triangles,
triI
);
}
insertTriangles
(
triEngine.triPoints(faces[facei]),
facei,
patchi,
reverse, // whether to reverse
triangles,
triI
);
}
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -27,6 +27,7 @@ Description
\*---------------------------------------------------------------------------*/
#include "triSurface.H"
#include "polygonTriangulate.H"
#include "IFstream.H"
#include "IStringStream.H"
@ -76,6 +77,9 @@ bool Foam::triSurface::readOFF(const fileName& OFFfileName)
points[pointi] = point(x, y, z);
}
// Create a triangulation engine
polygonTriangulate triEngine;
// Read faces & triangulate them,
DynamicList<labelledTri> tris(nElems);
@ -107,17 +111,11 @@ bool Foam::triSurface::readOFF(const fileName& OFFfileName)
}
else
{
faceList triFaces(f.nTriangles(points));
triEngine.triangulate(UIndirectList<point>(points, f));
label nTri = 0;
f.triangles(points, nTri, triFaces);
forAll(triFaces, triFacei)
forAll(triEngine.triPoints(), trii)
{
const face& f = triFaces[triFacei];
tris.append(labelledTri(f[0], f[1], f[2], 0));
tris.append(labelledTri(triEngine.triPoints(trii, f), 0));
}
}
}