mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add point snapping to iso-surface topo algorithm (#2210)
- helps avoid the creation of small face cuts (near corners, edges) that result in zero-size faces on output. CONFIG: make default iso-surface topo regularisation less aggressive - The full (diagcell) regularisation no longer includes cleaning of non-manifold surfaces by removing open edges. This can be selected by the 'clean' regularisation option instead. ie, 'clean' = 'full' + erode open edges ENH: additional debug modes for iso-surface topo - with (debug & 8) dumps out a VTK file of the tets to be cut and the calculated open edges.
This commit is contained in:
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2019-2020 OpenCFD Ltd.
|
Copyright (C) 2019-2021 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -127,26 +127,6 @@ protected:
|
|||||||
|
|
||||||
// Protected Member Functions
|
// Protected Member Functions
|
||||||
|
|
||||||
//- Check for tet values above/below given (iso) value
|
|
||||||
// Result encoded as a single integer
|
|
||||||
inline static constexpr int getTetCutIndex
|
|
||||||
(
|
|
||||||
const scalar a,
|
|
||||||
const scalar b,
|
|
||||||
const scalar c,
|
|
||||||
const scalar d,
|
|
||||||
const scalar isoval
|
|
||||||
) noexcept
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(
|
|
||||||
(a < isoval ? 1 : 0)
|
|
||||||
| (b < isoval ? 2 : 0)
|
|
||||||
| (c < isoval ? 4 : 0)
|
|
||||||
| (d < isoval ? 8 : 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Count the number of cuts matching the mask type
|
//- Count the number of cuts matching the mask type
|
||||||
// Checks as bitmask or as zero.
|
// Checks as bitmask or as zero.
|
||||||
static label countCutType
|
static label countCutType
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2020 OpenCFD Ltd.
|
Copyright (C) 2020-2021 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -52,10 +52,12 @@ const Foam::Enum
|
|||||||
Foam::isoSurfaceParams::filterNames
|
Foam::isoSurfaceParams::filterNames
|
||||||
({
|
({
|
||||||
{ filterType::NONE, "none" },
|
{ filterType::NONE, "none" },
|
||||||
{ filterType::CELL, "cell" },
|
|
||||||
{ filterType::DIAGCELL, "diagcell" },
|
|
||||||
{ filterType::PARTIAL, "partial" },
|
{ filterType::PARTIAL, "partial" },
|
||||||
{ filterType::FULL, "full" },
|
{ filterType::FULL, "full" },
|
||||||
|
{ filterType::CLEAN, "clean" },
|
||||||
|
|
||||||
|
{ filterType::CELL, "cell" },
|
||||||
|
{ filterType::DIAGCELL, "diagcell" },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -137,6 +139,7 @@ Foam::isoSurfaceParams::isoSurfaceParams
|
|||||||
:
|
:
|
||||||
algo_(algo),
|
algo_(algo),
|
||||||
filter_(filter),
|
filter_(filter),
|
||||||
|
snap_(true),
|
||||||
mergeTol_(1e-6),
|
mergeTol_(1e-6),
|
||||||
clipBounds_(boundBox::invertedBox)
|
clipBounds_(boundBox::invertedBox)
|
||||||
{}
|
{}
|
||||||
@ -152,6 +155,7 @@ Foam::isoSurfaceParams::isoSurfaceParams
|
|||||||
{
|
{
|
||||||
algo_ = getAlgorithmType(dict, algo_);
|
algo_ = getAlgorithmType(dict, algo_);
|
||||||
filter_ = getFilterType(dict, filter_);
|
filter_ = getFilterType(dict, filter_);
|
||||||
|
snap_ = dict.getOrDefault("snap", true);
|
||||||
dict.readIfPresent("mergeTol", mergeTol_);
|
dict.readIfPresent("mergeTol", mergeTol_);
|
||||||
dict.readIfPresent("bounds", clipBounds_);
|
dict.readIfPresent("bounds", clipBounds_);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2020 OpenCFD Ltd.
|
Copyright (C) 2020-2021 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -35,12 +35,22 @@ Description
|
|||||||
isoMethod | Algorithm (cell/topo/point/default) | no | default
|
isoMethod | Algorithm (cell/topo/point/default) | no | default
|
||||||
regularise | Face simplification (enum or bool) | no | true
|
regularise | Face simplification (enum or bool) | no | true
|
||||||
mergeTol | Point merge tolerance (cell/point) | no | 1e-6
|
mergeTol | Point merge tolerance (cell/point) | no | 1e-6
|
||||||
|
snap | Point snapping (topo) | no | true
|
||||||
bounds | Optional clip bounds | no | inverted
|
bounds | Optional clip bounds | no | inverted
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
The default algorithm denotes the use of the current \em standard
|
The default algorithm denotes the use of the current \em standard
|
||||||
algorithm.
|
algorithm.
|
||||||
|
|
||||||
|
Filtering types (for topological iso-surface)
|
||||||
|
- \c none : leave tet cuts untouched
|
||||||
|
- \c partial , \c cell : Combine intra-cell faces
|
||||||
|
- \c full , \c diagcell : Perform \c partial and remove face-diagonal
|
||||||
|
points
|
||||||
|
- \c clean : Perform \c full and eliminate open edges as well.
|
||||||
|
(<b>May cause excessive erosion!</b>)
|
||||||
|
.
|
||||||
|
|
||||||
SourceFiles
|
SourceFiles
|
||||||
isoSurfaceParams.C
|
isoSurfaceParams.C
|
||||||
|
|
||||||
@ -85,8 +95,12 @@ public:
|
|||||||
NONE = 0, //!< No filtering
|
NONE = 0, //!< No filtering
|
||||||
CELL, //!< Remove pyramid edge points
|
CELL, //!< Remove pyramid edge points
|
||||||
DIAGCELL, //!< Remove pyramid edge points, face-diagonals
|
DIAGCELL, //!< Remove pyramid edge points, face-diagonals
|
||||||
|
NONMANIFOLD, //!< Remove pyramid edge points, face-diagonals
|
||||||
|
//!< and non-manifold faces
|
||||||
|
|
||||||
PARTIAL = CELL, //!< Same as CELL
|
PARTIAL = CELL, //!< Same as CELL
|
||||||
FULL = DIAGCELL, //!< Same as DIAGCELL
|
FULL = DIAGCELL, //!< Same as DIAGCELL
|
||||||
|
CLEAN = NONMANIFOLD //!< Same as NONMANIFOLD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -100,6 +114,9 @@ private:
|
|||||||
//- Filtering for iso-surface faces/points
|
//- Filtering for iso-surface faces/points
|
||||||
filterType filter_;
|
filterType filter_;
|
||||||
|
|
||||||
|
//- Point snapping enabled
|
||||||
|
bool snap_;
|
||||||
|
|
||||||
//- Merge tolerance for cell/point (default: 1e-6)
|
//- Merge tolerance for cell/point (default: 1e-6)
|
||||||
scalar mergeTol_;
|
scalar mergeTol_;
|
||||||
|
|
||||||
@ -186,6 +203,18 @@ public:
|
|||||||
filter_ = fltr;
|
filter_ = fltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- Get point snapping flag
|
||||||
|
bool snap() const noexcept
|
||||||
|
{
|
||||||
|
return snap_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Set point snapping flag
|
||||||
|
void snap(bool on) noexcept
|
||||||
|
{
|
||||||
|
snap_ = on;
|
||||||
|
}
|
||||||
|
|
||||||
//- Get current merge tolerance
|
//- Get current merge tolerance
|
||||||
scalar mergeTol() const noexcept
|
scalar mergeTol() const noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -50,6 +50,7 @@ namespace Foam
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Forward Declarations
|
// Forward Declarations
|
||||||
|
class cellShape;
|
||||||
class polyMesh;
|
class polyMesh;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
/*---------------------------------------------------------------------------*\
|
||||||
@ -62,63 +63,103 @@ class isoSurfaceTopo
|
|||||||
{
|
{
|
||||||
// Private Data
|
// Private Data
|
||||||
|
|
||||||
//- Corrected version of tetBasePtIs
|
//- Per point: originating mesh vertex/cell centre combination.
|
||||||
labelList tetBasePtIs_;
|
// Vertices less than nPoints are mesh vertices,
|
||||||
|
// duplicate vertices indicate a snapped point
|
||||||
//- Per point: originating mesh vertex/cc. See encoding above
|
|
||||||
edgeList pointToVerts_;
|
edgeList pointToVerts_;
|
||||||
|
|
||||||
//- For every point the originating face in mesh
|
|
||||||
labelList pointToFace_;
|
|
||||||
|
|
||||||
//- The cell cut type
|
// Private Classes
|
||||||
List<cutType> cellCutType_;
|
|
||||||
|
//- Handling, bookkeeping for tet cuts
|
||||||
|
class tetCutAddressing
|
||||||
|
{
|
||||||
|
// Bookkeeping hashes used during construction
|
||||||
|
EdgeMap<label> vertsToPointLookup_;
|
||||||
|
Map<label> snapVertsLookup_;
|
||||||
|
|
||||||
|
// Filter information for face diagonals
|
||||||
|
DynamicList<label> pointToFace_;
|
||||||
|
DynamicList<bool> pointFromDiag_;
|
||||||
|
|
||||||
|
// Final output
|
||||||
|
DynamicList<edge> pointToVerts_;
|
||||||
|
DynamicList<label> cutPoints_;
|
||||||
|
|
||||||
|
//- List of cut (decomposed) cell tets. Debug use only.
|
||||||
|
DynamicList<cellShape> debugCutTets_;
|
||||||
|
|
||||||
|
bool debugCutTetsOn_;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct with reserved sizes
|
||||||
|
tetCutAddressing
|
||||||
|
(
|
||||||
|
const label nCutCells,
|
||||||
|
const bool useSnap,
|
||||||
|
const bool useDebugCuts = false
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Effective number of faces
|
||||||
|
label nFaces() const { return cutPoints_.size()/3; }
|
||||||
|
|
||||||
|
DynamicList<label>& pointToFace() { return pointToFace_; }
|
||||||
|
DynamicList<bool>& pointFromDiag() { return pointFromDiag_; }
|
||||||
|
|
||||||
|
DynamicList<edge>& pointToVerts() { return pointToVerts_; }
|
||||||
|
DynamicList<label>& cutPoints() { return cutPoints_; }
|
||||||
|
DynamicList<cellShape>& debugCutTets() { return debugCutTets_; }
|
||||||
|
|
||||||
|
//- Number of debug cut tets
|
||||||
|
label nDebugTets() const { return debugCutTets_.size(); }
|
||||||
|
|
||||||
|
//- Debugging cut tets active
|
||||||
|
bool debugCutTetsOn() const { return debugCutTetsOn_; }
|
||||||
|
|
||||||
|
void clearDebug();
|
||||||
|
void clearDiagonal();
|
||||||
|
void clearHashes();
|
||||||
|
|
||||||
|
//- Generate single point on edge
|
||||||
|
label generatePoint
|
||||||
|
(
|
||||||
|
label facei, //!< Originating mesh face for cut-point
|
||||||
|
bool edgeIsDiagonal, //!< Edge on face diagonal
|
||||||
|
|
||||||
|
// 0: no snap, 1: snap first, 2: snap second
|
||||||
|
const int snapEnd,
|
||||||
|
|
||||||
|
const edge& vertices
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Generate triangles from tet cut
|
||||||
|
bool generatePoints
|
||||||
|
(
|
||||||
|
const label facei,
|
||||||
|
const int tetCutIndex, //!< Encoded tet cut + tet snapping
|
||||||
|
const tetCell& tetLabels,
|
||||||
|
const FixedList<bool, 6>& edgeIsDiagonal
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
//- Generate single point on edge
|
//- Generate triangle points from cell
|
||||||
label generatePoint
|
|
||||||
(
|
|
||||||
const label facei,
|
|
||||||
const bool edgeIsDiag,
|
|
||||||
const edge& vertices,
|
|
||||||
|
|
||||||
DynamicList<edge>& pointToVerts,
|
|
||||||
DynamicList<label>& pointToFace,
|
|
||||||
DynamicList<bool>& pointFromDiag,
|
|
||||||
EdgeMap<label>& vertsToPoint
|
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Generate triangles from tet
|
|
||||||
void generateTriPoints
|
|
||||||
(
|
|
||||||
const label facei,
|
|
||||||
const int tetCutIndex, //!< Encoded tet cuts. getTetCutIndex()
|
|
||||||
const tetCell& tetLabels,
|
|
||||||
const FixedList<bool, 6>& edgeIsDiag,
|
|
||||||
|
|
||||||
DynamicList<edge>& pointToVerts,
|
|
||||||
DynamicList<label>& pointToFace,
|
|
||||||
DynamicList<bool>& pointFromDiag,
|
|
||||||
|
|
||||||
EdgeMap<label>& vertsToPoint,
|
|
||||||
DynamicList<label>& verts
|
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Generate triangles from cell
|
|
||||||
void generateTriPoints
|
void generateTriPoints
|
||||||
(
|
(
|
||||||
const label celli,
|
const label celli,
|
||||||
const bool isTet,
|
const bool isTet,
|
||||||
|
const labelList& tetBasePtIs,
|
||||||
|
|
||||||
DynamicList<edge>& pointToVerts,
|
tetCutAddressing& tetCutAddr
|
||||||
DynamicList<label>& pointToFace,
|
|
||||||
DynamicList<bool>& pointFromDiag,
|
|
||||||
|
|
||||||
EdgeMap<label>& vertsToPoint,
|
|
||||||
DynamicList<label>& verts,
|
|
||||||
DynamicList<label>& faceLabels
|
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
|
|
||||||
@ -165,12 +206,12 @@ protected:
|
|||||||
|
|
||||||
// Sampling
|
// Sampling
|
||||||
|
|
||||||
//- Interpolates cCoords,pCoords.
|
//- Interpolates cellData and pointData fields
|
||||||
template<class Type>
|
template<class Type>
|
||||||
tmp<Field<Type>> interpolateTemplate
|
tmp<Field<Type>> interpolateTemplate
|
||||||
(
|
(
|
||||||
const Field<Type>& cCoords,
|
const Field<Type>& cellData,
|
||||||
const Field<Type>& pCoords
|
const Field<Type>& pointData
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -205,14 +246,10 @@ public:
|
|||||||
|
|
||||||
// Member Functions
|
// Member Functions
|
||||||
|
|
||||||
//- For every point originating face (pyramid) in mesh
|
//- Per point: originating mesh vertex/cell centre combination.
|
||||||
const labelList& pointToFace() const
|
// Vertices less than nPoints are mesh vertices (encoding above),
|
||||||
{
|
// duplicate vertices indicate a snapped point
|
||||||
return pointToFace_;
|
const edgeList& pointToVerts() const noexcept
|
||||||
}
|
|
||||||
|
|
||||||
//- Per point: originating mesh vertex/cc. See encoding above
|
|
||||||
const edgeList& pointToVerts() const
|
|
||||||
{
|
{
|
||||||
return pointToVerts_;
|
return pointToVerts_;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011-2018 OpenFOAM Foundation
|
Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||||
Copyright (C) 2020 OpenCFD Ltd.
|
Copyright (C) 2020-2021 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -32,8 +32,8 @@ template<class Type>
|
|||||||
Foam::tmp<Foam::Field<Type>>
|
Foam::tmp<Foam::Field<Type>>
|
||||||
Foam::isoSurfaceTopo::interpolateTemplate
|
Foam::isoSurfaceTopo::interpolateTemplate
|
||||||
(
|
(
|
||||||
const Field<Type>& cellCoords,
|
const Field<Type>& cellData,
|
||||||
const Field<Type>& pointCoords
|
const Field<Type>& pointData
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
auto tfld = tmp<Field<Type>>::New(pointToVerts_.size());
|
auto tfld = tmp<Field<Type>>::New(pointToVerts_.size());
|
||||||
@ -41,41 +41,50 @@ Foam::isoSurfaceTopo::interpolateTemplate
|
|||||||
|
|
||||||
forAll(pointToVerts_, i)
|
forAll(pointToVerts_, i)
|
||||||
{
|
{
|
||||||
|
const edge& verts = pointToVerts_[i];
|
||||||
|
Type& val = fld[i];
|
||||||
|
|
||||||
scalar s0;
|
scalar s0;
|
||||||
Type p0;
|
Type v0;
|
||||||
{
|
{
|
||||||
label idx = pointToVerts_[i].first();
|
label idx = verts.first();
|
||||||
if (idx < mesh_.nPoints())
|
if (idx < mesh_.nPoints())
|
||||||
{
|
{
|
||||||
// Point index
|
// Point index
|
||||||
s0 = pVals_[idx];
|
s0 = pVals_[idx];
|
||||||
p0 = pointCoords[idx];
|
v0 = pointData[idx];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cell index
|
// Cell index
|
||||||
idx -= mesh_.nPoints();
|
idx -= mesh_.nPoints();
|
||||||
s0 = cVals_[idx];
|
s0 = cVals_[idx];
|
||||||
p0 = cellCoords[idx];
|
v0 = cellData[idx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scalar s1;
|
scalar s1;
|
||||||
Type p1;
|
Type v1;
|
||||||
{
|
{
|
||||||
label idx = pointToVerts_[i].second();
|
label idx = verts.second();
|
||||||
if (idx < mesh_.nPoints())
|
if (idx == verts.first())
|
||||||
|
{
|
||||||
|
// Duplicate index (ie, snapped)
|
||||||
|
val = v0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (idx < mesh_.nPoints())
|
||||||
{
|
{
|
||||||
// Point index
|
// Point index
|
||||||
s1 = pVals_[idx];
|
s1 = pVals_[idx];
|
||||||
p1 = pointCoords[idx];
|
v1 = pointData[idx];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cell index
|
// Cell index
|
||||||
idx -= mesh_.nPoints();
|
idx -= mesh_.nPoints();
|
||||||
s1 = cVals_[idx];
|
s1 = cVals_[idx];
|
||||||
p1 = cellCoords[idx];
|
v1 = cellData[idx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,11 +92,11 @@ Foam::isoSurfaceTopo::interpolateTemplate
|
|||||||
if (mag(d) > VSMALL)
|
if (mag(d) > VSMALL)
|
||||||
{
|
{
|
||||||
const scalar s = (iso_-s0)/d;
|
const scalar s = (iso_-s0)/d;
|
||||||
fld[i] = s*p1+(1.0-s)*p0;
|
val = s*v1+(1.0-s)*v0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fld[i] = 0.5*(p0+p1);
|
val = 0.5*(v0+v1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user