Files
create/src/Mod/Mesh/App/Core/Degeneration.cpp
2016-07-31 19:08:42 +02:00

1069 lines
37 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>
#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 <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<unsigned long> MeshEvalInvalids::GetIndices() const
{
std::vector<unsigned long> aInds;
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
const MeshPointArray& rPoints = _rclMesh.GetPoints();
unsigned long 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 : public std::binary_function<const VertexIterator&,
const VertexIterator&, bool>
{
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 : public std::binary_function<const VertexIterator&,
const VertexIterator&, bool>
{
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<unsigned long> 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<unsigned long> 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::vector<unsigned long> aInds;
std::sort(vertices.begin(), vertices.end(), Vertex_Less());
Vertex_EqualTo pred;
std::vector<VertexIterator>::iterator next = vertices.begin();
std::map<unsigned long, unsigned long> mapPointIndex;
std::vector<unsigned long> pointIndices;
while (next < vertices.end()) {
next = std::adjacent_find(next, vertices.end(), pred);
if (next < vertices.end()) {
std::vector<VertexIterator>::iterator first = next;
unsigned long first_index = *first - rPoints.begin();
++next;
while (next < vertices.end() && pred(*first, *next)) {
unsigned long 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<unsigned long, unsigned long>::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<unsigned long> MeshEvalNaNPoints::GetIndices() const
{
std::vector<unsigned long> 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<unsigned long> 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 : public std::binary_function<const FaceIterator&,
const FaceIterator&, bool>
{
bool operator()(const FaceIterator& x,
const FaceIterator& y) const
{
unsigned long tmp;
unsigned long x0 = x->_aulPoints[0];
unsigned long x1 = x->_aulPoints[1];
unsigned long x2 = x->_aulPoints[2];
unsigned long y0 = y->_aulPoints[0];
unsigned long y1 = y->_aulPoints[1];
unsigned long 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 : public std::binary_function<const FaceIterator&,
const FaceIterator&, bool>
{
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<unsigned long> 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<unsigned long> 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<unsigned long> aInds;
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
unsigned long 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()
{
unsigned long uIndex=0;
std::vector<unsigned long> 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();
unsigned long 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<unsigned long> MeshEvalDegeneratedFacets::GetIndices() const
{
std::vector<unsigned long> 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)) {
unsigned long uCt = _rclMesh.CountFacets();
unsigned long uId = it.Position();
cTopAlg.RemoveDegeneratedFacet(uId);
if (uCt != _rclMesh.CountFacets()) {
// due to a modification of the array the iterator became invalid
it.Set(uId-1);
}
}
}
return true;
}
unsigned long MeshFixDegeneratedFacets::RemoveEdgeTooSmall (float fMinEdgeLength, float fMinEdgeAngle)
{
unsigned long ulCtLastLoop, ulCtFacets = _rclMesh.CountFacets();
const MeshFacetArray &rclFAry = _rclMesh.GetFacets();
const MeshPointArray &rclPAry = _rclMesh.GetPoints();
MeshFacetArray::_TConstIterator f_beg = rclFAry.begin();
// repeat until no facet van be removed
do {
MeshRefPointToFacets clPt2Facets(_rclMesh);
rclFAry.ResetInvalid();
rclPAry.ResetInvalid();
rclPAry.ResetFlag(MeshPoint::VISIT);
std::set<std::pair<unsigned long, unsigned long> > aclPtDelList;
MeshFacetIterator clFIter(_rclMesh), clFN0(_rclMesh), clFN1(_rclMesh), clFN2(_rclMesh);
for (clFIter.Init(); clFIter.More(); clFIter.Next()) {
MeshGeomFacet clSFacet = *clFIter;
Base::Vector3f clP0 = clSFacet._aclPoints[0];
Base::Vector3f clP1 = clSFacet._aclPoints[1];
Base::Vector3f clP2 = clSFacet._aclPoints[2];
Base::Vector3f clE01 = clP1 - clP0;
Base::Vector3f clE12 = clP2 - clP1;
Base::Vector3f clE20 = clP2 - clP0;
MeshFacet clFacet = clFIter.GetIndices();
unsigned long ulP0 = clFacet._aulPoints[0];
unsigned long ulP1 = clFacet._aulPoints[1];
unsigned long ulP2 = clFacet._aulPoints[2];
if ((Base::Distance(clP0, clP1) < fMinEdgeLength) ||
(clE20.GetAngle(-clE12) < fMinEdgeAngle)) {
// delete point P1 on P0
aclPtDelList.insert(std::make_pair
(std::min<unsigned long>(ulP1, ulP0), std::max<unsigned long>(ulP1, ulP0)));
}
else if ((Base::Distance(clP1, clP2) < fMinEdgeLength) ||
(clE01.GetAngle(-clE20) < fMinEdgeAngle)) {
// delete point P2 on P1
aclPtDelList.insert(std::make_pair
(std::min<unsigned long>(ulP2, ulP1), std::max<unsigned long>(ulP2, ulP1)));
}
else if ((Base::Distance(clP2, clP0) < fMinEdgeLength) ||
(clE12.GetAngle(-clE01) < fMinEdgeAngle)) {
// delete point P0 on P2
aclPtDelList.insert(std::make_pair
(std::min<unsigned long>(ulP0, ulP2), std::max<unsigned long>(ulP0, ulP2)));
}
}
// remove points, fix indices
for (std::set<std::pair<unsigned long, unsigned long> >::iterator pI = aclPtDelList.begin();
pI != aclPtDelList.end(); ++pI) {
// one of the point pairs is already processed
if ((rclPAry[pI->first].IsFlag(MeshPoint::VISIT) == true) ||
(rclPAry[pI->second].IsFlag(MeshPoint::VISIT) == true))
continue;
rclPAry[pI->first].SetFlag(MeshPoint::VISIT);
rclPAry[pI->second].SetFlag(MeshPoint::VISIT);
rclPAry[pI->second].SetInvalid();
// Redirect all point-indices to the new neighbour point of all facets referencing the
// deleted point
const std::set<unsigned long>& faces = clPt2Facets[pI->second];
for (std::set<unsigned long>::const_iterator pF = faces.begin(); pF != faces.end(); ++pF) {
const MeshFacet &rclF = f_beg[*pF];
for (int i = 0; i < 3; i++) {
// if (rclF._aulPoints[i] == pI->second)
// rclF._aulPoints[i] = pI->first;
}
// Delete facets with two identical corners
if ((rclF._aulPoints[0] == rclF._aulPoints[1]) ||
(rclF._aulPoints[0] == rclF._aulPoints[2]) ||
(rclF._aulPoints[1] == rclF._aulPoints[2])) {
rclF.SetInvalid();
}
}
}
ulCtLastLoop = _rclMesh.CountFacets();
_rclMesh.RemoveInvalids();
}
while (ulCtLastLoop > _rclMesh.CountFacets());
_rclMesh.RebuildNeighbours();
return ulCtFacets - _rclMesh.CountFacets();
}
// ----------------------------------------------------------------------
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<unsigned long> MeshEvalDeformedFacets::GetIndices() const
{
float fCosMinAngle = cos(fMinAngle);
float fCosMaxAngle = cos(fMaxAngle);
std::vector<unsigned long> 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();
unsigned long uNeighbour = face._aulNeighbours[(i+1)%3];
if (uNeighbour!=ULONG_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();
unsigned long uNeighbour = face._aulNeighbours[j];
if (uNeighbour!=ULONG_MAX && cTopAlg.ShouldSwapEdge(it.Position(), uNeighbour, fMaxSwapAngle)) {
cTopAlg.SwapEdge(it.Position(), uNeighbour);
break;
}
uNeighbour = face._aulNeighbours[(j+2)%3];
if (uNeighbour!=ULONG_MAX && cTopAlg.ShouldSwapEdge(it.Position(), uNeighbour, fMaxSwapAngle)) {
cTopAlg.SwapEdge(it.Position(), uNeighbour);
break;
}
}
}
}
}
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<unsigned long> point;
point.push_back(index);
// get the local neighbourhood of the point
std::set<unsigned long> nb = clPt2Facets.NeighbourPoints(point,1);
const std::set<unsigned long>& faces = clPt2Facets[index];
for (std::set<unsigned long>::iterator pt = nb.begin(); pt != nb.end(); ++pt) {
const MeshPoint& mp = rPntAry[*pt];
for (std::set<unsigned long>::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<unsigned long>& 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<unsigned long> 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<unsigned long> 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++) {
unsigned long n1 = it->_aulNeighbours[i];
unsigned long n2 = it->_aulNeighbours[(i+1)%3];
Base::Vector3f v1 =_rclMesh.GetFacet(*it).GetNormal();
if (n1 != ULONG_MAX && n2 != ULONG_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<unsigned long> 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] != ULONG_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<unsigned long> MeshEvalFoldsOnBoundary::GetIndices() const
{
return this->indices;
}
bool MeshFixFoldsOnBoundary::Fixup()
{
MeshEvalFoldsOnBoundary eval(_rclMesh);
if (!eval.Evaluate()) {
std::vector<unsigned long> 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++) {
unsigned long index1 = f_it->_aulNeighbours[i];
unsigned long index2 = f_it->_aulNeighbours[(i+1)%3];
if (index1 != ULONG_MAX && index2 != ULONG_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++) {
unsigned long 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();
unsigned long 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] < ULONG_MAX)) {
return false;
}
}
}
return true;
}
std::vector<unsigned long> MeshEvalRangeFacet::GetIndices() const
{
std::vector<unsigned long> aInds;
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
unsigned long ulCtFacets = rFaces.size();
unsigned long 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] < ULONG_MAX)) {
aInds.push_back(ind);
break;
}
}
}
return aInds;
}
bool MeshFixRangeFacet::Fixup()
{
_rclMesh.RebuildNeighbours();
return true;
}
// ----------------------------------------------------------------------
bool MeshEvalRangePoint::Evaluate()
{
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
unsigned long ulCtPoints = _rclMesh.CountPoints();
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it) {
if (std::find_if(it->_aulPoints, it->_aulPoints + 3, std::bind2nd(std::greater_equal<unsigned long>(), ulCtPoints)) < it->_aulPoints + 3)
return false;
}
return true;
}
std::vector<unsigned long> MeshEvalRangePoint::GetIndices() const
{
std::vector<unsigned long> aInds;
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
unsigned long ulCtPoints = _rclMesh.CountPoints();
unsigned long ind=0;
for (MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, ind++) {
if (std::find_if(it->_aulPoints, it->_aulPoints + 3, std::bind2nd(std::greater_equal<unsigned long>(), 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<unsigned long> invalid = eval.GetIndices();
if (!invalid.empty()) {
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
for (std::vector<unsigned long>::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->_aulPoints[0] == it->_aulPoints[1]) ||
(it->_aulPoints[1] == it->_aulPoints[2]) ||
(it->_aulPoints[2] == it->_aulPoints[0]))
return false;
}
return true;
}
std::vector<unsigned long> MeshEvalCorruptedFacets::GetIndices() const
{
std::vector<unsigned long> aInds;
const MeshFacetArray& rFaces = _rclMesh.GetFacets();
unsigned long ind=0;
for ( MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it, ind++ ) {
if ((it->_aulPoints[0] == it->_aulPoints[1]) ||
(it->_aulPoints[1] == it->_aulPoints[2]) ||
(it->_aulPoints[2] == it->_aulPoints[0]))
aInds.push_back(ind);
}
return aInds;
}
bool MeshFixCorruptedFacets::Fixup()
{
MeshTopoAlgorithm cTopAlg(_rclMesh);
MeshFacetIterator it(_rclMesh);
for ( it.Init(); it.More(); it.Next() )
{
if ( it->Area() <= FLOAT_EPS )
{
unsigned long uId = it.Position();
cTopAlg.RemoveCorruptedFacet(uId);
// due to a modification of the array the iterator became invalid
it.Set(uId-1);
}
}
return true;
}