From 62fb18b24aa4ec18f5d011b1f5127ae490a59e09 Mon Sep 17 00:00:00 2001 From: jgv Date: Fri, 8 Jul 2022 10:59:45 +0300 Subject: [PATCH] [bos #29470][EDF](2022-T1) Advanced geometry features: cloud point on a face --- src/FeaturesAPI/CMakeLists.txt | 2 + src/FeaturesAPI/FeaturesAPI.i | 2 + .../FeaturesAPI_PointCloudOnFace.cpp | 84 +++ .../FeaturesAPI_PointCloudOnFace.h | 83 +++ src/FeaturesAPI/FeaturesAPI_swig.h | 1 + src/FeaturesPlugin/CMakeLists.txt | 2 + src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp | 3 + .../FeaturesPlugin_PointCloudOnFace.cpp | 84 +++ .../FeaturesPlugin_PointCloudOnFace.h | 77 ++ src/FeaturesPlugin/Test/TestPointCloud.py | 56 ++ src/FeaturesPlugin/plugin-Features.xml | 10 + src/FeaturesPlugin/tests.set | 1 + src/GeomAlgoAPI/CMakeLists.txt | 2 + .../GeomAlgoAPI_PointCloudOnFace.cpp | 672 ++++++++++++++++++ .../GeomAlgoAPI_PointCloudOnFace.h | 44 ++ src/PythonAPI/model/features/__init__.py | 1 + 16 files changed, 1124 insertions(+) create mode 100644 src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.cpp create mode 100644 src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.h create mode 100644 src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.h create mode 100644 src/FeaturesPlugin/Test/TestPointCloud.py create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_PointCloudOnFace.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_PointCloudOnFace.h diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 2d641033f..5ced6f8c9 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -38,6 +38,7 @@ SET(PROJECT_HEADERS FeaturesAPI_Partition.h FeaturesAPI_Pipe.h FeaturesAPI_Placement.h + FeaturesAPI_PointCloudOnFace.h FeaturesAPI_Recover.h FeaturesAPI_RemoveResults.h FeaturesAPI_RemoveSubShapes.h @@ -75,6 +76,7 @@ SET(PROJECT_SOURCES FeaturesAPI_Partition.cpp FeaturesAPI_Pipe.cpp FeaturesAPI_Placement.cpp + FeaturesAPI_PointCloudOnFace.cpp FeaturesAPI_Recover.cpp FeaturesAPI_RemoveResults.cpp FeaturesAPI_RemoveSubShapes.cpp diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index d2b6dbfce..d9d5367b8 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -77,6 +77,7 @@ %shared_ptr(FeaturesAPI_Partition) %shared_ptr(FeaturesAPI_Pipe) %shared_ptr(FeaturesAPI_Placement) +%shared_ptr(FeaturesAPI_PointCloudOnFace) %shared_ptr(FeaturesAPI_Recover) %shared_ptr(FeaturesAPI_RemoveSubShapes) %shared_ptr(FeaturesAPI_Revolution) @@ -219,6 +220,7 @@ %include "FeaturesAPI_Partition.h" %include "FeaturesAPI_Pipe.h" %include "FeaturesAPI_Placement.h" +%include "FeaturesAPI_PointCloudOnFace.h" %include "FeaturesAPI_Recover.h" %include "FeaturesAPI_RemoveSubShapes.h" %include "FeaturesAPI_Revolution.h" diff --git a/src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.cpp b/src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.cpp new file mode 100644 index 000000000..da7ae7ce1 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FeaturesAPI_PointCloudOnFace.h" + +#include +#include +#include + +//================================================================================================= +FeaturesAPI_PointCloudOnFace::FeaturesAPI_PointCloudOnFace(const std::shared_ptr& theFeature) + : ModelHighAPI_Interface(theFeature) +{ + initialize(); +} + +//================================================================================================= +FeaturesAPI_PointCloudOnFace::FeaturesAPI_PointCloudOnFace( + const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theFace, + const ModelHighAPI_Integer& theNumber) +:ModelHighAPI_Interface(theFeature) +{ + if (initialize()) { + fillAttribute(theFace, myfaceSelected); + setNumberOfPoints(theNumber); + } +} + + +//================================================================================================= +FeaturesAPI_PointCloudOnFace::~FeaturesAPI_PointCloudOnFace() +{ +} + +//================================================================================================== +void FeaturesAPI_PointCloudOnFace::setNumberOfPoints(const ModelHighAPI_Integer& theNumber) +{ + fillAttribute(theNumber, nbPoints()); + + execute(); +} + +//================================================================================================= +void FeaturesAPI_PointCloudOnFace::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionPtr anAttrObject = + aBase->selection(FeaturesPlugin_PointCloudOnFace::FACE_SELECTED_ID()); + int aNbPnts = aBase->integer(FeaturesPlugin_PointCloudOnFace::NUMBER_ID())->value(); + + theDumper << aBase << " = model.makeVertexInsideFace(" << aDocName + << ", " << anAttrObject << ", " << aNbPnts << ")" << std::endl; +} + +//================================================================================================== +PointCloudPtr makeVertexInsideFace(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theFace, + const ModelHighAPI_Integer& theNumber) +{ + FeaturePtr aFeature = thePart->addFeature(FeaturesPlugin_PointCloudOnFace::ID()); + PointCloudPtr aPointCloud; + aPointCloud.reset(new FeaturesAPI_PointCloudOnFace(aFeature, theFace, theNumber)); + + return aPointCloud; +} diff --git a/src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.h b/src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.h new file mode 100644 index 000000000..323a7512a --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_PointCloudOnFace.h @@ -0,0 +1,83 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FeaturesAPI_PointCloudOnFace_H_ +#define FeaturesAPI_PointCloudOnFace_H_ + +#include "FeaturesAPI.h" + +#include + +#include +#include +#include + + +class ModelHighAPI_Selection; + +/// \class FeaturesAPI_PointCloudOnFace +/// \ingroup CPPHighAPI +/// \brief Interface for PointCloudOnFace feature. +class FeaturesAPI_PointCloudOnFace: public ModelHighAPI_Interface +{ +public: + /// Constructor without values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_PointCloudOnFace(const std::shared_ptr& theFeature); + + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_PointCloudOnFace(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theFace, + const ModelHighAPI_Integer& theNumber); + + /// Destructor. + FEATURESAPI_EXPORT + virtual ~FeaturesAPI_PointCloudOnFace(); + + INTERFACE_2(FeaturesPlugin_PointCloudOnFace::ID(), + faceSelected, FeaturesPlugin_PointCloudOnFace::FACE_SELECTED_ID(), + ModelAPI_AttributeSelection, /** face */, + nbPoints, FeaturesPlugin_PointCloudOnFace::NUMBER_ID(), + ModelAPI_AttributeInteger, /** Number of points */) + + /// Modify CreationMethod, nb_points attribute of the feature. + FEATURESAPI_EXPORT + void setNumberOfPoints(const ModelHighAPI_Integer& theNumber); + + /// Dump wrapped feature + FEATURESAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + +}; + +/// Pointer on the PointCloudOnFace object. +typedef std::shared_ptr PointCloudPtr; + +/// \ingroup CPPHighAPI +/// \brief Create point cloud on a face feature +/// \param thePart the part +/// \param theFace the selected face +/// \param theNumberOfPoints the selected point +FEATURESAPI_EXPORT +PointCloudPtr makeVertexInsideFace(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theFace, + const ModelHighAPI_Integer& theNumber); + +#endif // FeaturesAPI_PointCloudOnFace_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index 066aa098f..a761ff93a 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -41,6 +41,7 @@ #include "FeaturesAPI_Partition.h" #include "FeaturesAPI_Pipe.h" #include "FeaturesAPI_Placement.h" + #include "FeaturesAPI_PointCloudOnFace.h" #include "FeaturesAPI_Recover.h" #include "FeaturesAPI_RemoveSubShapes.h" #include "FeaturesAPI_Revolution.h" diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index 1d031c8ce..4f2148191 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -40,6 +40,7 @@ SET(PROJECT_HEADERS FeaturesPlugin_Partition.h FeaturesPlugin_Pipe.h FeaturesPlugin_Placement.h + FeaturesPlugin_PointCloudOnFace.h FeaturesPlugin_CompositeBoolean.h FeaturesPlugin_CompositeSketch.h FeaturesPlugin_ExtrusionBoolean.h @@ -94,6 +95,7 @@ SET(PROJECT_SOURCES FeaturesPlugin_Partition.cpp FeaturesPlugin_Pipe.cpp FeaturesPlugin_Placement.cpp + FeaturesPlugin_PointCloudOnFace.cpp FeaturesPlugin_CompositeBoolean.cpp FeaturesPlugin_CompositeSketch.cpp FeaturesPlugin_ExtrusionBoolean.cpp diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 795bc77b5..24442767f 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -215,6 +216,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new FeaturesPlugin_InspectNormalToFace); } else if (theFeatureID == FeaturesPlugin_NormalToFace::ID()) { return FeaturePtr(new FeaturesPlugin_NormalToFace); + } else if (theFeatureID == FeaturesPlugin_PointCloudOnFace::ID()) { + return FeaturePtr(new FeaturesPlugin_PointCloudOnFace); } diff --git a/src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.cpp b/src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.cpp new file mode 100644 index 000000000..e9a6c64c1 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FeaturesPlugin_PointCloudOnFace.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//================================================================================================= +FeaturesPlugin_PointCloudOnFace::FeaturesPlugin_PointCloudOnFace() +{ +} + +//================================================================================================= +void FeaturesPlugin_PointCloudOnFace::initAttributes() +{ + // attribute for object selected + data()->addAttribute(FACE_SELECTED_ID(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(NUMBER_ID(), ModelAPI_AttributeInteger::typeId()); +} + +//================================================================================================= +void FeaturesPlugin_PointCloudOnFace::attributeChanged(const std::string& /*theID*/) +{ +} + +//================================================================================================= +void FeaturesPlugin_PointCloudOnFace::execute() +{ + + AttributeSelectionPtr aSelectionFace = selection(FACE_SELECTED_ID()); + + GeomShapePtr aShape; + + if (aSelectionFace && aSelectionFace->isInitialized()) { + aShape = aSelectionFace->value(); + if (!aShape && aSelectionFace->context()) + aShape = aSelectionFace->context()->shape(); + } + + // Getting number of points + int aNbPnts = integer(FeaturesPlugin_PointCloudOnFace::NUMBER_ID())->value(); + + if (aShape && aNbPnts >= 2) { + std::string aError; + std::shared_ptr aPoints(new GeomAPI_Shape); + if (!GeomAlgoAPI_PointCloudOnFace::PointCloud(aShape, + aNbPnts, + aPoints, + aError)) + setError("Error in points calculation :" + aError); + + ResultConstructionPtr aConstr = document()->createConstruction(data()); + aConstr->setInfinite(true); + aConstr->setShape(aPoints); + setResult(aConstr); + } +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.h b/src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.h new file mode 100644 index 000000000..83d1b849e --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_PointCloudOnFace.h @@ -0,0 +1,77 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FeaturesPlugin_PointCloudOnFace_H_ +#define FeaturesPlugin_PointCloudOnFace_H_ + +#include "FeaturesPlugin.h" +#include + +#include +#include + +/// \class FeaturesPlugin_PointCloudOnFace +/// \ingroup Plugins +/// \brief Persistence feature to construct normal to face +class FeaturesPlugin_PointCloudOnFace : public ModelAPI_Feature +{ +public: + /// Point Cloud on face kind. + inline static const std::string& ID() + { + static const std::string MY_ID("Point_cloud"); + return MY_ID; + } + + /// Attribute name for face selected. + inline static const std::string& FACE_SELECTED_ID() + { + static const std::string MY_FACE_ID("face"); + return MY_FACE_ID; + } + + /// \return the kind of a feature. + virtual const std::string& getKind() + { + return ID(); + } + + /// Attribute name of number of points in the point cloud. + inline static const std::string& NUMBER_ID() + { + static const std::string MY_NUMBER_OF_POINTS_ID("number_of_points"); + return MY_NUMBER_OF_POINTS_ID; + } + + /// Performs the algorithm and stores results it in the data structure. + FEATURESPLUGIN_EXPORT virtual void execute(); + + /// Request for initialization of data model of the feature: adding all attributes + FEATURESPLUGIN_EXPORT virtual void initAttributes(); + + /// Called on change of any argument-attribute of this object + /// \param theID identifier of changed attribute + FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Use plugin manager for features creation + FeaturesPlugin_PointCloudOnFace(); + +}; + +#endif diff --git a/src/FeaturesPlugin/Test/TestPointCloud.py b/src/FeaturesPlugin/Test/TestPointCloud.py new file mode 100644 index 000000000..69fb70655 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestPointCloud.py @@ -0,0 +1,56 @@ +# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +""" + Unit test of makeVertexInsideFace +""" + +from salome.shaper import model +from GeomAPI import * + +model.begin() +partSet = model.moduleDocument() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +### Create Sphere +Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), 10) + +### Get Points Cloud +PC_1 = model.makeVertexInsideFace(Part_1_doc, model.selection("FACE", "Sphere_1_1/Face_1"), 100) + +model.end() + +### Check result +err = PC_1.feature().error() +if err != "": + print(err) + # this test should not fail with old OCCT + assert("Improper OCCT version" in err) +else: + model.testNbResults(PC_1, 1) + model.testNbSubResults(PC_1, [0]) + model.testNbSubShapes(PC_1, GeomAPI_Shape.SOLID, [0]) + model.testNbSubShapes(PC_1, GeomAPI_Shape.FACE, [0]) + model.testNbSubShapes(PC_1, GeomAPI_Shape.EDGE, [0]) + model.testNbSubShapes(PC_1, GeomAPI_Shape.VERTEX, [100]) + + assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 87e47c378..0292c038c 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -195,6 +195,16 @@ icon="icons/Features/measurement.png" helpfile="measurementFeature.html" abort_confirmation="false"> + + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +// code from KERNEL_SRC/src/Basics/Basics_OCCTVersion.hxx +#ifdef OCC_VERSION_SERVICEPACK +# define OCC_VERSION_LARGE (OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8 | OCC_VERSION_SERVICEPACK) +#else +# ifdef OCC_VERSION_DEVELOPMENT +# define OCC_VERSION_LARGE ((OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8)-1) +# else +# define OCC_VERSION_LARGE (OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8) +# endif +#endif + +#include + +Standard_Boolean comp(const std::pair& theA, + const std::pair& theB) +{ + return (theA.second < theB.second); +} + +Standard_Boolean IsUiso (const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace) +{ + BRepAdaptor_Curve2d aBAcurve2d (theEdge, theFace); + gp_Pnt2d aP2d; + gp_Vec2d aVec; + aBAcurve2d.D1 (aBAcurve2d.FirstParameter(), aP2d, aVec); + return (Abs(aVec.Y()) > Abs(aVec.X())); +} + +void CorrectShell (const TopoDS_Shape& theShell, + const TopoDS_Face& theFace) +{ + BRepAdaptor_Surface aBAsurf (theFace, Standard_False); + GeomAbs_SurfaceType aType = aBAsurf.GetType(); + if (aType <= GeomAbs_Torus) //elementary surfaces + return; + + TopLoc_Location anInputLoc; + const Handle(Geom_Surface)& anInputSurf = BRep_Tool::Surface (theFace, anInputLoc); + + BRep_Builder aBB; + + TopoDS_Iterator anIter (theShell); + for (; anIter.More(); anIter.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (anIter.Value()); + TopLoc_Location aLoc; + const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (aFace, aLoc); + if (aSurf == anInputSurf) + continue; + + TopExp_Explorer anExplo (aFace, TopAbs_EDGE); + for (; anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + Standard_Real aFirst, aLast; + Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (anEdge, aFace, aFirst, aLast); + aBB.UpdateEdge (anEdge, aPCurve, anInputSurf, anInputLoc, 0.); + } + Standard_Real aTol = BRep_Tool::Tolerance (aFace); + aBB.UpdateFace (aFace, anInputSurf, anInputLoc, aTol); + } +} + +gp_Pnt GetMidPnt2d(const TopoDS_Face& theFace, + const Standard_Boolean theIsNaturalRestrictions) +{ + gp_Pnt aResPnt; + + if (theIsNaturalRestrictions) + { + BRepAdaptor_Surface aBAsurf (theFace); + Standard_Real aUmin, aUmax, aVmin, aVmax; + aUmin = aBAsurf.FirstUParameter(); + aUmax = aBAsurf.LastUParameter(); + aVmin = aBAsurf.FirstVParameter(); + aVmax = aBAsurf.LastVParameter(); + aResPnt = aBAsurf.Value ((aUmin + aUmax)/2, (aVmin + aVmax)/2); + } + else + { + const Standard_Integer aNbSamples = 4; + TopoDS_Wire aWire = BRepTools::OuterWire (theFace); + TopTools_IndexedMapOfShape aEmap; + TopExp::MapShapes (aWire, TopAbs_EDGE, aEmap); + Standard_Integer aNbPointsOnContour = aNbSamples * aEmap.Extent(); + TColgp_Array1OfPnt anArray (1, aNbPointsOnContour); + + BRepTools_WireExplorer aWexp (aWire, theFace); + Standard_Integer anInd = 0; + for (; aWexp.More(); aWexp.Next()) + { + const TopoDS_Edge& anEdge = aWexp.Current(); + BRepAdaptor_Curve2d aBAcurve2d (anEdge, theFace); + Standard_Real aDelta = (aBAcurve2d.LastParameter() - aBAcurve2d.FirstParameter())/aNbSamples; + for (Standard_Integer ii = 0; ii < aNbSamples; ii++) + { + Standard_Real aParam = aBAcurve2d.FirstParameter() + ii * aDelta; + gp_Pnt2d aP2d = aBAcurve2d.Value (aParam); + gp_Pnt aPnt (aP2d.X(), aP2d.Y(), 0.); + anArray (++anInd) = aPnt; + } + } + + gp_Ax2 anAxis; + Standard_Boolean anIsSingular; + GeomLib::AxeOfInertia (anArray, anAxis, anIsSingular); + gp_Pnt aBaryCentre = anAxis.Location(); + gp_Pnt2d aCentre2d (aBaryCentre.X(), aBaryCentre.Y()); + BRepTopAdaptor_FClass2d aClassifier (theFace, Precision::Confusion()); + BRepAdaptor_Surface aBAsurf (theFace, Standard_False); + + TopAbs_State aStatus = aClassifier.Perform (aCentre2d); + gp_Pnt2d aP2d = aCentre2d; + Standard_Integer anIndVertex = 0; + const Standard_Integer aNbIter = 10; + while (aStatus != TopAbs_IN && anIndVertex < aNbPointsOnContour) + { + gp_Pnt aVertexPnt = anArray (anIndVertex+1); + gp_Pnt2d aVertexP2d (aVertexPnt.X(), aVertexPnt.Y()); + TColgp_SequenceOfPnt2d aPseq; + aPseq.Append (aCentre2d); + aPseq.Append (aVertexP2d); + for (Standard_Integer ii = 1; ii <= aNbIter; ii++) + { + for (Standard_Integer jj = 1; jj < aPseq.Length(); jj++) + { + aP2d.SetXY ((aPseq(jj).XY() + aPseq(jj+1).XY())/2); + aStatus = aClassifier.Perform (aP2d); + if (aStatus == TopAbs_IN) + break; + else + { + aPseq.InsertAfter (jj, aP2d); + jj++; + } + } + if (aStatus == TopAbs_IN) + break; + } + anIndVertex += aNbSamples; + } + aResPnt = aBAsurf.Value (aP2d.X(), aP2d.Y()); + } //case of complex boundaries + + return aResPnt; +} + +void ModifyFacesForGlobalResult(const TopoDS_Face& theInputFace, + const Standard_Real theAverageArea, + const Standard_Boolean theIsToAddFaces, + Standard_Integer& theNbExtremalFaces, + TopTools_MapOfShape& theExtremalFaces, + const std::vector> theFacesAndAreas, + const TopTools_DataMapOfShapeReal& theFaceAreaMap, + const TopTools_IndexedDataMapOfShapeListOfShape& theEFmap, + TopoDS_Shape& theRes, + TopoDS_Shape& theGlobalRes, + TopTools_MapOfShape& theRemovedFaces) +{ + BRep_Builder aBB; + const Standard_Integer aNbFaces = (Standard_Integer) theFacesAndAreas.size(); + + const Standard_Integer aDiff = theNbExtremalFaces - theRemovedFaces.Extent(); + + Standard_Integer aSum = 0; + while (aSum < aDiff) //global loop + { + Standard_Integer aNbFacesDone = 0, aNbFacesInTape = 0; + TopoDS_Face aStartFace; + + Standard_Integer aStartIndex = (theIsToAddFaces)? aNbFaces-1 : 0; + Standard_Integer anEndIndex = (theIsToAddFaces)? 0 : aNbFaces-1; + Standard_Integer aStep = (theIsToAddFaces)? -1 : 1; + + for (Standard_Integer ii = aStartIndex; ii != anEndIndex; ii += aStep) + { + const TopoDS_Face& aFace = TopoDS::Face (theFacesAndAreas[ii].first); + if (!theRemovedFaces.Contains(aFace)) + { + aStartFace = aFace; + break; + } + } + if (aStartFace.IsNull()) + break; + + theRemovedFaces.Add (aStartFace); + + TopoDS_Edge aCommonEdge; + TopoDS_Face aNextFace; + Standard_Real anExtremalArea = (theIsToAddFaces)? 0. : Precision::Infinite(); + for (TopExp_Explorer anExplo(aStartFace, TopAbs_EDGE); anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + const TopTools_ListOfShape& aFaceList = theEFmap.FindFromKey (anEdge); + TopTools_ListIteratorOfListOfShape anItl (aFaceList); + for (; anItl.More(); anItl.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (anItl.Value()); + if (aFace.IsSame (aStartFace) || + theRemovedFaces.Contains(aFace)) + continue; + Standard_Real anArea = theFaceAreaMap(aFace); + Standard_Boolean anIsToExchange = (theIsToAddFaces)? (anArea > anExtremalArea) : (anArea < anExtremalArea); + if (anIsToExchange) + { + anExtremalArea = anArea; + aCommonEdge = anEdge; + aNextFace = aFace; + } + } + } + if (aCommonEdge.IsNull()) //all adjacent faces are already removed + { + theExtremalFaces.Add (theFacesAndAreas[theNbExtremalFaces].first); + theNbExtremalFaces++; + continue; + } + + //Start filling the shell + aBB.Remove (theRes, aStartFace); + aNbFacesDone++; + TopoDS_Shell aShell; + aBB.MakeShell (aShell); + Standard_Real anAreaOfTape = 0.; + aBB.Add (aShell, aStartFace); + aNbFacesInTape++; + anAreaOfTape += theFaceAreaMap (aStartFace); + + Standard_Boolean anIsUiso = IsUiso (aCommonEdge, aStartFace); + //Find another faces on this level + TopoDS_Face aCurrentFace = aNextFace; + TopoDS_Edge aCurrentEdge = aCommonEdge; + Standard_Boolean anIsFirstDirection = Standard_True; + aBB.Remove (theRes, aCurrentFace); + theRemovedFaces.Add (aCurrentFace); + if (theExtremalFaces.Contains (aCurrentFace)) + { + aNbFacesDone++; + } + aBB.Add (aShell, aCurrentFace); + aNbFacesInTape++; + anAreaOfTape += theFaceAreaMap (aCurrentFace); + Standard_Boolean anIsRound = Standard_False; + for (;;) //local loop + { + TopoDS_Edge aNextEdge; + for (TopExp_Explorer anExplo(aCurrentFace, TopAbs_EDGE); anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + if (anEdge.IsSame (aCurrentEdge)) + continue; + const TopTools_ListOfShape& aFaceList = theEFmap.FindFromKey (anEdge); + TopTools_ListIteratorOfListOfShape anItl (aFaceList); + for (; anItl.More(); anItl.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (anItl.Value()); + if (aFace.IsSame (aCurrentFace)) + continue; + if (aFace.IsSame (aStartFace)) + { + anIsRound = Standard_True; + break; + } + if (theRemovedFaces.Contains(aFace)) + continue; + if (anIsUiso == IsUiso (anEdge, aFace)) + { + aNextEdge = anEdge; + aNextFace = aFace; + break; + } + } + if (anIsRound || !aNextEdge.IsNull()) + break; + } + if (anIsRound) //round tape: returned to start face + break; + if (aNextEdge.IsNull()) + { + if (anIsFirstDirection) + { + aCurrentFace = aStartFace; + aCurrentEdge = aCommonEdge; + anIsFirstDirection = Standard_False; + continue; + } + else + break; + } + + aBB.Add (aShell, aNextFace); + aNbFacesInTape++; + anAreaOfTape += theFaceAreaMap (aNextFace); + aBB.Remove (theRes, aNextFace); + theRemovedFaces.Add (aNextFace); + if (theExtremalFaces.Contains (aNextFace)) + { + aNbFacesDone++; + } + aCurrentEdge = aNextEdge; + aNextEdge.Nullify(); + aCurrentFace = aNextFace; + } //end of local loop + + //Tape is formed + Standard_Integer aNumberToSplit = (theIsToAddFaces)? aNbFacesInTape + aNbFacesDone : aNbFacesInTape - aNbFacesDone; + if (!theIsToAddFaces && aNbFacesDone > 1) + { + Standard_Integer aRealNumberToSplit = (aNumberToSplit > 0)? aNumberToSplit : 1; + Standard_Real anAverageAreaInTape = anAreaOfTape / aRealNumberToSplit; + if (anAverageAreaInTape > theAverageArea) + { + Standard_Integer aNewNumberToSplit = RealToInt(round(anAreaOfTape / theAverageArea)); + if (aNewNumberToSplit < aNbFacesInTape) + { + Standard_Integer aNumberToIncrease = aNewNumberToSplit - aNumberToSplit; + for (Standard_Integer jj = theNbExtremalFaces; jj < theNbExtremalFaces + aNumberToIncrease; jj++) + theExtremalFaces.Add (theFacesAndAreas[jj].first); + theNbExtremalFaces += aNumberToIncrease; + aNumberToSplit = aNewNumberToSplit; + } + } + } + if (anIsRound && aNumberToSplit <= 1) + { + Standard_Integer aNumberToIncrease = 3 - aNumberToSplit; + for (Standard_Integer jj = theNbExtremalFaces; jj < theNbExtremalFaces + aNumberToIncrease; jj++) + theExtremalFaces.Add (theFacesAndAreas[jj].first); + theNbExtremalFaces += aNumberToIncrease; + aNumberToSplit = 3; + } + CorrectShell (aShell, theInputFace); + ShapeUpgrade_UnifySameDomain aUnifier; + aUnifier.Initialize (aShell, Standard_True, Standard_True); + aUnifier.Build(); + TopoDS_Shape aUnifiedShape = aUnifier.Shape(); + //Splitting + TopoDS_Shape aLocalResult = aUnifiedShape; + Standard_Integer aNbFacesInLocalResult = 1; + if (aNumberToSplit > 1) + { +#if OCC_VERSION_LARGE < 0x07050304 + aNbFacesInLocalResult = 1; +#else + ShapeUpgrade_ShapeDivideArea aLocalTool (aUnifiedShape); + aLocalTool.SetSplittingByNumber (Standard_True); + aLocalTool.MaxArea() = -1; + if (anIsUiso) + aLocalTool.SetNumbersUVSplits (aNumberToSplit, 1); + else + aLocalTool.SetNumbersUVSplits (1, aNumberToSplit); + aLocalTool.Perform(); + aLocalResult = aLocalTool.Result(); + aNbFacesInLocalResult = aNumberToSplit; +#endif + } + else + { + if (aNumberToSplit == 0) + { + theExtremalFaces.Add (theFacesAndAreas[theNbExtremalFaces].first); + theNbExtremalFaces++; + } + } + aBB.Add (theGlobalRes, aLocalResult); + + aSum += Abs(aNbFacesInTape - aNbFacesInLocalResult); + } //end of global loop + + //Second global loop + TopoDS_Compound aSecondComp; + aBB.MakeCompound (aSecondComp); + while (aSum < aDiff) + { + TopoDS_Shape aMaxShell; + Standard_Integer aMaxNbFaces = 0; + TopoDS_Iterator anIter (theGlobalRes); + for (; anIter.More(); anIter.Next()) + { + const TopoDS_Shape& aShell = anIter.Value(); + TopTools_IndexedMapOfShape aFaceMap; + TopExp::MapShapes (aShell, TopAbs_FACE, aFaceMap); + if (aFaceMap.Extent() > aMaxNbFaces) + { + aMaxNbFaces = aFaceMap.Extent(); + aMaxShell = aShell; + } + } + + if (aMaxNbFaces == 1) + break; + + aBB.Remove (theGlobalRes, aMaxShell); + //Find iso + Standard_Boolean anIsUiso = Standard_True; + TopTools_IndexedDataMapOfShapeListOfShape aLocalEFmap; + TopExp::MapShapesAndAncestors (aMaxShell, TopAbs_EDGE, TopAbs_FACE, aLocalEFmap); + for (Standard_Integer jj = 1; jj <= aLocalEFmap.Extent(); jj++) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (aLocalEFmap.FindKey(jj)); + const TopTools_ListOfShape& aFaceList = aLocalEFmap(jj); + if (aFaceList.Extent() == 2) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceList.First()); + anIsUiso = IsUiso (anEdge, aFace); + break; + } + } + CorrectShell (aMaxShell, theInputFace); + ShapeUpgrade_UnifySameDomain aUnifier; + aUnifier.Initialize (aMaxShell, Standard_True, Standard_True); + aUnifier.Build(); + TopoDS_Shape aUnifiedShape = aUnifier.Shape(); + TopoDS_Shape aLocalResult = aUnifiedShape; + + Standard_Integer aNumberToSplit = (theIsToAddFaces)? aMaxNbFaces + (aDiff-aSum) : aMaxNbFaces - (aDiff-aSum); + if (aNumberToSplit > 1) + { +#if OCC_VERSION_LARGE < 0x07050304 + aNumberToSplit = 1; +#else + ShapeUpgrade_ShapeDivideArea aLocalTool (aUnifiedShape); + aLocalTool.SetSplittingByNumber (Standard_True); + aLocalTool.MaxArea() = -1; + if (anIsUiso) + aLocalTool.SetNumbersUVSplits (aNumberToSplit, 1); + else + aLocalTool.SetNumbersUVSplits (1, aNumberToSplit); + aLocalTool.Perform(); + aLocalResult = aLocalTool.Result(); +#endif + } + else + aNumberToSplit = 1; + + aBB.Add (aSecondComp, aLocalResult); + + if (theIsToAddFaces) + break; + aSum += aMaxNbFaces - aNumberToSplit; + } + aBB.Add (theGlobalRes, aSecondComp); +} + +//================================================================================================= +bool GeomAlgoAPI_PointCloudOnFace::PointCloud(GeomShapePtr theFace, + const int theNumberOfPoints, + GeomShapePtr thePoints, + std::string& theError) +{ +#ifdef _DEBUG + std::cout << "GeomAlgoAPI_PointCloudOnFace::PointCloud" << std::endl; +#endif + +#if OCC_VERSION_LARGE < 0x07050304 + theError = "Improper OCCT version: please, use OCCT 7.5.3p4 or newer."; + return false; +#else + + if (!theFace.get()) { + theError = "Face for point cloud calculation is null"; + return false; + } + + TopoDS_Shape anInputShape = theFace->impl(); + + if (anInputShape.ShapeType() != TopAbs_FACE) { + theError = "Shape for normale calculation is not a face"; + return false; + } + + TopoDS_Face anInputFace = TopoDS::Face (anInputShape); + + ShapeUpgrade_ShapeDivideArea tool (anInputFace); + tool.SetSplittingByNumber (Standard_True); + tool.NbParts() = theNumberOfPoints; + tool.Perform(); + TopoDS_Shape res = tool.Result(); + + BRep_Builder aBB; + TopoDS_Compound aGlobalRes; + aBB.MakeCompound (aGlobalRes); + + TopTools_IndexedMapOfShape aFaceMap; + TopExp::MapShapes (res, TopAbs_FACE, aFaceMap); + Standard_Integer aNbFaces = aFaceMap.Extent(); + + TopTools_IndexedDataMapOfShapeListOfShape aEFmap; + TopExp::MapShapesAndAncestors (res, TopAbs_EDGE, TopAbs_FACE, aEFmap); + + TopTools_MapOfShape aBiggestFaces, aSmallestFaces; + Standard_Boolean aUseTriangulation = Standard_True; + Standard_Boolean aSkipShared = Standard_False; + if (aNbFaces != theNumberOfPoints) + { + Standard_Real aTotalArea = 0.; + std::vector> aFacesAndAreas (aNbFaces); + for (Standard_Integer ii = 1; ii <= aNbFaces; ii++) + { + GProp_GProps aProps; + BRepGProp::SurfaceProperties (aFaceMap(ii), aProps, aSkipShared, aUseTriangulation); + Standard_Real anArea = aProps.Mass(); + aTotalArea += anArea; + std::pair aFaceWithArea (aFaceMap(ii), anArea); + aFacesAndAreas[ii-1] = aFaceWithArea; + } + std::sort (aFacesAndAreas.begin(), aFacesAndAreas.end(), comp); + + Standard_Real anAverageArea = aTotalArea / theNumberOfPoints; + + TopTools_DataMapOfShapeReal aFaceAreaMap; + for (Standard_Integer ii = 0; ii < aNbFaces; ii++) + aFaceAreaMap.Bind (aFacesAndAreas[ii].first, aFacesAndAreas[ii].second); + + TopTools_MapOfShape aRemovedFaces; + + if (aNbFaces < theNumberOfPoints) + { + Standard_Integer aNbMissingFaces = theNumberOfPoints - aNbFaces; + for (Standard_Integer ii = aNbFaces-1; ii > aNbFaces - aNbMissingFaces - 1; ii--) + aBiggestFaces.Add (aFacesAndAreas[ii].first); + + ModifyFacesForGlobalResult (anInputFace, anAverageArea, + Standard_True, //to add faces + aNbMissingFaces, aBiggestFaces, + aFacesAndAreas, aFaceAreaMap, aEFmap, + res, aGlobalRes, + aRemovedFaces); + } + else //aNbFaces > theNumberOfPoints + { + Standard_Integer aNbExcessFaces = aNbFaces - theNumberOfPoints; + for (Standard_Integer ii = 0; ii < aNbExcessFaces; ii++) + aSmallestFaces.Add (aFacesAndAreas[ii].first); + + TopTools_IndexedDataMapOfShapeListOfShape aVFmap; + TopExp::MapShapesAndAncestors (res, TopAbs_VERTEX, TopAbs_FACE, aVFmap); + + //Remove smallest faces with free boundaries + for (Standard_Integer ii = 0; ii < aNbExcessFaces; ii++) + { + const TopoDS_Face& aFace = TopoDS::Face (aFacesAndAreas[ii].first); + Standard_Boolean anIsFreeBoundFound = Standard_False; + TopExp_Explorer anExplo (aFace, TopAbs_EDGE); + for (; anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + if (!BRep_Tool::Degenerated (anEdge) && + aEFmap.FindFromKey(anEdge).Extent() < 2) + { + anIsFreeBoundFound = Standard_True; + break; + } + } + if (anIsFreeBoundFound) + { + Standard_Real aMaxArea = 0.; + for (anExplo.Init(aFace, TopAbs_VERTEX); anExplo.More(); anExplo.Next()) + { + const TopoDS_Shape& aVertex = anExplo.Current(); + const TopTools_ListOfShape& aFaceList = aVFmap.FindFromKey (aVertex); + TopTools_ListIteratorOfListOfShape anItl (aFaceList); + for (; anItl.More(); anItl.Next()) + { + Standard_Real anArea = aFaceAreaMap (anItl.Value()); + if (anArea > aMaxArea) + aMaxArea = anArea; + } + } + Standard_Real anArreaOfSmallestFace = aFaceAreaMap (aFace); + if (anArreaOfSmallestFace < aMaxArea / 16) + { + aBB.Remove (res, aFace); + aRemovedFaces.Add (aFace); + } + } + } + + ModifyFacesForGlobalResult (anInputFace, anAverageArea, + Standard_False, //to decrease number of faces + aNbExcessFaces, aSmallestFaces, + aFacesAndAreas, aFaceAreaMap, aEFmap, + res, aGlobalRes, + aRemovedFaces); + } + } + + aBB.Add (aGlobalRes, res); + + TopoDS_Compound aCompound; + aBB.MakeCompound (aCompound); + for (TopExp_Explorer aGlobalExplo(aGlobalRes, TopAbs_FACE); aGlobalExplo.More(); aGlobalExplo.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aGlobalExplo.Current()); + Standard_Boolean anIsNaturalRestrictions = Standard_True; + TopExp_Explorer anExplo (aFace, TopAbs_EDGE); + for (; anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + if (BRep_Tool::Degenerated (anEdge)) + continue; + if (!aEFmap.Contains(anEdge) || + aEFmap.FindFromKey(anEdge).Extent() < 2) + { + anIsNaturalRestrictions = Standard_False; + break; + } + } + + gp_Pnt aPnt = GetMidPnt2d (aFace, anIsNaturalRestrictions); + TopoDS_Vertex aVertex = BRepLib_MakeVertex (aPnt); + aBB.Add (aCompound, aVertex); + } + + thePoints->setImpl(new TopoDS_Shape(aCompound)); + + return true; +#endif +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_PointCloudOnFace.h b/src/GeomAlgoAPI/GeomAlgoAPI_PointCloudOnFace.h new file mode 100644 index 000000000..df63db5b0 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_PointCloudOnFace.h @@ -0,0 +1,44 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef GeomAlgoAPI_PointCloudOnFace_H_ +#define GeomAlgoAPI_PointCloudOnFace_H_ + +#include +#include + +/**\class GeomAlgoAPI_PointCloudOnFace + * \ingroup DataAlgo + * \brief Allows to create a cloud of points on face + */ + +class GeomAlgoAPI_PointCloudOnFace +{ + public: + /// Get the set of points on face + /// \param theFace the face + /// \param thePoints the compound of vertices + /// \param theError the error + GEOMALGOAPI_EXPORT static bool PointCloud(GeomShapePtr theFace, + const int theNumberOfPoints, + GeomShapePtr thePoints, + std::string& theError); +}; + +#endif diff --git a/src/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index e31635882..c0faaacf6 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -32,6 +32,7 @@ from FeaturesAPI import addFusionFaces from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle from FeaturesAPI import getPointCoordinates, getGeometryCalculation, getBoundingBox from FeaturesAPI import getNormal +from FeaturesAPI import makeVertexInsideFace from FeaturesAPI import addRemoveResults from FeaturesAPI import addCopy, addImportResult from FeaturesAPI import addDefeaturing -- 2.39.2