1275 lines
43 KiB
C++
1275 lines
43 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2005 Imetric 3D GmbH *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library 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 Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include "PreCompiled.h"
|
|
|
|
#ifndef _PreComp_
|
|
# include <algorithm>
|
|
# include <map>
|
|
# include <queue>
|
|
#endif
|
|
|
|
#include "Degeneration.h"
|
|
#include "Definitions.h"
|
|
#include "Iterator.h"
|
|
#include "Helpers.h"
|
|
#include "MeshKernel.h"
|
|
#include "Algorithm.h"
|
|
#include "Info.h"
|
|
#include "Grid.h"
|
|
#include "TopoAlgorithm.h"
|
|
#include "Triangulation.h"
|
|
|
|
#include <boost/math/special_functions/fpclassify.hpp>
|
|
#include <Base/Sequencer.h>
|
|
|
|
using namespace MeshCore;
|
|
|
|
bool MeshEvalInvalids::Evaluate()
|
|
{
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
for ( MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it )
|
|
{
|
|
if ( !it->IsValid() )
|
|
return false;
|
|
}
|
|
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
for ( MeshPointArray::_TConstIterator jt = rPoints.begin(); jt != rPoints.end(); ++jt )
|
|
{
|
|
if ( !jt->IsValid() )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalInvalids::GetIndices() const
|
|
{
|
|
std::vector<FacetIndex> aInds;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
FacetIndex ind=0;
|
|
for ( MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, ind++ )
|
|
{
|
|
if ( !it->IsValid() )
|
|
aInds.push_back(ind);
|
|
else if ( !rPoints[it->_aulPoints[0]].IsValid() )
|
|
aInds.push_back(ind);
|
|
else if ( !rPoints[it->_aulPoints[1]].IsValid() )
|
|
aInds.push_back(ind);
|
|
else if ( !rPoints[it->_aulPoints[2]].IsValid() )
|
|
aInds.push_back(ind);
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixInvalids::Fixup()
|
|
{
|
|
_rclMesh.RemoveInvalids();
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
namespace MeshCore {
|
|
|
|
typedef MeshPointArray::_TConstIterator VertexIterator;
|
|
/*
|
|
* When building up a mesh then usually the class MeshBuilder is used. This
|
|
* class uses internally a std::set<MeshPoint> which uses the '<' operator of
|
|
* MeshPoint to sort the points. Thus to be consistent (and avoid using the
|
|
* '==' operator of MeshPoint) we use the same operator when comparing the
|
|
* points in the function object.
|
|
*/
|
|
struct Vertex_EqualTo
|
|
{
|
|
bool operator()(const VertexIterator& x,
|
|
const VertexIterator& y) const
|
|
{
|
|
if ( (*x) < (*y) )
|
|
return false;
|
|
else if ( (*y) < (*x) )
|
|
return false;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
struct Vertex_Less
|
|
{
|
|
bool operator()(const VertexIterator& x,
|
|
const VertexIterator& y) const
|
|
{
|
|
return (*x) < (*y);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
bool MeshEvalDuplicatePoints::Evaluate()
|
|
{
|
|
// get an const iterator to each vertex and sort them in ascending order by
|
|
// their (x,y,z) coordinates
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
std::vector<VertexIterator> vertices;
|
|
vertices.reserve(rPoints.size());
|
|
for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) {
|
|
vertices.push_back(it);
|
|
}
|
|
|
|
// if there are two adjacent vertices which have the same coordinates
|
|
std::sort(vertices.begin(), vertices.end(), Vertex_Less());
|
|
if (std::adjacent_find(vertices.begin(), vertices.end(), Vertex_EqualTo()) < vertices.end() )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
std::vector<PointIndex> MeshEvalDuplicatePoints::GetIndices() const
|
|
{
|
|
//Note: We must neither use map or set to get duplicated indices because
|
|
//the sort algorithms deliver different results compared to std::sort of
|
|
//a vector.
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
std::vector<VertexIterator> vertices;
|
|
vertices.reserve(rPoints.size());
|
|
for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) {
|
|
vertices.push_back(it);
|
|
}
|
|
|
|
// if there are two adjacent vertices which have the same coordinates
|
|
std::vector<PointIndex> aInds;
|
|
Vertex_EqualTo pred;
|
|
std::sort(vertices.begin(), vertices.end(), Vertex_Less());
|
|
|
|
std::vector<VertexIterator>::iterator vt = vertices.begin();
|
|
while (vt < vertices.end()) {
|
|
// get first item which adjacent element has the same vertex
|
|
vt = std::adjacent_find(vt, vertices.end(), pred);
|
|
if (vt < vertices.end()) {
|
|
++vt;
|
|
aInds.push_back(*vt - rPoints.begin());
|
|
}
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixDuplicatePoints::Fixup()
|
|
{
|
|
//Note: We must neither use map or set to get duplicated indices because
|
|
//the sort algorithms deliver different results compared to std::sort of
|
|
//a vector.
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
std::vector<VertexIterator> vertices;
|
|
vertices.reserve(rPoints.size());
|
|
for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) {
|
|
vertices.push_back(it);
|
|
}
|
|
|
|
// get the indices of adjacent vertices which have the same coordinates
|
|
std::sort(vertices.begin(), vertices.end(), Vertex_Less());
|
|
|
|
Vertex_EqualTo pred;
|
|
std::vector<VertexIterator>::iterator next = vertices.begin();
|
|
std::map<PointIndex, PointIndex> mapPointIndex;
|
|
std::vector<PointIndex> pointIndices;
|
|
while (next < vertices.end()) {
|
|
next = std::adjacent_find(next, vertices.end(), pred);
|
|
if (next < vertices.end()) {
|
|
std::vector<VertexIterator>::iterator first = next;
|
|
PointIndex first_index = *first - rPoints.begin();
|
|
++next;
|
|
while (next < vertices.end() && pred(*first, *next)) {
|
|
PointIndex next_index = *next - rPoints.begin();
|
|
mapPointIndex[next_index] = first_index;
|
|
pointIndices.push_back(next_index);
|
|
++next;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now set all facets to the correct index
|
|
MeshFacetArray& rFacets = _rclMesh._aclFacetArray;
|
|
for (MeshFacetArray::_TIterator it = rFacets.begin(); it != rFacets.end(); ++it) {
|
|
for (int i=0; i<3; i++) {
|
|
std::map<PointIndex, PointIndex>::iterator pt = mapPointIndex.find(it->_aulPoints[i]);
|
|
if (pt != mapPointIndex.end())
|
|
it->_aulPoints[i] = pt->second;
|
|
}
|
|
}
|
|
|
|
// remove invalid indices
|
|
_rclMesh.DeletePoints(pointIndices);
|
|
_rclMesh.RebuildNeighbours();
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalNaNPoints::Evaluate()
|
|
{
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) {
|
|
if (boost::math::isnan(it->x) || boost::math::isnan(it->y) || boost::math::isnan(it->z))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<PointIndex> MeshEvalNaNPoints::GetIndices() const
|
|
{
|
|
std::vector<PointIndex> aInds;
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) {
|
|
if (boost::math::isnan(it->x) || boost::math::isnan(it->y) || boost::math::isnan(it->z))
|
|
aInds.push_back(it - rPoints.begin());
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixNaNPoints::Fixup()
|
|
{
|
|
std::vector<PointIndex> aInds;
|
|
const MeshPointArray& rPoints = _rclMesh.GetPoints();
|
|
for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) {
|
|
if (boost::math::isnan(it->x) || boost::math::isnan(it->y) || boost::math::isnan(it->z))
|
|
aInds.push_back(it - rPoints.begin());
|
|
}
|
|
|
|
// remove invalid indices
|
|
_rclMesh.DeletePoints(aInds);
|
|
_rclMesh.RebuildNeighbours();
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
namespace MeshCore {
|
|
|
|
typedef MeshFacetArray::_TConstIterator FaceIterator;
|
|
/*
|
|
* The facet with the lowset index is regarded as 'less'.
|
|
*/
|
|
struct MeshFacet_Less
|
|
{
|
|
bool operator()(const FaceIterator& x,
|
|
const FaceIterator& y) const
|
|
{
|
|
PointIndex tmp;
|
|
PointIndex x0 = x->_aulPoints[0];
|
|
PointIndex x1 = x->_aulPoints[1];
|
|
PointIndex x2 = x->_aulPoints[2];
|
|
PointIndex y0 = y->_aulPoints[0];
|
|
PointIndex y1 = y->_aulPoints[1];
|
|
PointIndex y2 = y->_aulPoints[2];
|
|
|
|
if (x0 > x1)
|
|
{ tmp = x0; x0 = x1; x1 = tmp; }
|
|
if (x0 > x2)
|
|
{ tmp = x0; x0 = x2; x2 = tmp; }
|
|
if (x1 > x2)
|
|
{ tmp = x1; x1 = x2; x2 = tmp; }
|
|
if (y0 > y1)
|
|
{ tmp = y0; y0 = y1; y1 = tmp; }
|
|
if (y0 > y2)
|
|
{ tmp = y0; y0 = y2; y2 = tmp; }
|
|
if (y1 > y2)
|
|
{ tmp = y1; y1 = y2; y2 = tmp; }
|
|
|
|
if (x0 < y0)
|
|
return true;
|
|
else if (x0 > y0) return false;
|
|
else if (x1 < y1) return true;
|
|
else if (x1 > y1) return false;
|
|
else if (x2 < y2) return true;
|
|
else return false;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
/*
|
|
* Two facets are equal if all its three point indices refer to the same
|
|
* location in the point array of the mesh kernel they belong to.
|
|
*/
|
|
struct MeshFacet_EqualTo
|
|
{
|
|
bool operator()(const FaceIterator& x,
|
|
const FaceIterator& y) const
|
|
{
|
|
for (int i=0; i<3; i++ ) {
|
|
if (x->_aulPoints[0] == y->_aulPoints[i]) {
|
|
if (x->_aulPoints[1] == y->_aulPoints[(i+1)%3] &&
|
|
x->_aulPoints[2] == y->_aulPoints[(i+2)%3])
|
|
return true;
|
|
else if (x->_aulPoints[1] == y->_aulPoints[(i+2)%3] &&
|
|
x->_aulPoints[2] == y->_aulPoints[(i+1)%3])
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
bool MeshEvalDuplicateFacets::Evaluate()
|
|
{
|
|
std::set<FaceIterator, MeshFacet_Less> aFaces;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it)
|
|
{
|
|
std::pair<std::set<FaceIterator, MeshFacet_Less>::iterator, bool>
|
|
pI = aFaces.insert(it);
|
|
if (!pI.second)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalDuplicateFacets::GetIndices() const
|
|
{
|
|
#if 1
|
|
const MeshFacetArray& rFacets = _rclMesh.GetFacets();
|
|
std::vector<FaceIterator> faces;
|
|
faces.reserve(rFacets.size());
|
|
for (MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it) {
|
|
faces.push_back(it);
|
|
}
|
|
|
|
// if there are two adjacent faces which references the same vertices
|
|
std::vector<FacetIndex> aInds;
|
|
MeshFacet_EqualTo pred;
|
|
std::sort(faces.begin(), faces.end(), MeshFacet_Less());
|
|
|
|
std::vector<FaceIterator>::iterator ft = faces.begin();
|
|
while (ft < faces.end()) {
|
|
// get first item which adjacent element has the same face
|
|
ft = std::adjacent_find(ft, faces.end(), pred);
|
|
if (ft < faces.end()) {
|
|
++ft;
|
|
aInds.push_back(*ft - rFacets.begin());
|
|
}
|
|
}
|
|
|
|
return aInds;
|
|
#else
|
|
std::vector<FacetIndex> aInds;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
FacetIndex uIndex=0;
|
|
|
|
// get all facets
|
|
std::set<FaceIterator, MeshFacet_Less > aFaceSet;
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, uIndex++)
|
|
{
|
|
std::pair<std::set<FaceIterator, MeshFacet_Less>::iterator, bool>
|
|
pI = aFaceSet.insert(it);
|
|
if (!pI.second)
|
|
aInds.push_back(uIndex);
|
|
}
|
|
|
|
return aInds;
|
|
#endif
|
|
}
|
|
|
|
bool MeshFixDuplicateFacets::Fixup()
|
|
{
|
|
FacetIndex uIndex=0;
|
|
std::vector<FacetIndex> aRemoveFaces;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
|
|
// get all facets
|
|
std::set<FaceIterator, MeshFacet_Less > aFaceSet;
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, uIndex++) {
|
|
std::pair<std::set<FaceIterator, MeshFacet_Less>::iterator, bool>
|
|
pI = aFaceSet.insert(it);
|
|
if (!pI.second)
|
|
aRemoveFaces.push_back(uIndex);
|
|
}
|
|
|
|
_rclMesh.DeleteFacets(aRemoveFaces);
|
|
_rclMesh.RebuildNeighbours(); // needs to be done here
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalInternalFacets::Evaluate()
|
|
{
|
|
_indices.clear();
|
|
FacetIndex uIndex=0;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
|
|
// get all facets
|
|
std::set<FaceIterator, MeshFacet_Less > aFaceSet;
|
|
MeshFacetArray::_TConstIterator first = rFaces.begin();
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, uIndex++) {
|
|
std::pair<std::set<FaceIterator, MeshFacet_Less>::iterator, bool>
|
|
pI = aFaceSet.insert(it);
|
|
if (!pI.second) {
|
|
// collect both elements
|
|
_indices.push_back(*pI.first - first);
|
|
_indices.push_back(uIndex);
|
|
}
|
|
}
|
|
|
|
return _indices.empty();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalDegeneratedFacets::Evaluate()
|
|
{
|
|
MeshFacetIterator it(_rclMesh);
|
|
for (it.Init(); it.More(); it.Next()) {
|
|
if (it->IsDegenerated(fEpsilon))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
unsigned long MeshEvalDegeneratedFacets::CountEdgeTooSmall (float fMinEdgeLength) const
|
|
{
|
|
MeshFacetIterator clFIter(_rclMesh);
|
|
unsigned long k = 0;
|
|
|
|
while (clFIter.EndReached() == false) {
|
|
for (int i = 0; i < 3; i++) {
|
|
if (Base::Distance(clFIter->_aclPoints[i], clFIter->_aclPoints[(i+1)%3]) < fMinEdgeLength)
|
|
k++;
|
|
}
|
|
++clFIter;
|
|
}
|
|
|
|
return k;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalDegeneratedFacets::GetIndices() const
|
|
{
|
|
std::vector<FacetIndex> aInds;
|
|
MeshFacetIterator it(_rclMesh);
|
|
for (it.Init(); it.More(); it.Next()) {
|
|
if (it->IsDegenerated(fEpsilon))
|
|
aInds.push_back(it.Position());
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixDegeneratedFacets::Fixup()
|
|
{
|
|
MeshTopoAlgorithm cTopAlg(_rclMesh);
|
|
|
|
MeshFacetIterator it(_rclMesh);
|
|
for (it.Init(); it.More(); it.Next()) {
|
|
if (it->IsDegenerated(fEpsilon)) {
|
|
FacetIndex uId = it.Position();
|
|
bool removed = cTopAlg.RemoveDegeneratedFacet(uId);
|
|
if (removed) {
|
|
// due to a modification of the array the iterator became invalid
|
|
it.Set(uId-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MeshRemoveNeedles::Fixup()
|
|
{
|
|
typedef std::pair<unsigned long, int> FaceEdge; // (face, edge) pair
|
|
typedef std::pair<float, FaceEdge> FaceEdgePriority;
|
|
|
|
MeshTopoAlgorithm topAlg(_rclMesh);
|
|
MeshRefPointToFacets vf_it(_rclMesh);
|
|
const MeshFacetArray &rclFAry = _rclMesh.GetFacets();
|
|
const MeshPointArray &rclPAry = _rclMesh.GetPoints();
|
|
rclFAry.ResetInvalid();
|
|
rclPAry.ResetInvalid();
|
|
rclPAry.ResetFlag(MeshPoint::VISIT);
|
|
std::size_t facetCount = rclFAry.size();
|
|
|
|
std::priority_queue<FaceEdgePriority,
|
|
std::vector<FaceEdgePriority>,
|
|
std::greater<FaceEdgePriority> > todo;
|
|
for (std::size_t index = 0; index < facetCount; index++) {
|
|
const MeshFacet& facet = rclFAry[index];
|
|
MeshGeomFacet tria(_rclMesh.GetFacet(facet));
|
|
float perimeter = tria.Perimeter();
|
|
float fMinLen = perimeter * fMinEdgeLength;
|
|
for (int i=0; i<3; i++) {
|
|
const Base::Vector3f& p1 = rclPAry[facet._aulPoints[i]];
|
|
const Base::Vector3f& p2 = rclPAry[facet._aulPoints[(i+1)%3]];
|
|
|
|
float distance = Base::Distance(p1, p2);
|
|
if (distance < fMinLen) {
|
|
unsigned long facetIndex = static_cast<unsigned long>(index);
|
|
todo.push(std::make_pair(distance, std::make_pair(facetIndex, i)));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool removedEdge = false;
|
|
while (!todo.empty()) {
|
|
FaceEdge faceedge = todo.top().second;
|
|
todo.pop();
|
|
|
|
// check if one of the face pairs was already processed
|
|
if (!rclFAry[faceedge.first].IsValid())
|
|
continue;
|
|
|
|
// the facet points may have changed, so check the current distance again
|
|
const MeshFacet& facet = rclFAry[faceedge.first];
|
|
MeshGeomFacet tria(_rclMesh.GetFacet(facet));
|
|
float perimeter = tria.Perimeter();
|
|
float fMinLen = perimeter * fMinEdgeLength;
|
|
const Base::Vector3f& p1 = rclPAry[facet._aulPoints[faceedge.second]];
|
|
const Base::Vector3f& p2 = rclPAry[facet._aulPoints[(faceedge.second+1)%3]];
|
|
float distance = Base::Distance(p1, p2);
|
|
if (distance >= fMinLen)
|
|
continue;
|
|
|
|
// collect the collapse-edge information
|
|
EdgeCollapse ce;
|
|
ce._fromPoint = rclFAry[faceedge.first]._aulPoints[faceedge.second];
|
|
ce._toPoint = rclFAry[faceedge.first]._aulPoints[(faceedge.second+1)%3];
|
|
|
|
ce._removeFacets.push_back(faceedge.first);
|
|
FacetIndex neighbour = rclFAry[faceedge.first]._aulNeighbours[faceedge.second];
|
|
if (neighbour != FACET_INDEX_MAX)
|
|
ce._removeFacets.push_back(neighbour);
|
|
|
|
std::set<FacetIndex> vf = vf_it[ce._fromPoint];
|
|
vf.erase(faceedge.first);
|
|
if (neighbour != FACET_INDEX_MAX)
|
|
vf.erase(neighbour);
|
|
ce._changeFacets.insert(ce._changeFacets.begin(), vf.begin(), vf.end());
|
|
|
|
// get adjacent points
|
|
std::set<PointIndex> vv;
|
|
vv = vf_it.NeighbourPoints(ce._fromPoint);
|
|
ce._adjacentFrom.insert(ce._adjacentFrom.begin(), vv.begin(),vv.end());
|
|
vv = vf_it.NeighbourPoints(ce._toPoint);
|
|
ce._adjacentTo.insert(ce._adjacentTo.begin(), vv.begin(),vv.end());
|
|
|
|
if (topAlg.IsCollapseEdgeLegal(ce)) {
|
|
topAlg.CollapseEdge(ce);
|
|
for (auto it : ce._removeFacets) {
|
|
vf_it.RemoveFacet(it);
|
|
}
|
|
for (auto it : ce._changeFacets) {
|
|
vf_it.RemoveNeighbour(ce._fromPoint, it);
|
|
vf_it.AddNeighbour(ce._toPoint, it);
|
|
}
|
|
removedEdge = true;
|
|
}
|
|
}
|
|
|
|
if (removedEdge) {
|
|
topAlg.Cleanup();
|
|
_rclMesh.RebuildNeighbours();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshFixCaps::Fixup()
|
|
{
|
|
typedef std::pair<unsigned long, int> FaceVertex; // (face, vertex) pair
|
|
typedef std::pair<float, FaceVertex> FaceVertexPriority;
|
|
|
|
MeshTopoAlgorithm topAlg(_rclMesh);
|
|
const MeshFacetArray &rclFAry = _rclMesh.GetFacets();
|
|
const MeshPointArray &rclPAry = _rclMesh.GetPoints();
|
|
std::size_t facetCount = rclFAry.size();
|
|
|
|
float fCosMaxAngle = static_cast<float>(cos(fMaxAngle));
|
|
|
|
std::priority_queue<FaceVertexPriority,
|
|
std::vector<FaceVertexPriority>,
|
|
std::greater<FaceVertexPriority> > todo;
|
|
for (std::size_t index = 0; index < facetCount; index++) {
|
|
for (int i=0; i<3; i++) {
|
|
const MeshFacet& facet = rclFAry[index];
|
|
const Base::Vector3f& p1 = rclPAry[facet._aulPoints[i]];
|
|
const Base::Vector3f& p2 = rclPAry[facet._aulPoints[(i+1)%3]];
|
|
const Base::Vector3f& p3 = rclPAry[facet._aulPoints[(i+2)%3]];
|
|
Base::Vector3f dir1(p2-p1); dir1.Normalize();
|
|
Base::Vector3f dir2(p3-p1); dir2.Normalize();
|
|
|
|
float fCosAngle = dir1.Dot(dir2);
|
|
if (fCosAngle < fCosMaxAngle) {
|
|
unsigned long facetIndex = static_cast<unsigned long>(index);
|
|
todo.push(std::make_pair(fCosAngle, std::make_pair(facetIndex, i)));
|
|
}
|
|
}
|
|
}
|
|
|
|
while (!todo.empty()) {
|
|
FaceVertex facevertex = todo.top().second;
|
|
todo.pop();
|
|
|
|
// the facet points may have changed, so check the current distance again
|
|
const MeshFacet& facet = rclFAry[facevertex.first];
|
|
const Base::Vector3f& p1 = rclPAry[facet._aulPoints[facevertex.second]];
|
|
const Base::Vector3f& p2 = rclPAry[facet._aulPoints[(facevertex.second+1)%3]];
|
|
const Base::Vector3f& p3 = rclPAry[facet._aulPoints[(facevertex.second+2)%3]];
|
|
Base::Vector3f dir1(p2-p1); dir1.Normalize();
|
|
Base::Vector3f dir2(p3-p1); dir2.Normalize();
|
|
|
|
// check that the criterion is still OK in case
|
|
// an earlier edge-swap has an impact
|
|
float fCosAngle = dir1.Dot(dir2);
|
|
if (fCosAngle >= fCosMaxAngle)
|
|
continue;
|
|
|
|
// the triangle shouldn't be a needle, therefore the projection of the point with
|
|
// the maximum angle must have a clear distance to the other corner points
|
|
// as factor we choose a default value of 25% of the corresponding edge length
|
|
Base::Vector3f p4 = p1.Perpendicular(p2, p3-p2);
|
|
float distP2P3 = Base::Distance(p2,p3);
|
|
float distP2P4 = Base::Distance(p2,p4);
|
|
float distP3P4 = Base::Distance(p3,p4);
|
|
if (distP2P4/distP2P3 < fSplitFactor || distP3P4/distP2P3 < fSplitFactor)
|
|
continue;
|
|
|
|
FacetIndex facetpos = facevertex.first;
|
|
FacetIndex neighbour = rclFAry[facetpos]._aulNeighbours[(facevertex.second+1)%3];
|
|
if (neighbour != FACET_INDEX_MAX)
|
|
topAlg.SwapEdge(facetpos, neighbour);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalDeformedFacets::Evaluate()
|
|
{
|
|
float fCosMinAngle = cos(fMinAngle);
|
|
float fCosMaxAngle = cos(fMaxAngle);
|
|
|
|
MeshFacetIterator it(_rclMesh);
|
|
for (it.Init(); it.More(); it.Next()) {
|
|
if (it->IsDeformed(fCosMinAngle, fCosMaxAngle))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalDeformedFacets::GetIndices() const
|
|
{
|
|
float fCosMinAngle = cos(fMinAngle);
|
|
float fCosMaxAngle = cos(fMaxAngle);
|
|
|
|
std::vector<FacetIndex> aInds;
|
|
MeshFacetIterator it(_rclMesh);
|
|
for (it.Init(); it.More(); it.Next()) {
|
|
if (it->IsDeformed(fCosMinAngle, fCosMaxAngle))
|
|
aInds.push_back(it.Position());
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixDeformedFacets::Fixup()
|
|
{
|
|
float fCosMinAngle = cos(fMinAngle);
|
|
float fCosMaxAngle = cos(fMaxAngle);
|
|
|
|
Base::Vector3f u,v;
|
|
MeshTopoAlgorithm cTopAlg(_rclMesh);
|
|
|
|
MeshFacetIterator it(_rclMesh);
|
|
for (it.Init(); it.More(); it.Next()) {
|
|
// possibly deformed but not degenerated
|
|
if (!it->IsDegenerated(fEpsilon)) {
|
|
// store the angles to avoid to compute twice
|
|
float fCosAngles[3] = {0,0,0};
|
|
bool done=false;
|
|
|
|
for (int i=0; i<3; i++) {
|
|
u = it->_aclPoints[(i+1)%3]-it->_aclPoints[i];
|
|
v = it->_aclPoints[(i+2)%3]-it->_aclPoints[i];
|
|
u.Normalize();
|
|
v.Normalize();
|
|
|
|
float fCosAngle = u * v;
|
|
fCosAngles[i] = fCosAngle;
|
|
}
|
|
|
|
// first check for angle > 120 deg: in this case we swap with the opposite edge
|
|
for (int i=0; i<3; i++) {
|
|
float fCosAngle = fCosAngles[i];
|
|
if (fCosAngle < fCosMaxAngle) {
|
|
const MeshFacet& face = it.GetReference();
|
|
FacetIndex uNeighbour = face._aulNeighbours[(i+1)%3];
|
|
if (uNeighbour!=FACET_INDEX_MAX && cTopAlg.ShouldSwapEdge(it.Position(), uNeighbour, fMaxSwapAngle)) {
|
|
cTopAlg.SwapEdge(it.Position(), uNeighbour);
|
|
done = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// we have swapped already
|
|
if (done)
|
|
continue;
|
|
|
|
// now check for angle < 30 deg: in this case we swap with one of the edges the corner is part of
|
|
for (int j=0; j<3; j++) {
|
|
float fCosAngle = fCosAngles[j];
|
|
if (fCosAngle > fCosMinAngle) {
|
|
const MeshFacet& face = it.GetReference();
|
|
|
|
FacetIndex uNeighbour = face._aulNeighbours[j];
|
|
if (uNeighbour!=FACET_INDEX_MAX && cTopAlg.ShouldSwapEdge(it.Position(), uNeighbour, fMaxSwapAngle)) {
|
|
cTopAlg.SwapEdge(it.Position(), uNeighbour);
|
|
break;
|
|
}
|
|
|
|
uNeighbour = face._aulNeighbours[(j+2)%3];
|
|
if (uNeighbour!=FACET_INDEX_MAX && cTopAlg.ShouldSwapEdge(it.Position(), uNeighbour, fMaxSwapAngle)) {
|
|
cTopAlg.SwapEdge(it.Position(), uNeighbour);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshFixMergeFacets::Fixup()
|
|
{
|
|
MeshCore::MeshRefPointToPoints vv_it(_rclMesh);
|
|
MeshCore::MeshRefPointToFacets vf_it(_rclMesh);
|
|
unsigned long countPoints = _rclMesh.CountPoints();
|
|
|
|
std::vector<MeshFacet> newFacets;
|
|
newFacets.reserve(countPoints/20); // 5% should be sufficient
|
|
|
|
MeshTopoAlgorithm topAlg(_rclMesh);
|
|
for (unsigned long i=0; i<countPoints; i++) {
|
|
if (vv_it[i].size() == 3 && vf_it[i].size() == 3) {
|
|
VertexCollapse vc;
|
|
vc._point = i;
|
|
const std::set<PointIndex>& adjPts = vv_it[i];
|
|
vc._circumPoints.insert(vc._circumPoints.begin(), adjPts.begin(), adjPts.end());
|
|
const std::set<FacetIndex>& adjFts = vf_it[i];
|
|
vc._circumFacets.insert(vc._circumFacets.begin(), adjFts.begin(), adjFts.end());
|
|
topAlg.CollapseVertex(vc);
|
|
}
|
|
}
|
|
|
|
topAlg.Cleanup();
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalDentsOnSurface::Evaluate()
|
|
{
|
|
this->indices.clear();
|
|
MeshRefPointToFacets clPt2Facets(_rclMesh);
|
|
const MeshPointArray& rPntAry = _rclMesh.GetPoints();
|
|
MeshFacetArray::_TConstIterator f_beg = _rclMesh.GetFacets().begin();
|
|
|
|
MeshGeomFacet rTriangle;
|
|
Base::Vector3f tmp;
|
|
unsigned long ctPoints = _rclMesh.CountPoints();
|
|
for (unsigned long index=0; index < ctPoints; index++) {
|
|
std::vector<PointIndex> point;
|
|
point.push_back(index);
|
|
|
|
// get the local neighbourhood of the point
|
|
std::set<PointIndex> nb = clPt2Facets.NeighbourPoints(point,1);
|
|
const std::set<FacetIndex>& faces = clPt2Facets[index];
|
|
|
|
for (std::set<PointIndex>::iterator pt = nb.begin(); pt != nb.end(); ++pt) {
|
|
const MeshPoint& mp = rPntAry[*pt];
|
|
for (std::set<FacetIndex>::const_iterator
|
|
ft = faces.begin(); ft != faces.end(); ++ft) {
|
|
// the point must not be part of the facet we test
|
|
if (f_beg[*ft]._aulPoints[0] == *pt)
|
|
continue;
|
|
if (f_beg[*ft]._aulPoints[1] == *pt)
|
|
continue;
|
|
if (f_beg[*ft]._aulPoints[2] == *pt)
|
|
continue;
|
|
// is the point projectable onto the facet?
|
|
rTriangle = _rclMesh.GetFacet(f_beg[*ft]);
|
|
if (rTriangle.IntersectWithLine(mp,rTriangle.GetNormal(),tmp)) {
|
|
const std::set<FacetIndex>& f = clPt2Facets[*pt];
|
|
this->indices.insert(this->indices.end(), f.begin(), f.end());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove duplicates
|
|
std::sort(this->indices.begin(), this->indices.end());
|
|
this->indices.erase(std::unique(this->indices.begin(),
|
|
this->indices.end()), this->indices.end());
|
|
|
|
return this->indices.empty();
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalDentsOnSurface::GetIndices() const
|
|
{
|
|
return this->indices;
|
|
}
|
|
|
|
/*
|
|
Forbidden is:
|
|
+ two facets share a common point but not a common edge
|
|
|
|
Repair:
|
|
+ store the point indices which can be projected on a face
|
|
+ store the face indices on which a point can be projected
|
|
+ remove faces with an edge length smaller than a certain threshold (e.g. 0.01) from the stored triangles or that reference one of the stored points
|
|
+ for this edge merge the two points
|
|
+ if a point of a face can be projected onto another face and they have a common point then split the second face if the distance is under a certain threshold
|
|
*/
|
|
bool MeshFixDentsOnSurface::Fixup()
|
|
{
|
|
MeshEvalDentsOnSurface eval(_rclMesh);
|
|
if (!eval.Evaluate()) {
|
|
std::vector<FacetIndex> inds = eval.GetIndices();
|
|
_rclMesh.DeleteFacets(inds);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalFoldsOnSurface::Evaluate()
|
|
{
|
|
this->indices.clear();
|
|
const MeshFacetArray& rFAry = _rclMesh.GetFacets();
|
|
unsigned long ct=0;
|
|
for (MeshFacetArray::const_iterator it = rFAry.begin(); it != rFAry.end(); ++it, ct++) {
|
|
for (int i=0; i<3; i++) {
|
|
FacetIndex n1 = it->_aulNeighbours[i];
|
|
FacetIndex n2 = it->_aulNeighbours[(i+1)%3];
|
|
Base::Vector3f v1 =_rclMesh.GetFacet(*it).GetNormal();
|
|
if (n1 != FACET_INDEX_MAX && n2 != FACET_INDEX_MAX) {
|
|
Base::Vector3f v2 = _rclMesh.GetFacet(n1).GetNormal();
|
|
Base::Vector3f v3 = _rclMesh.GetFacet(n2).GetNormal();
|
|
if (v2 * v3 > 0.0f) {
|
|
if (v1 * v2 < -0.1f && v1 * v3 < -0.1f) {
|
|
indices.push_back(n1);
|
|
indices.push_back(n2);
|
|
indices.push_back(ct);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove duplicates
|
|
std::sort(this->indices.begin(), this->indices.end());
|
|
this->indices.erase(std::unique(this->indices.begin(),
|
|
this->indices.end()), this->indices.end());
|
|
return this->indices.empty();
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalFoldsOnSurface::GetIndices() const
|
|
{
|
|
return this->indices;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalFoldsOnBoundary::Evaluate()
|
|
{
|
|
// remove all boundary facets with two open edges and where
|
|
// the angle to the neighbour is more than 60 degree
|
|
this->indices.clear();
|
|
const MeshFacetArray& rFacAry = _rclMesh.GetFacets();
|
|
for (MeshFacetArray::_TConstIterator it = rFacAry.begin(); it != rFacAry.end(); ++it) {
|
|
if (it->CountOpenEdges() == 2) {
|
|
for (int i=0; i<3; i++) {
|
|
if (it->_aulNeighbours[i] != FACET_INDEX_MAX) {
|
|
MeshGeomFacet f1 = _rclMesh.GetFacet(*it);
|
|
MeshGeomFacet f2 = _rclMesh.GetFacet(it->_aulNeighbours[i]);
|
|
float cos_angle = f1.GetNormal() * f2.GetNormal();
|
|
if (cos_angle <= 0.5f) // ~ 60 degree
|
|
indices.push_back(it-rFacAry.begin());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this->indices.empty();
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalFoldsOnBoundary::GetIndices() const
|
|
{
|
|
return this->indices;
|
|
}
|
|
|
|
bool MeshFixFoldsOnBoundary::Fixup()
|
|
{
|
|
MeshEvalFoldsOnBoundary eval(_rclMesh);
|
|
if (!eval.Evaluate()) {
|
|
std::vector<FacetIndex> inds = eval.GetIndices();
|
|
_rclMesh.DeleteFacets(inds);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalFoldOversOnSurface::Evaluate()
|
|
{
|
|
this->indices.clear();
|
|
const MeshCore::MeshFacetArray& facets = _rclMesh.GetFacets();
|
|
MeshCore::MeshFacetArray::_TConstIterator f_it,
|
|
f_beg = facets.begin(), f_end = facets.end();
|
|
|
|
Base::Vector3f n1, n2;
|
|
for (f_it = facets.begin(); f_it != f_end; ++f_it) {
|
|
for (int i=0; i<3; i++) {
|
|
FacetIndex index1 = f_it->_aulNeighbours[i];
|
|
FacetIndex index2 = f_it->_aulNeighbours[(i+1)%3];
|
|
if (index1 != FACET_INDEX_MAX && index2 != FACET_INDEX_MAX) {
|
|
// if the topology is correct but the normals flip from
|
|
// two neighbours we have a fold
|
|
if (f_it->HasSameOrientation(f_beg[index1]) &&
|
|
f_it->HasSameOrientation(f_beg[index2])) {
|
|
n1 = _rclMesh.GetFacet(index1).GetNormal();
|
|
n2 = _rclMesh.GetFacet(index2).GetNormal();
|
|
if (n1 * n2 < -0.5f) { // angle > 120 deg
|
|
this->indices.push_back(f_it-f_beg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this->indices.empty();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
bool MeshEvalBorderFacet::Evaluate()
|
|
{
|
|
const MeshCore::MeshFacetArray& facets = _rclMesh.GetFacets();
|
|
MeshCore::MeshFacetArray::_TConstIterator f_it,
|
|
f_beg = facets.begin(), f_end = facets.end();
|
|
MeshCore::MeshRefPointToPoints vv_it(_rclMesh);
|
|
MeshCore::MeshRefPointToFacets vf_it(_rclMesh);
|
|
|
|
for (f_it = facets.begin(); f_it != f_end; ++f_it) {
|
|
bool ok = true;
|
|
for (int i=0; i<3; i++) {
|
|
PointIndex index = f_it->_aulPoints[i];
|
|
if (vv_it[index].size() == vf_it[index].size()) {
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
_facets.push_back(f_it-f_beg);
|
|
}
|
|
|
|
return _facets.empty();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalRangeFacet::Evaluate()
|
|
{
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
FacetIndex ulCtFacets = rFaces.size();
|
|
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it) {
|
|
for (int i = 0; i < 3; i++) {
|
|
if ((it->_aulNeighbours[i] >= ulCtFacets) && (it->_aulNeighbours[i] < FACET_INDEX_MAX)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalRangeFacet::GetIndices() const
|
|
{
|
|
std::vector<FacetIndex> aInds;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
FacetIndex ulCtFacets = rFaces.size();
|
|
|
|
FacetIndex ind=0;
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, ind++) {
|
|
for (int i = 0; i < 3; i++) {
|
|
if ((it->_aulNeighbours[i] >= ulCtFacets) && (it->_aulNeighbours[i] < FACET_INDEX_MAX)) {
|
|
aInds.push_back(ind);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixRangeFacet::Fixup()
|
|
{
|
|
_rclMesh.RebuildNeighbours();
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalRangePoint::Evaluate()
|
|
{
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
PointIndex ulCtPoints = _rclMesh.CountPoints();
|
|
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it) {
|
|
if (std::find_if(it->_aulPoints, it->_aulPoints + 3, [ulCtPoints](PointIndex i) {
|
|
return i >= ulCtPoints;
|
|
}) < it->_aulPoints + 3)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<PointIndex> MeshEvalRangePoint::GetIndices() const
|
|
{
|
|
std::vector<PointIndex> aInds;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
PointIndex ulCtPoints = _rclMesh.CountPoints();
|
|
|
|
PointIndex ind=0;
|
|
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, ind++) {
|
|
if (std::find_if(it->_aulPoints, it->_aulPoints + 3, [ulCtPoints](PointIndex i) {
|
|
return i >= ulCtPoints;
|
|
}) < it->_aulPoints + 3)
|
|
aInds.push_back(ind);
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixRangePoint::Fixup()
|
|
{
|
|
MeshEvalRangePoint eval(_rclMesh);
|
|
if (_rclMesh.CountPoints() == 0) {
|
|
// if no points are there but facets then the whole mesh can be cleared
|
|
_rclMesh.Clear();
|
|
}
|
|
else {
|
|
// facets with point indices out of range cannot be directly deleted because
|
|
// 'DeleteFacets' will segfault. But setting all point indices to 0 works.
|
|
std::vector<PointIndex> invalid = eval.GetIndices();
|
|
if (!invalid.empty()) {
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
for (std::vector<PointIndex>::iterator it = invalid.begin(); it != invalid.end(); ++it) {
|
|
MeshFacet& face = const_cast<MeshFacet&>(rFaces[*it]);
|
|
face._aulPoints[0] = 0;
|
|
face._aulPoints[1] = 0;
|
|
face._aulPoints[2] = 0;
|
|
}
|
|
|
|
_rclMesh.DeleteFacets(invalid);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalCorruptedFacets::Evaluate()
|
|
{
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
|
|
for ( MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it ) {
|
|
// dupicated point indices
|
|
if (it->IsDegenerated())
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalCorruptedFacets::GetIndices() const
|
|
{
|
|
std::vector<FacetIndex> aInds;
|
|
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
|
|
FacetIndex ind=0;
|
|
|
|
for ( MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, ind++ ) {
|
|
if (it->IsDegenerated())
|
|
aInds.push_back(ind);
|
|
}
|
|
|
|
return aInds;
|
|
}
|
|
|
|
bool MeshFixCorruptedFacets::Fixup()
|
|
{
|
|
MeshTopoAlgorithm cTopAlg(_rclMesh);
|
|
|
|
MeshFacetIterator it(_rclMesh);
|
|
for ( it.Init(); it.More(); it.Next() )
|
|
{
|
|
if ( it.GetReference().IsDegenerated() )
|
|
{
|
|
unsigned long uId = it.Position();
|
|
bool removed = cTopAlg.RemoveCorruptedFacet(uId);
|
|
if (removed) {
|
|
// due to a modification of the array the iterator became invalid
|
|
it.Set(uId-1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool MeshEvalPointOnEdge::Evaluate ()
|
|
{
|
|
MeshFacetGrid facetGrid(_rclMesh);
|
|
const MeshPointArray& points = _rclMesh.GetPoints();
|
|
const MeshFacetArray& facets = _rclMesh.GetFacets();
|
|
|
|
auto IsPointOnEdge = [&points](PointIndex idx, const MeshFacet& facet) {
|
|
// point must not be a corner of the facet
|
|
if (!facet.HasPoint(idx)) {
|
|
for (int i = 0; i < 3; i++) {
|
|
MeshGeomEdge edge;
|
|
edge._aclPoints[0] = points[facet._aulPoints[i]];
|
|
edge._aclPoints[1] = points[facet._aulPoints[(i+1)%3]];
|
|
|
|
if (edge.GetBoundBox().IsInBox(points[idx])) {
|
|
if (edge.IsPointOf(points[idx], 0.001f))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
PointIndex maxPoints = _rclMesh.CountPoints();
|
|
for (PointIndex i = 0; i < maxPoints; i++) {
|
|
std::vector<FacetIndex> elements;
|
|
facetGrid.GetElements(points[i], elements);
|
|
|
|
for (const auto& it : elements) {
|
|
const MeshFacet& face = facets[it];
|
|
if (IsPointOnEdge(i, face)) {
|
|
pointsIndices.push_back(i);
|
|
if (face.HasOpenEdge())
|
|
facetsIndices.push_back(it);
|
|
}
|
|
}
|
|
}
|
|
return pointsIndices.empty();
|
|
}
|
|
|
|
std::vector<PointIndex> MeshEvalPointOnEdge::GetPointIndices() const
|
|
{
|
|
return pointsIndices;
|
|
}
|
|
|
|
std::vector<FacetIndex> MeshEvalPointOnEdge::GetFacetIndices() const
|
|
{
|
|
return facetsIndices;
|
|
}
|
|
|
|
bool MeshFixPointOnEdge::Fixup ()
|
|
{
|
|
MeshEvalPointOnEdge eval(_rclMesh);
|
|
eval.Evaluate();
|
|
std::vector<PointIndex> pointsIndices = eval.GetPointIndices();
|
|
std::vector<FacetIndex> facetsIndices = eval.GetFacetIndices();
|
|
|
|
if (!pointsIndices.empty()) {
|
|
if (fillBoundary) {
|
|
MarkBoundaries(facetsIndices);
|
|
}
|
|
|
|
_rclMesh.DeletePoints(pointsIndices);
|
|
|
|
if (fillBoundary) {
|
|
std::list<std::vector<PointIndex> > borderList;
|
|
FindBoundaries(borderList);
|
|
if (!borderList.empty())
|
|
FillBoundaries(borderList);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MeshFixPointOnEdge::MarkBoundaries(const std::vector<FacetIndex>& facetsIndices)
|
|
{
|
|
MeshAlgorithm meshalg(_rclMesh);
|
|
meshalg.ResetFacetFlag(MeshFacet::TMP0);
|
|
meshalg.SetFacetsFlag(facetsIndices, MeshFacet::TMP0);
|
|
}
|
|
|
|
void MeshFixPointOnEdge::FindBoundaries(std::list<std::vector<PointIndex> >& borderList)
|
|
{
|
|
std::vector<FacetIndex> tmp;
|
|
MeshAlgorithm meshalg(_rclMesh);
|
|
meshalg.GetFacetsFlag(tmp, MeshFacet::TMP0);
|
|
|
|
if (!tmp.empty()) {
|
|
meshalg.GetFacetsBorders(tmp, borderList);
|
|
}
|
|
}
|
|
|
|
void MeshFixPointOnEdge::FillBoundaries(const std::list<std::vector<PointIndex> >& borderList)
|
|
{
|
|
FlatTriangulator tria;
|
|
tria.SetVerifier(new MeshCore::TriangulationVerifierV2);
|
|
MeshTopoAlgorithm topalg(_rclMesh);
|
|
std::list<std::vector<PointIndex> > failed;
|
|
topalg.FillupHoles(1, tria, borderList, failed);
|
|
}
|