diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index 828a6675a..18847d664 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -1538,7 +1538,6 @@ bool MeshAlgorithm::ConnectLines (std::listindices.clear(); MeshRefPointToFacets clPt2Facets(_rclMesh); @@ -749,14 +749,25 @@ bool MeshEvalFoldsOnSurface::Evaluate() return this->indices.empty(); } -std::vector MeshEvalFoldsOnSurface::GetIndices() const +std::vector MeshEvalDentsOnSurface::GetIndices() const { return this->indices; } -bool MeshFixFoldsOnSurface::Fixup() +/* +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() { - MeshEvalFoldsOnSurface eval(_rclMesh); + MeshEvalDentsOnSurface eval(_rclMesh); if (!eval.Evaluate()) { std::vector inds = eval.GetIndices(); _rclMesh.DeleteFacets(inds); @@ -767,6 +778,44 @@ bool MeshFixFoldsOnSurface::Fixup() // ---------------------------------------------------------------------- +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 MeshEvalFoldsOnSurface::GetIndices() const +{ + return this->indices; +} + +// ---------------------------------------------------------------------- + bool MeshEvalFoldsOnBoundary::Evaluate() { // remove all boundary facets with two open edges and where diff --git a/src/Mod/Mesh/App/Core/Degeneration.h b/src/Mod/Mesh/App/Core/Degeneration.h index db6c3d010..e5a4f7fdd 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.h +++ b/src/Mod/Mesh/App/Core/Degeneration.h @@ -380,6 +380,37 @@ private: float fMaxAngle; }; +/** + * If an adjacent point (A) of a point (P) can be projected onto a triangle shared + * by (P) but not by (A) then we have a local dent. The topology is not affected. + */ +class MeshExport MeshEvalDentsOnSurface : public MeshEvaluation +{ +public: + MeshEvalDentsOnSurface (const MeshKernel &rclM) : MeshEvaluation( rclM ) { } + ~MeshEvalDentsOnSurface() {} + + bool Evaluate(); + std::vector GetIndices() const; + +private: + std::vector indices; +}; + +class MeshExport MeshFixDentsOnSurface : public MeshValidation +{ +public: + MeshFixDentsOnSurface (MeshKernel &rclM) : MeshValidation( rclM ) { } + ~MeshFixDentsOnSurface() {} + + bool Fixup(); +}; + +/** + * If the angle between the adjacent triangles of a triangle is lower then 90 deg + * but the angles between both of these adjacent triangles is higher than 90 deg + * we have a fold. The topology is not affected but the geometry is broken. + */ class MeshExport MeshEvalFoldsOnSurface : public MeshEvaluation { public: @@ -393,15 +424,12 @@ private: std::vector indices; }; -class MeshExport MeshFixFoldsOnSurface : public MeshValidation -{ -public: - MeshFixFoldsOnSurface (MeshKernel &rclM) : MeshValidation( rclM ) { } - ~MeshFixFoldsOnSurface() {} - - bool Fixup(); -}; - +/** + * Considers a boundary triangle with two open edges and an angle higher than + * 60 deg with its adjacent triangle as a boundary fold. + * The topology is not affected there but such triangles can lead to problems + * on some hole-filling algorithms. + */ class MeshExport MeshEvalFoldsOnBoundary : public MeshEvaluation { public: @@ -424,6 +452,10 @@ public: bool Fixup(); }; +/** + * Considers two adjacent triangles with an angle higher than 120 deg of their + * normals as a fold-over. The topology is not affected there. + */ class MeshExport MeshEvalFoldOversOnSurface : public MeshEvaluation { public: diff --git a/src/Mod/Mesh/App/Core/Evaluation.cpp b/src/Mod/Mesh/App/Core/Evaluation.cpp index 32508476d..45d6753a8 100644 --- a/src/Mod/Mesh/App/Core/Evaluation.cpp +++ b/src/Mod/Mesh/App/Core/Evaluation.cpp @@ -411,27 +411,26 @@ unsigned long MeshEvalTopology::CountManifolds() const bool MeshFixTopology::Fixup () { - std::vector indices; #if 0 MeshEvalTopology eval(_rclMesh); if (!eval.Evaluate()) { - eval.GetFacetManifolds(indices); + eval.GetFacetManifolds(deletedFaces); // remove duplicates - std::sort(indices.begin(), indices.end()); - indices.erase(std::unique(indices.begin(), indices.end()), indices.end()); + std::sort(deletedFaces.begin(), deletedFaces.end()); + deletedFaces.erase(std::unique(deletedFaces.begin(), deletedFaces.end()), deletedFaces.end()); - _rclMesh.DeleteFacets(indices); + _rclMesh.DeleteFacets(deletedFaces); } #else const MeshFacetArray& rFaces = _rclMesh.GetFacets(); - indices.reserve(3 * nonManifoldList.size()); // allocate some memory + deletedFaces.reserve(3 * nonManifoldList.size()); // allocate some memory std::list >::const_iterator it; for (it = nonManifoldList.begin(); it != nonManifoldList.end(); ++it) { std::vector non_mf; non_mf.reserve(it->size()); for (std::vector::const_iterator jt = it->begin(); jt != it->end(); ++jt) { - // fscet is only connected with one edge and there causes a non-manifold + // facet is only connected with one edge and there causes a non-manifold unsigned short numOpenEdges = rFaces[*jt].CountOpenEdges(); if (numOpenEdges == 2) non_mf.push_back(*jt); @@ -441,17 +440,17 @@ bool MeshFixTopology::Fixup () // are we able to repair the non-manifold edge by not removing all facets? if (it->size() - non_mf.size() == 2) - indices.insert(indices.end(), non_mf.begin(), non_mf.end()); + deletedFaces.insert(deletedFaces.end(), non_mf.begin(), non_mf.end()); else - indices.insert(indices.end(), it->begin(), it->end()); + deletedFaces.insert(deletedFaces.end(), it->begin(), it->end()); } - if (!indices.empty()) { + if (!deletedFaces.empty()) { // remove duplicates - std::sort(indices.begin(), indices.end()); - indices.erase(std::unique(indices.begin(), indices.end()), indices.end()); + std::sort(deletedFaces.begin(), deletedFaces.end()); + deletedFaces.erase(std::unique(deletedFaces.begin(), deletedFaces.end()), deletedFaces.end()); - _rclMesh.DeleteFacets(indices); + _rclMesh.DeleteFacets(deletedFaces); _rclMesh.RebuildNeighbours(); } #endif @@ -461,6 +460,53 @@ bool MeshFixTopology::Fixup () // --------------------------------------------------------- +bool MeshEvalPointManifolds::Evaluate () +{ + this->nonManifoldPoints.clear(); + this->facetsOfNonManifoldPoints.clear(); + + MeshCore::MeshRefPointToPoints vv_it(_rclMesh); + MeshCore::MeshRefPointToFacets vf_it(_rclMesh); + + unsigned long ctPoints = _rclMesh.CountPoints(); + for (unsigned long index=0; index < ctPoints; index++) { + // get the local neighbourhood of the point + const std::set& nf = vf_it[index]; + const std::set& np = vv_it[index]; + + std::set::size_type sp, sf; + sp = np.size(); + sf = nf.size(); + // for an inner point the number of adjacent points is equal to the number of shared faces + // for a boundary point the number of adjacent points is higher by one than the number of shared faces + // for a non-manifold point the number of adjacent points is higher by more than one than the number of shared faces + if (sp > sf + 1) { + nonManifoldPoints.push_back(index); + std::vector faces; + faces.insert(faces.end(), nf.begin(), nf.end()); + this->facetsOfNonManifoldPoints.push_back(faces); + } + } + + return this->nonManifoldPoints.empty(); +} + +void MeshEvalPointManifolds::GetFacetIndices (std::vector &facets) const +{ + std::list >::const_iterator it; + for (it = facetsOfNonManifoldPoints.begin(); it != facetsOfNonManifoldPoints.end(); ++it) { + facets.insert(facets.end(), it->begin(), it->end()); + } + + if (!facets.empty()) { + // remove duplicates + std::sort(facets.begin(), facets.end()); + facets.erase(std::unique(facets.begin(), facets.end()), facets.end()); + } +} + +// --------------------------------------------------------- + bool MeshEvalSingleFacet::Evaluate () { // get all non-manifolds diff --git a/src/Mod/Mesh/App/Core/Evaluation.h b/src/Mod/Mesh/App/Core/Evaluation.h index 902628841..cde501e64 100644 --- a/src/Mod/Mesh/App/Core/Evaluation.h +++ b/src/Mod/Mesh/App/Core/Evaluation.h @@ -214,12 +214,40 @@ public: virtual ~MeshFixTopology () {} bool Fixup(); + const std::vector& GetDeletedFaces() const { return deletedFaces; } + protected: + std::vector deletedFaces; const std::list >& nonManifoldList; }; // ---------------------------------------------------- +/** + * The MeshEvalPointManifolds class checks for non-manifold points. + * A point is considered non-manifold if two sets of triangles share + * the point but are not topologically connected over a common edge. + * Such mesh defects can lead to some very ugly folds on the surface. + */ +class MeshExport MeshEvalPointManifolds : public MeshEvaluation +{ +public: + MeshEvalPointManifolds (const MeshKernel &rclB) : MeshEvaluation(rclB) {} + virtual ~MeshEvalPointManifolds () {} + virtual bool Evaluate (); + + void GetFacetIndices (std::vector &facets) const; + const std::list >& GetFacetIndices () const { return facetsOfNonManifoldPoints; } + const std::vector& GetIndices() const { return nonManifoldPoints; } + unsigned long CountManifolds() const { return nonManifoldPoints.size(); } + +protected: + std::vector nonManifoldPoints; + std::list > facetsOfNonManifoldPoints; +}; + +// ---------------------------------------------------- + /** * The MeshEvalSingleFacet class checks a special case of non-manifold edges as follows. * If an edge is shared by more than two facets and if all further facets causing this non- diff --git a/src/Mod/Mesh/App/Core/Smoothing.cpp b/src/Mod/Mesh/App/Core/Smoothing.cpp index b529f2d98..a84fd1930 100644 --- a/src/Mod/Mesh/App/Core/Smoothing.cpp +++ b/src/Mod/Mesh/App/Core/Smoothing.cpp @@ -50,16 +50,16 @@ void AbstractSmoothing::initialize(Component comp, Continuity cont) this->continuity = cont; } -MeshSmoothing::MeshSmoothing(MeshKernel& m) +PlaneFitSmoothing::PlaneFitSmoothing(MeshKernel& m) : AbstractSmoothing(m) { } -MeshSmoothing::~MeshSmoothing() +PlaneFitSmoothing::~PlaneFitSmoothing() { } -void MeshSmoothing::Smooth(unsigned int iterations) +void PlaneFitSmoothing::Smooth(unsigned int iterations) { MeshCore::MeshPoint center; MeshCore::MeshPointArray PointArray = kernel.GetPoints(); @@ -112,6 +112,60 @@ void MeshSmoothing::Smooth(unsigned int iterations) } } +void PlaneFitSmoothing::SmoothPoints(unsigned int iterations, const std::vector& point_indices) +{ + MeshCore::MeshPoint center; + MeshCore::MeshPointArray PointArray = kernel.GetPoints(); + + MeshCore::MeshPointIterator v_it(kernel); + MeshCore::MeshRefPointToPoints vv_it(kernel); + MeshCore::MeshPointArray::_TConstIterator v_beg = kernel.GetPoints().begin(); + + for (unsigned int i=0; i::const_iterator it = point_indices.begin(); it != point_indices.end(); ++it) { + v_it.Set(*it); + MeshCore::PlaneFit pf; + pf.AddPoint(*v_it); + center = *v_it; + const std::set& cv = vv_it[v_it.Position()]; + if (cv.size() < 3) + continue; + + std::set::const_iterator cv_it; + for (cv_it = cv.begin(); cv_it !=cv.end(); ++cv_it) { + pf.AddPoint(v_beg[*cv_it]); + center += v_beg[*cv_it]; + } + + float scale = 1.0f/((float)cv.size()+1.0f); + center.Scale(scale,scale,scale); + + // get the mean plane of the current vertex with the surrounding vertices + pf.Fit(); + N = pf.GetNormal(); + N.Normalize(); + + // look in which direction we should move the vertex + L.Set(v_it->x - center.x, v_it->y - center.y, v_it->z - center.z); + if (N*L < 0.0) + N.Scale(-1.0, -1.0, -1.0); + + // maximum value to move is distance to mean plane + float d = std::min((float)fabs(this->tolerance),(float)fabs(N*L)); + N.Scale(d,d,d); + + PointArray[v_it.Position()].Set(v_it->x - N.x, v_it->y - N.y, v_it->z - N.z); + } + + // assign values without affecting iterators + unsigned long count = kernel.CountPoints(); + for (unsigned long idx = 0; idx < count; idx++) { + kernel.SetPoint(idx, PointArray[idx]); + } + } +} + LaplaceSmoothing::LaplaceSmoothing(MeshKernel& m) : AbstractSmoothing(m), lambda(0.6307) { @@ -157,6 +211,41 @@ void LaplaceSmoothing::Umbrella(const MeshRefPointToPoints& vv_it, } } +void LaplaceSmoothing::Umbrella(const MeshRefPointToPoints& vv_it, + const MeshRefPointToFacets& vf_it, double stepsize, + const std::vector& point_indices) +{ + const MeshCore::MeshPointArray& points = kernel.GetPoints(); + MeshCore::MeshPointArray::_TConstIterator v_beg = points.begin(); + + for (std::vector::const_iterator pos = point_indices.begin(); pos != point_indices.end(); ++pos) { + const std::set& cv = vv_it[*pos]; + if (cv.size() < 3) + continue; + if (cv.size() != vf_it[*pos].size()) { + // do nothing for border points + continue; + } + + unsigned int n_count = cv.size(); + double w; + w=1.0/double(n_count); + + double delx=0.0,dely=0.0,delz=0.0; + std::set::const_iterator cv_it; + for (cv_it = cv.begin(); cv_it !=cv.end(); ++cv_it) { + delx += w*((v_beg[*cv_it]).x-(v_beg[*pos]).x); + dely += w*((v_beg[*cv_it]).y-(v_beg[*pos]).y); + delz += w*((v_beg[*cv_it]).z-(v_beg[*pos]).z); + } + + float x = (float)((v_beg[*pos]).x+stepsize*delx); + float y = (float)((v_beg[*pos]).y+stepsize*dely); + float z = (float)((v_beg[*pos]).z+stepsize*delz); + kernel.SetPoint(*pos,x,y,z); + } +} + void LaplaceSmoothing::Smooth(unsigned int iterations) { MeshCore::MeshRefPointToPoints vv_it(kernel); @@ -167,6 +256,16 @@ void LaplaceSmoothing::Smooth(unsigned int iterations) } } +void LaplaceSmoothing::SmoothPoints(unsigned int iterations, const std::vector& point_indices) +{ + MeshCore::MeshRefPointToPoints vv_it(kernel); + MeshCore::MeshRefPointToFacets vf_it(kernel); + + for (unsigned int i=0; i& point_indices) +{ + MeshCore::MeshPointArray::_TConstIterator v_it; + MeshCore::MeshRefPointToPoints vv_it(kernel); + MeshCore::MeshRefPointToFacets vf_it(kernel); + + // Theoretically Taubin does not shrink the surface + iterations = (iterations+1)/2; // two steps per iteration + for (unsigned int i=0; i + namespace MeshCore { class MeshKernel; @@ -52,6 +54,7 @@ public: /** Smooth the triangle mesh. */ virtual void Smooth(unsigned int) = 0; + virtual void SmoothPoints(unsigned int, const std::vector&) = 0; protected: MeshKernel& kernel; @@ -61,12 +64,13 @@ protected: Continuity continuity; }; -class MeshExport MeshSmoothing : public AbstractSmoothing +class MeshExport PlaneFitSmoothing : public AbstractSmoothing { public: - MeshSmoothing(MeshKernel&); - virtual ~MeshSmoothing(); + PlaneFitSmoothing(MeshKernel&); + virtual ~PlaneFitSmoothing(); void Smooth(unsigned int); + void SmoothPoints(unsigned int, const std::vector&); }; class MeshExport LaplaceSmoothing : public AbstractSmoothing @@ -75,11 +79,15 @@ public: LaplaceSmoothing(MeshKernel&); virtual ~LaplaceSmoothing(); void Smooth(unsigned int); + void SmoothPoints(unsigned int, const std::vector&); void SetLambda(double l) { lambda = l;} protected: void Umbrella(const MeshRefPointToPoints&, const MeshRefPointToFacets&, double); + void Umbrella(const MeshRefPointToPoints&, + const MeshRefPointToFacets&, double, + const std::vector&); protected: double lambda; @@ -91,6 +99,7 @@ public: TaubinSmoothing(MeshKernel&); virtual ~TaubinSmoothing(); void Smooth(unsigned int); + void SmoothPoints(unsigned int, const std::vector&); void SetMicro(double m) { micro = m;} protected: diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 928c57edd..9a13a27a8 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -1108,15 +1108,18 @@ bool MeshObject::hasNonManifolds() const void MeshObject::removeNonManifolds() { - unsigned long count = _kernel.CountFacets(); - MeshCore::MeshEvalTopology cMeshEval(_kernel); - if (!cMeshEval.Evaluate()) { - MeshCore::MeshFixTopology cMeshFix(_kernel, cMeshEval.GetFacets()); - cMeshFix.Fixup(); + MeshCore::MeshEvalTopology f_eval(_kernel); + if (!f_eval.Evaluate()) { + MeshCore::MeshFixTopology f_fix(_kernel, f_eval.GetFacets()); + f_fix.Fixup(); + deletedFacets(f_fix.GetDeletedFaces()); + } + MeshCore::MeshEvalPointManifolds p_eval(_kernel); + if (!p_eval.Evaluate()) { + std::vector faces; + p_eval.GetFacetIndices(faces); + deleteFacets(faces); } - - if (_kernel.CountFacets() < count) - this->_segments.clear(); } bool MeshObject::hasSelfIntersections() const diff --git a/src/Mod/Mesh/Gui/AppMeshGui.cpp b/src/Mod/Mesh/Gui/AppMeshGui.cpp index e585deb67..a3ff09cc6 100644 --- a/src/Mod/Mesh/Gui/AppMeshGui.cpp +++ b/src/Mod/Mesh/Gui/AppMeshGui.cpp @@ -124,6 +124,7 @@ void MeshGuiExport initMeshGui() MeshGui::ViewProviderMeshDefects ::init(); MeshGui::ViewProviderMeshOrientation ::init(); MeshGui::ViewProviderMeshNonManifolds ::init(); + MeshGui::ViewProviderMeshNonManifoldPoints ::init(); MeshGui::ViewProviderMeshDuplicatedFaces ::init(); MeshGui::ViewProviderMeshDuplicatedPoints ::init(); MeshGui::ViewProviderMeshDegenerations ::init(); diff --git a/src/Mod/Mesh/Gui/DlgEvaluateMeshImp.cpp b/src/Mod/Mesh/Gui/DlgEvaluateMeshImp.cpp index ddcd50ca0..aabb82690 100644 --- a/src/Mod/Mesh/Gui/DlgEvaluateMeshImp.cpp +++ b/src/Mod/Mesh/Gui/DlgEvaluateMeshImp.cpp @@ -478,29 +478,37 @@ void DlgEvaluateMeshImp::on_analyzeNonmanifoldsButton_clicked() qApp->setOverrideCursor(Qt::WaitCursor); const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel(); - MeshEvalTopology eval(rMesh); + MeshEvalTopology f_eval(rMesh); + MeshEvalPointManifolds p_eval(rMesh); + bool ok1 = f_eval.Evaluate(); + bool ok2 = p_eval.Evaluate(); - if (eval.Evaluate()) { + if (ok1 && ok2) { checkNonmanifoldsButton->setText(tr("No non-manifolds")); checkNonmanifoldsButton->setChecked(false); repairNonmanifoldsButton->setEnabled(false); removeViewProvider("MeshGui::ViewProviderMeshNonManifolds"); } else { - checkNonmanifoldsButton->setText(tr("%1 non-manifolds").arg(eval.CountManifolds())); + checkNonmanifoldsButton->setText(tr("%1 non-manifolds").arg(f_eval.CountManifolds()+p_eval.CountManifolds())); checkNonmanifoldsButton->setChecked(true); repairNonmanifoldsButton->setEnabled(true); repairAllTogether->setEnabled(true); - const std::vector >& inds = eval.GetIndices(); - std::vector indices; - indices.reserve(2*inds.size()); - std::vector >::const_iterator it; - for (it = inds.begin(); it != inds.end(); ++it) { - indices.push_back(it->first); - indices.push_back(it->second); - } + if (!ok1) { + const std::vector >& inds = f_eval.GetIndices(); + std::vector indices; + indices.reserve(2*inds.size()); + std::vector >::const_iterator it; + for (it = inds.begin(); it != inds.end(); ++it) { + indices.push_back(it->first); + indices.push_back(it->second); + } - addViewProvider("MeshGui::ViewProviderMeshNonManifolds", indices); + addViewProvider("MeshGui::ViewProviderMeshNonManifolds", indices); + } + if (!ok2) { + addViewProvider("MeshGui::ViewProviderMeshNonManifoldPoints", p_eval.GetIndices()); + } } qApp->restoreOverrideCursor(); @@ -1124,9 +1132,9 @@ void DlgEvaluateMeshImp::on_repairAllTogether_clicked() } // ------------------------------------------------------------- - -/* TRANSLATOR MeshGui::DockEvaluateMeshImp */ +/* TRANSLATOR MeshGui::DockEvaluateMeshImp */ + #if 0 // needed for Qt's lupdate utility qApp->translate("QDockWidget", "Evaluate & Repair Mesh"); #endif diff --git a/src/Mod/Mesh/Gui/ViewProviderDefects.cpp b/src/Mod/Mesh/Gui/ViewProviderDefects.cpp index f8d85de36..7931f1b5f 100644 --- a/src/Mod/Mesh/Gui/ViewProviderDefects.cpp +++ b/src/Mod/Mesh/Gui/ViewProviderDefects.cpp @@ -59,6 +59,7 @@ using namespace MeshGui; PROPERTY_SOURCE_ABSTRACT(MeshGui::ViewProviderMeshDefects, Gui::ViewProviderDocumentObject) PROPERTY_SOURCE(MeshGui::ViewProviderMeshOrientation, MeshGui::ViewProviderMeshDefects) PROPERTY_SOURCE(MeshGui::ViewProviderMeshNonManifolds, MeshGui::ViewProviderMeshDefects) +PROPERTY_SOURCE(MeshGui::ViewProviderMeshNonManifoldPoints, MeshGui::ViewProviderMeshDefects) PROPERTY_SOURCE(MeshGui::ViewProviderMeshDuplicatedFaces, MeshGui::ViewProviderMeshDefects) PROPERTY_SOURCE(MeshGui::ViewProviderMeshDuplicatedPoints, MeshGui::ViewProviderMeshDefects) PROPERTY_SOURCE(MeshGui::ViewProviderMeshDegenerations, MeshGui::ViewProviderMeshDefects) @@ -234,6 +235,63 @@ void ViewProviderMeshNonManifolds::showDefects(const std::vector& // ---------------------------------------------------------------------- +ViewProviderMeshNonManifoldPoints::ViewProviderMeshNonManifoldPoints() +{ + pcPoints = new SoPointSet; + pcPoints->ref(); +} + +ViewProviderMeshNonManifoldPoints::~ViewProviderMeshNonManifoldPoints() +{ + pcPoints->unref(); +} + +void ViewProviderMeshNonManifoldPoints::attach(App::DocumentObject* pcFeat) +{ + ViewProviderDocumentObject::attach( pcFeat ); + + SoGroup* pcPointRoot = new SoGroup(); + pcDrawStyle->pointSize = 3; + pcPointRoot->addChild(pcDrawStyle); + + // Draw points + SoSeparator* pointsep = new SoSeparator; + SoBaseColor * basecol = new SoBaseColor; + basecol->rgb.setValue( 1.0f, 0.5f, 0.0f ); + pointsep->addChild(basecol); + pointsep->addChild(pcCoords); + pointsep->addChild(pcPoints); + pcPointRoot->addChild(pointsep); + + // Draw markers + SoBaseColor * markcol = new SoBaseColor; + markcol->rgb.setValue( 1.0f, 1.0f, 0.0f ); + SoMarkerSet* marker = new SoMarkerSet; + marker->markerIndex=SoMarkerSet::PLUS_7_7; + pointsep->addChild(markcol); + pointsep->addChild(marker); + + addDisplayMaskMode(pcPointRoot, "Point"); +} + +void ViewProviderMeshNonManifoldPoints::showDefects(const std::vector& inds) +{ + Mesh::Feature* f = dynamic_cast(pcObject); + const MeshCore::MeshKernel & rMesh = f->Mesh.getValue().getKernel(); + pcCoords->point.deleteValues(0); + pcCoords->point.setNum(inds.size()); + MeshCore::MeshPointIterator cP(rMesh); + unsigned long i = 0; + for ( std::vector::const_iterator it = inds.begin(); it != inds.end(); ++it ) { + cP.Set(*it); + pcCoords->point.set1Value(i++,cP->x,cP->y,cP->z); + } + + setDisplayMaskMode("Point"); +} + +// ---------------------------------------------------------------------- + ViewProviderMeshDuplicatedFaces::ViewProviderMeshDuplicatedFaces() { pcFaces = new SoFaceSet; diff --git a/src/Mod/Mesh/Gui/ViewProviderDefects.h b/src/Mod/Mesh/Gui/ViewProviderDefects.h index ad45847ed..d9815a8f2 100644 --- a/src/Mod/Mesh/Gui/ViewProviderDefects.h +++ b/src/Mod/Mesh/Gui/ViewProviderDefects.h @@ -96,6 +96,24 @@ protected: SoLineSet* pcLines; }; +/** The ViewProviderMeshNonManifoldPoints class displays non-manifold vertexes in red. + * @author Werner Mayer + */ +class MeshGuiExport ViewProviderMeshNonManifoldPoints : public ViewProviderMeshDefects +{ + PROPERTY_HEADER(MeshGui::ViewProviderMeshNonManifoldPoints); + +public: + ViewProviderMeshNonManifoldPoints(); + virtual ~ViewProviderMeshNonManifoldPoints(); + + void attach(App::DocumentObject* pcFeature); + void showDefects(const std::vector&); + +protected: + SoPointSet* pcPoints; +}; + /** The ViewProviderMeshDuplicatedFaces class displays duplicated faces in red. * @author Werner Mayer */ diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index 4767cbca3..c34b8d539 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -195,6 +195,28 @@ int TopoShapeFacePy::PyInit(PyObject* args, PyObject* /*kwd*/) if (!wires.empty()) { BRepBuilderAPI_MakeFace mkFace(wires.front()); + if (!mkFace.IsDone()) { + switch (mkFace.Error()) { + case BRepBuilderAPI_NoFace: + Standard_Failure::Raise("No face"); + break; + case BRepBuilderAPI_NotPlanar: + Standard_Failure::Raise("Not planar"); + break; + case BRepBuilderAPI_CurveProjectionFailed: + Standard_Failure::Raise("Curve projection failed"); + break; + case BRepBuilderAPI_ParametersOutOfRange: + Standard_Failure::Raise("Parameters out of range"); + break; + case BRepBuilderAPI_SurfaceNotC2: + Standard_Failure::Raise("Surface not C2"); + break; + default: + Standard_Failure::Raise("Unknown failure"); + break; + } + } for (std::vector::iterator it = wires.begin()+1; it != wires.end(); ++it) mkFace.Add(*it); getTopoShapePtr()->_Shape = mkFace.Face();