From 34b9ff8867cd06f44257bc8b43b51534bbf9572d Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 5 Mar 2016 23:36:57 +0100 Subject: [PATCH] + command to create points object from geometry + implement TopoShape::getPoints --- src/Mod/Part/App/TopoShape.cpp | 112 +++++++++++++++++++++++++++++++++ src/Mod/Part/App/TopoShape.h | 6 +- src/Mod/Points/Gui/Command.cpp | 42 ++++++++++--- 3 files changed, 149 insertions(+), 11 deletions(-) diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index a0c7fc819..65717479b 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -59,6 +59,7 @@ # include # include # include +# include # include # include # include @@ -76,6 +77,8 @@ # include # include # include +# include +# include # include # include # include @@ -86,6 +89,7 @@ # include # include # include +# include # include # include # include @@ -2532,3 +2536,111 @@ void TopoShape::setFaces(const std::vector &Points, if (_Shape.IsNull()) _Shape = aComp; } + +void TopoShape::getPoints(std::vector &Points, + std::vector &Normals, + float Accuracy, uint16_t flags) const +{ + if (_Shape.IsNull()) + return; + + const int minPointsPerEdge = 30; + const double lateralDistance = Accuracy; + + // get all 3d points from free vertices + for (TopExp_Explorer xp(_Shape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { + gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current())); + Points.push_back(Base::convertTo(p)); + Normals.push_back(Base::Vector3d(0,0,0)); + } + + // sample inner points of all free edges + for (TopExp_Explorer xp(_Shape, TopAbs_EDGE, TopAbs_FACE); xp.More(); xp.Next()) { + BRepAdaptor_Curve curve(TopoDS::Edge(xp.Current())); + GCPnts_UniformAbscissa discretizer(curve, lateralDistance, curve.FirstParameter(), curve.LastParameter()); + if (discretizer.IsDone () && discretizer.NbPoints () > 0) { + int nbPoints = discretizer.NbPoints(); + for (int i=1; i<=nbPoints; i++) { + gp_Pnt p = curve.Value (discretizer.Parameter(i)); + Points.push_back(Base::convertTo(p)); + Normals.push_back(Base::Vector3d(0,0,0)); + } + } + } + + // sample inner points of all faces + BRepClass_FaceClassifier classifier; + bool hasFaces = false; + for (TopExp_Explorer xp(_Shape, TopAbs_FACE); xp.More(); xp.Next()) { + hasFaces = true; + int pointsPerEdge = minPointsPerEdge; + TopoDS_Face face = TopoDS::Face(xp.Current()); + BRepAdaptor_Surface surface(face); + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(face); + + // parameter ranges + Standard_Real uFirst = surface.FirstUParameter(); + Standard_Real uLast = surface.LastUParameter(); + Standard_Real vFirst = surface.FirstVParameter(); + Standard_Real vLast = surface.LastVParameter(); + + // get geometrical length and width of the surface + // + gp_Pnt p1, p2; + Standard_Real fLengthU = 0.0, fLengthV = 0.0; + for (int i = 1; i <= pointsPerEdge; i++) { + double u1 = static_cast(i-1)/static_cast(pointsPerEdge); + double s1 = (1.0-u1)*uFirst + u1*uLast; + p1 = surface.Value(s1,0.0); + + double u2 = static_cast(i)/static_cast(pointsPerEdge); + double s2 = (1.0-u2)*uFirst + u2*uLast; + p2 = surface.Value(s2,0.0); + + fLengthU += p1.Distance(p2); + } + + for (int i = 1; i <= pointsPerEdge; i++) { + double v1 = static_cast(i-1)/static_cast(pointsPerEdge); + double t1 = (1.0-v1)*vFirst + v1*vLast; + p1 = surface.Value(0.0,t1); + + double v2 = static_cast(i)/static_cast(pointsPerEdge); + double t2 = (1.0-v2)*vFirst + v2*vLast; + p2 = surface.Value(0.0,t2); + + fLengthV += p1.Distance(p2); + } + + int uPointsPerEdge = static_cast(fLengthU / lateralDistance); + int vPointsPerEdge = static_cast(fLengthV / lateralDistance); + + for (int i = 0; i <= uPointsPerEdge; i++) { + double u = static_cast(i)/static_cast(uPointsPerEdge); + double s = (1.0-u)*uFirst + u*uLast; + + for (int j = 0; j <= vPointsPerEdge; j++) { + double v = static_cast(j)/static_cast(vPointsPerEdge); + double t = (1.0-v)*vFirst + v*vLast; + + gp_Pnt2d p2d(s,t); + classifier.Perform(face,p2d,1.0e-4); + if (classifier.State() == TopAbs_IN || classifier.State() == TopAbs_ON) { + gp_Pnt p = surface.Value(s,t); + Points.push_back(Base::convertTo(p)); + gp_Dir normal; + if (GeomLib::NormEstim(aSurf, p2d, Precision::Confusion(), normal) <= 1) { + Normals.push_back(Base::convertTo(normal)); + } + else { + Normals.push_back(Base::Vector3d(0,0,0)); + } + } + } + } + } + + // if no faces are found then the normals can be cleared + if (!hasFaces) + Normals.clear(); +} diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index fe291350e..74b3ad359 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -200,7 +200,11 @@ public: /** @name Getting basic geometric entities */ //@{ - void getFaces(std::vector &Points,std::vector &faces, + /** Get points from object with given accuracy */ + virtual void getPoints(std::vector &Points, + std::vector &Normals, + float Accuracy, uint16_t flags=0) const; + virtual void getFaces(std::vector &Points,std::vector &faces, float Accuracy, uint16_t flags=0) const; void setFaces(const std::vector &Points, const std::vector &faces, float Accuracy=1.0e-06); diff --git a/src/Mod/Points/Gui/Command.cpp b/src/Mod/Points/Gui/Command.cpp index 34d5bf575..27cd79a05 100644 --- a/src/Mod/Points/Gui/Command.cpp +++ b/src/Mod/Points/Gui/Command.cpp @@ -24,9 +24,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include -# include -# include -# include +# include +# include # include #endif @@ -42,6 +41,7 @@ #include #include #include +#include #include "../App/PointsFeature.h" #include "../App/Properties.h" @@ -182,7 +182,7 @@ CmdPointsConvert::CmdPointsConvert() { sAppModule = "Points"; sGroup = QT_TR_NOOP("Points"); - sMenuText = QT_TR_NOOP("Convert to points"); + sMenuText = QT_TR_NOOP("Convert to points..."); sToolTipText = QT_TR_NOOP("Convert to points"); sWhatsThis = QT_TR_NOOP("Convert to points"); sStatusTip = QT_TR_NOOP("Convert to points"); @@ -190,15 +190,32 @@ CmdPointsConvert::CmdPointsConvert() void CmdPointsConvert::activated(int iMsg) { + bool ok; + double tol = QInputDialog::getDouble(Gui::getMainWindow(), QObject::tr("Distance"), + QObject::tr("Enter maximum distance:"), 0.1, 0.05, 10.0, 2, &ok); + if (!ok) + return; + + Gui::WaitCursor wc; openCommand("Convert to points"); - std::vector meshes = getSelection().getObjectsOfType(Base::Type::fromName("Mesh::Feature")); - for (std::vector::iterator it = meshes.begin(); it != meshes.end(); ++it) { - App::PropertyComplexGeoData* prop = dynamic_cast((*it)->getPropertyByName("Mesh")); + std::vector geoObject = getSelection().getObjectsOfType(Base::Type::fromName("App::GeoFeature")); + + bool addedPoints = false; + for (std::vector::iterator it = geoObject.begin(); it != geoObject.end(); ++it) { + App::PropertyComplexGeoData* prop = 0; + + // a cad shape? + if ((*it)->isDerivedFrom(Base::Type::fromName("Part::Feature"))) + prop = dynamic_cast((*it)->getPropertyByName("Shape")); + // a mesh? + else if ((*it)->isDerivedFrom(Base::Type::fromName("Mesh::Feature"))) + prop = dynamic_cast((*it)->getPropertyByName("Mesh")); + if (prop) { const Data::ComplexGeoData* data = prop->getComplexData(); std::vector vertexes; std::vector normals; - data->getPoints(vertexes, normals, 0.0f); + data->getPoints(vertexes, normals, static_cast(tol)); if (!vertexes.empty()) { Points::Feature* fea = 0; if (vertexes.size() == normals.size()) { @@ -228,15 +245,20 @@ void CmdPointsConvert::activated(int iMsg) App::Document* doc = (*it)->getDocument(); doc->addObject(fea, "Points"); + addedPoints = true; } } } - commitCommand(); + + if (addedPoints) + commitCommand(); + else + abortCommand(); } bool CmdPointsConvert::isActive(void) { - return getSelection().countObjectsOfType(Base::Type::fromName("Mesh::Feature")) > 0; + return getSelection().countObjectsOfType(Base::Type::fromName("App::GeoFeature")) > 0; } DEF_STD_CMD_A(CmdPointsPolyCut);