for (ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) {
std::shared_ptr<GeomAPI_Edge> anEdgeInList(new GeomAPI_Edge(*anIt));
if (anEdgeInList->isEqual(anEdgeInResult)) {
- aResultBody->modified(anEdgeInList, anEdgeInResult);
+ if (anEdgeInList->isSame(anEdgeInResult))
+ aResultBody->generated(anEdgeInResult, "Edge");
+ else
+ aResultBody->modified(anEdgeInList, anEdgeInResult);
break;
}
}
%shared_ptr(FeaturesAPI_ExtrusionCut)
%shared_ptr(FeaturesAPI_ExtrusionFuse)
%shared_ptr(FeaturesAPI_Fillet)
+%shared_ptr(FeaturesAPI_Fillet1D)
+%shared_ptr(FeaturesAPI_Fillet2D)
%shared_ptr(FeaturesAPI_Intersection)
%shared_ptr(FeaturesAPI_MultiRotation)
%shared_ptr(FeaturesAPI_MultiTranslation)
#include <ModelHighAPI_Double.h>
#include <ModelHighAPI_Dumper.h>
-////#include <ModelHighAPI_Reference.h>
+#include <ModelHighAPI_Selection.h>
#include <ModelHighAPI_Tools.h>
+static GeomAPI_Shape::ShapeType typeOfSelection(
+ const std::list<ModelHighAPI_Selection>& theBaseObjects)
+{
+ std::string aType = theBaseObjects.empty() ? "SHAPE" : theBaseObjects.front().shapeType();
+ return GeomAPI_Shape::shapeTypeByStr(aType);
+}
+
+//==================================================================================================
+
FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature)
: ModelHighAPI_Interface(theFeature)
+{
+}
+
+//==================================================================================================
+
+FeaturesAPI_Fillet1D::FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+ : FeaturesAPI_Fillet(theFeature)
{
initialize();
}
-FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theBaseObjects,
- const ModelHighAPI_Double& theRadius)
- : ModelHighAPI_Interface(theFeature)
+FeaturesAPI_Fillet1D::FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const ModelHighAPI_Double& theRadius)
+ : FeaturesAPI_Fillet(theFeature)
+{
+ if (initialize()) {
+ setBase(theBaseObjects);
+ fillAttribute(theRadius, myradius);
+
+ execIfBaseNotEmpty();
+ }
+}
+
+FeaturesAPI_Fillet1D::~FeaturesAPI_Fillet1D()
+{
+}
+
+void FeaturesAPI_Fillet1D::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
+{
+ mybaseWires->clear();
+ mybaseVertices->clear();
+
+ if (typeOfSelection(theBaseObjects) == GeomAPI_Shape::WIRE) {
+ fillAttribute(FeaturesPlugin_Fillet1D::CREATION_BY_WIRES(), mycreationMethod);
+ fillAttribute(theBaseObjects, mybaseWires);
+ }
+ else {
+ fillAttribute(FeaturesPlugin_Fillet1D::CREATION_BY_VERTICES(), mycreationMethod);
+ fillAttribute(theBaseObjects, mybaseVertices);
+ }
+
+ execIfBaseNotEmpty();
+}
+
+void FeaturesAPI_Fillet1D::setRadius(const ModelHighAPI_Double& theRadius)
+{
+ fillAttribute(theRadius, myradius);
+ execIfBaseNotEmpty();
+}
+
+void FeaturesAPI_Fillet1D::execIfBaseNotEmpty()
+{
+ if (mybaseWires->size() > 0 || mybaseVertices->size() > 0)
+ execute();
+}
+
+void FeaturesAPI_Fillet1D::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ FeaturePtr aBase = feature();
+ const std::string& aDocName = theDumper.name(aBase->document());
+
+ AttributeSelectionListPtr anAttrObjects;
+ if (creationMethod()->value() == FeaturesPlugin_Fillet1D::CREATION_BY_WIRES())
+ anAttrObjects = aBase->selectionList(FeaturesPlugin_Fillet1D::WIRE_LIST_ID());
+ else if (creationMethod()->value() == FeaturesPlugin_Fillet1D::CREATION_BY_VERTICES())
+ anAttrObjects = aBase->selectionList(FeaturesPlugin_Fillet1D::VERTEX_LIST_ID());
+
+ AttributeDoublePtr anAttrRadius = aBase->real(FeaturesPlugin_Fillet1D::RADIUS_ID());
+
+ theDumper << aBase << " = model.addFillet(" << aDocName << ", " << anAttrObjects
+ << ", " << anAttrRadius;
+
+ if (!aBase->data()->version().empty())
+ theDumper << ", keepSubResults = True";
+
+ theDumper << ")" << std::endl;
+}
+
+//==================================================================================================
+
+FeaturesAPI_Fillet2D::FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+ : FeaturesAPI_Fillet(theFeature)
+{
+ initialize();
+}
+
+FeaturesAPI_Fillet2D::FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const ModelHighAPI_Double& theRadius)
+ : FeaturesAPI_Fillet(theFeature)
{
if (initialize()) {
fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_SINGLE_RADIUS(), mycreationMethod);
}
}
-FeaturesAPI_Fillet::FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theBaseObjects,
- const ModelHighAPI_Double& theRadius1,
- const ModelHighAPI_Double& theRadius2)
- : ModelHighAPI_Interface(theFeature)
+FeaturesAPI_Fillet2D::FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const ModelHighAPI_Double& theRadius1,
+ const ModelHighAPI_Double& theRadius2)
+ : FeaturesAPI_Fillet(theFeature)
{
if (initialize()) {
fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_VARYING_RADIUS(), mycreationMethod);
}
}
-FeaturesAPI_Fillet::~FeaturesAPI_Fillet()
+FeaturesAPI_Fillet2D::~FeaturesAPI_Fillet2D()
{
}
-//==================================================================================================
-void FeaturesAPI_Fillet::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
+void FeaturesAPI_Fillet2D::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
{
mybaseObjects->clear();
fillAttribute(theBaseObjects, mybaseObjects);
execIfBaseNotEmpty();
}
-void FeaturesAPI_Fillet::setRadius(const ModelHighAPI_Double& theRadius)
+void FeaturesAPI_Fillet2D::setRadius(const ModelHighAPI_Double& theRadius)
{
fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_SINGLE_RADIUS(), mycreationMethod);
fillAttribute(theRadius, myradius);
execIfBaseNotEmpty();
}
-void FeaturesAPI_Fillet::setRadius(const ModelHighAPI_Double& theRadius1,
- const ModelHighAPI_Double& theRadius2)
+void FeaturesAPI_Fillet2D::setRadius(const ModelHighAPI_Double& theRadius1,
+ const ModelHighAPI_Double& theRadius2)
{
fillAttribute(FeaturesPlugin_Fillet::CREATION_METHOD_VARYING_RADIUS(), mycreationMethod);
fillAttribute(theRadius1, mystartRadius);
execIfBaseNotEmpty();
}
-void FeaturesAPI_Fillet::dump(ModelHighAPI_Dumper& theDumper) const
+void FeaturesAPI_Fillet2D::dump(ModelHighAPI_Dumper& theDumper) const
{
FeaturePtr aBase = feature();
const std::string& aDocName = theDumper.name(aBase->document());
theDumper << ")" << std::endl;
}
-void FeaturesAPI_Fillet::execIfBaseNotEmpty()
+void FeaturesAPI_Fillet2D::execIfBaseNotEmpty()
{
if (mybaseObjects->size() > 0)
execute();
const ModelHighAPI_Double& theRadius2,
const bool keepSubResults)
{
- std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Fillet::ID());
+ GeomAPI_Shape::ShapeType aType = typeOfSelection(theBaseObjects);
+ bool is1D = aType == GeomAPI_Shape::WIRE || aType == GeomAPI_Shape::VERTEX;
+
+ FeaturePtr aFeature =
+ thePart->addFeature(is1D ? FeaturesAPI_Fillet1D::ID() : FeaturesAPI_Fillet2D::ID());
if (!keepSubResults)
aFeature->data()->setVersion("");
FilletPtr aFillet;
- if (theRadius2.value() < 0.0)
- aFillet.reset(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1));
+ if (is1D)
+ aFillet.reset(new FeaturesAPI_Fillet1D(aFeature, theBaseObjects, theRadius1));
+ else if (theRadius2.value() < 0.0)
+ aFillet.reset(new FeaturesAPI_Fillet2D(aFeature, theBaseObjects, theRadius1));
else
- aFillet.reset(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1, theRadius2));
+ aFillet.reset(new FeaturesAPI_Fillet2D(aFeature, theBaseObjects, theRadius1, theRadius2));
return aFillet;
}
#include "FeaturesAPI.h"
#include <FeaturesPlugin_Fillet.h>
+#include <FeaturesPlugin_Fillet1D.h>
#include <ModelHighAPI_Double.h>
#include <ModelHighAPI_Interface.h>
/// \brief Interface for Fillet feature.
class FeaturesAPI_Fillet: public ModelHighAPI_Interface
{
+public:
+ /// Destructor.
+ virtual ~FeaturesAPI_Fillet() {}
+
+ virtual std::shared_ptr<ModelAPI_AttributeDouble> radius() const = 0;
+
+ /// Modify base objects of the fillet.
+ virtual void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects) = 0;
+
+ /// Modify fillet to have fixed radius
+ virtual void setRadius(const ModelHighAPI_Double& theRadius) = 0;
+
+protected:
+ FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+};
+
+/// Pointer on the fillet object.
+typedef std::shared_ptr<FeaturesAPI_Fillet> FilletPtr;
+
+
+/// \class FeaturesAPI_Fillet1D
+/// \ingroup CPPHighAPI
+/// \brief Interface for Fillet1D feature - fillet on vertices of a wire.
+class FeaturesAPI_Fillet1D : public FeaturesAPI_Fillet
+{
public:
/// Constructor without values.
FEATURESAPI_EXPORT
- explicit FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+ explicit FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature);
/// Constructor with values.
FEATURESAPI_EXPORT
- explicit FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theBaseObjects,
- const ModelHighAPI_Double& theRadius);
+ explicit FeaturesAPI_Fillet1D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const ModelHighAPI_Double& theRadius);
+
+ /// Destructor.
+ FEATURESAPI_EXPORT
+ virtual ~FeaturesAPI_Fillet1D();
+
+ INTERFACE_4(FeaturesPlugin_Fillet1D::ID(),
+ creationMethod, FeaturesPlugin_Fillet1D::CREATION_METHOD(),
+ ModelAPI_AttributeString,
+ /** Creation method */,
+ baseWires, FeaturesPlugin_Fillet1D::WIRE_LIST_ID(),
+ ModelAPI_AttributeSelectionList,
+ /** Base objects */,
+ baseVertices, FeaturesPlugin_Fillet1D::VERTEX_LIST_ID(),
+ ModelAPI_AttributeSelectionList,
+ /** Base objects */,
+ radius, FeaturesPlugin_Fillet1D::RADIUS_ID(),
+ ModelAPI_AttributeDouble,
+ /** Value of the fixed radius fillet */)
+
+ /// Modify base objects of the fillet.
+ FEATURESAPI_EXPORT
+ virtual void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+ /// Modify fillet to have fixed radius
+ FEATURESAPI_EXPORT
+ virtual void setRadius(const ModelHighAPI_Double& theRadius);
+
+ /// Dump wrapped feature
+ FEATURESAPI_EXPORT
+ virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+private:
+ void execIfBaseNotEmpty();
+};
+
+
+/// \class FeaturesAPI_Fillet2D
+/// \ingroup CPPHighAPI
+/// \brief Interface for Fillet feature - fillet edges on a solid.
+class FeaturesAPI_Fillet2D : public FeaturesAPI_Fillet
+{
+public:
+ /// Constructor without values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Constructor with values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const ModelHighAPI_Double& theRadius);
/// Constructor with values.
FEATURESAPI_EXPORT
- explicit FeaturesAPI_Fillet(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theBaseObjects,
- const ModelHighAPI_Double& theRadius1,
- const ModelHighAPI_Double& theRadius2);
+ explicit FeaturesAPI_Fillet2D(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const ModelHighAPI_Double& theRadius1,
+ const ModelHighAPI_Double& theRadius2);
/// Destructor.
FEATURESAPI_EXPORT
- virtual ~FeaturesAPI_Fillet();
+ virtual ~FeaturesAPI_Fillet2D();
INTERFACE_5(FeaturesPlugin_Fillet::ID(),
creationMethod, FeaturesPlugin_Fillet::CREATION_METHOD(),
/// Modify base objects of the fillet.
FEATURESAPI_EXPORT
- void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+ virtual void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
/// Modify fillet to have fixed radius
FEATURESAPI_EXPORT
- void setRadius(const ModelHighAPI_Double& theRadius);
+ virtual void setRadius(const ModelHighAPI_Double& theRadius);
/// Modify fillet to have varying radius
FEATURESAPI_EXPORT
void execIfBaseNotEmpty();
};
-/// Pointer on Fillet object.
-typedef std::shared_ptr<FeaturesAPI_Fillet> FilletPtr;
/// \ingroup CPPHighAPI
/// \brief Create Fillet feature.
FeaturesPlugin_MultiTranslation.h
FeaturesPlugin_MultiRotation.h
FeaturesPlugin_Fillet.h
+ FeaturesPlugin_Fillet1D.h
FeaturesPlugin_Measurement.h
FeaturesPlugin_FusionFaces.h
FeaturesPlugin_RemoveResults.h
FeaturesPlugin_MultiTranslation.cpp
FeaturesPlugin_MultiRotation.cpp
FeaturesPlugin_Fillet.cpp
+ FeaturesPlugin_Fillet1D.cpp
FeaturesPlugin_Measurement.cpp
FeaturesPlugin_FusionFaces.cpp
FeaturesPlugin_RemoveResults.cpp
multitranslation_widget.xml
multirotation_widget.xml
fillet_widget.xml
+ fillet1d_widget.xml
measurement_widget.xml
fusion_faces_widget.xml
chamfer_widget.xml
TestChamfer_MultiLevelCompound_v95_4.py
Test18836.py
Test2817.py
+ TestFillet1D_ErrorMsg.py
+ TestFillet1D_Vertices_1.py
+ TestFillet1D_Vertices_2.py
+ TestFillet1D_Vertices_3.py
+ TestFillet1D_Vertices_4.py
+ TestFillet1D_Vertices_5.py
+ TestFillet1D_Vertices_6.py
+ TestFillet1D_Vertices_7.py
+ TestFillet1D_Vertices_8.py
+ TestFillet1D_Wire_1.py
+ TestFillet1D_Wire_2.py
+ TestFillet1D_Wire_3.py
+ TestFillet1D_Wire_4.py
)
--- /dev/null
+// Copyright (C) 2020 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_Fillet1D.h>
+#include <FeaturesPlugin_Tools.h>
+
+#include <GeomAlgoAPI_Fillet1D.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAlgoAPI_Tools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pln.h>
+#include <GeomAPI_WireExplorer.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+
+FeaturesPlugin_Fillet1D::FeaturesPlugin_Fillet1D()
+{
+}
+
+void FeaturesPlugin_Fillet1D::initAttributes()
+{
+ data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
+ data()->addAttribute(WIRE_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+ data()->addAttribute(VERTEX_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+ data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+}
+
+void FeaturesPlugin_Fillet1D::execute()
+{
+ MapShapeSubs aWireVertices;
+ if (!baseShapes(aWireVertices))
+ return;
+
+ int aResultIndex = 0;
+ for (MapShapeSubs::iterator anIt = aWireVertices.begin(); anIt != aWireVertices.end(); ++anIt)
+ if (!performFillet(anIt->first, anIt->second, aResultIndex++))
+ break;
+ removeResults(aResultIndex);
+}
+
+bool FeaturesPlugin_Fillet1D::baseShapes(MapShapeSubs& theWireVertices)
+{
+ std::string aMethod = string(CREATION_METHOD())->value();
+ if (aMethod == CREATION_BY_WIRES()) {
+ AttributeSelectionListPtr aSelList = selectionList(WIRE_LIST_ID());
+
+ std::set<GeomShapePtr> aProcessedWires;
+ int aNbSel = aSelList->size();
+ for (int ind = 0; ind < aNbSel; ++ind) {
+ AttributeSelectionPtr aCurSel = aSelList->value(ind);
+ GeomShapePtr aWire = aCurSel->context()->shape();
+ if (aProcessedWires.find(aWire) != aProcessedWires.end())
+ continue;
+
+ aProcessedWires.insert(aWire);
+ // get vertices applicable for fillet
+ GeomAlgoAPI_MapShapesAndAncestors aMapVE(aWire, GeomAPI_Shape::VERTEX, GeomAPI_Shape::EDGE);
+ const MapShapeToShapes& aSubshapes = aMapVE.map();
+ std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aFilletVertices;
+ for (MapShapeToShapes::const_iterator anIt = aSubshapes.begin();
+ anIt != aSubshapes.end(); ++anIt) {
+ // vertex should have 2 adjacent edges
+ if (anIt->second.size() != 2)
+ continue;
+
+ // skip vertices, which adjacent edges are not on the same plane
+ ListOfShape anEdges;
+ anEdges.insert(anEdges.end(), anIt->second.begin(), anIt->second.end());
+ GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+ if (!aPlane)
+ continue;
+
+ // skip vertices, which smoothly connect adjacent edges
+ GeomEdgePtr anEdge1(new GeomAPI_Edge(anEdges.front()));
+ GeomEdgePtr anEdge2(new GeomAPI_Edge(anEdges.back()));
+ GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(anIt->first));
+ if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex))
+ continue;
+
+ aFilletVertices.insert(anIt->first);
+ }
+
+ if (aFilletVertices.empty()) {
+ setError("Wire has no vertices for fillet.");
+ return false;
+ }
+
+
+ // keep the sequence of fillet vertices stable
+ for (GeomAPI_WireExplorer anExp(aWire->wire()); anExp.more(); anExp.next()) {
+ GeomShapePtr aVertex = anExp.currentVertex();
+ if (aFilletVertices.find(aVertex) != aFilletVertices.end())
+ theWireVertices[aWire].push_back(aVertex);
+ }
+ }
+ }
+ else if (aMethod == CREATION_BY_VERTICES()) {
+ AttributeSelectionListPtr aSelList = selectionList(VERTEX_LIST_ID());
+ int aNbSel = aSelList->size();
+ for (int ind = 0; ind < aNbSel; ++ind) {
+ AttributeSelectionPtr aCurSel = aSelList->value(ind);
+ GeomShapePtr aWire = aCurSel->context()->shape();
+ GeomShapePtr aVertex = aCurSel->value();
+ theWireVertices[aWire].push_back(aVertex);
+ }
+ }
+ return true;
+}
+
+bool FeaturesPlugin_Fillet1D::performFillet(const GeomShapePtr& theWire,
+ const ListOfShape& theVertices,
+ const int theResultIndex)
+{
+ double aRadius = real(RADIUS_ID())->value();
+
+ // perform fillet operation
+ std::shared_ptr<GeomAlgoAPI_Fillet1D> aFilletBuilder(
+ new GeomAlgoAPI_Fillet1D(theWire, theVertices, aRadius));
+
+ std::string anError;
+ if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilletBuilder, getKind(), anError)) {
+ setError(anError);
+ return false;
+ }
+
+ static const std::string THE_PREFIX = "Fillet1D";
+
+ // store result
+ ResultBodyPtr aResult = document()->createBody(data(), theResultIndex);
+ ListOfShape anOriginal;
+ anOriginal.push_back(theWire);
+ FeaturesPlugin_Tools::loadModifiedShapes(aResult, anOriginal, ListOfShape(),
+ aFilletBuilder, aFilletBuilder->shape(), THE_PREFIX);
+ setResult(aResult, theResultIndex);
+ // store new edges generated from vertices
+ for (ListOfShape::const_iterator anIt = theVertices.begin(); anIt != theVertices.end(); ++anIt)
+ aResult->loadGeneratedShapes(aFilletBuilder, *anIt, GeomAPI_Shape::VERTEX, THE_PREFIX, true);
+
+ return true;
+}
--- /dev/null
+// Copyright (C) 2020 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_Fillet1D_H_
+#define FeaturesPlugin_Fillet1D_H_
+
+#include <FeaturesPlugin.h>
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Feature.h>
+
+#include <map>
+
+/// \class FeaturesPlugin_Fillet1D
+/// \ingroup Plugins
+/// \brief Feature for appling fillet on vertices of 3D wire.
+class FeaturesPlugin_Fillet1D : public ModelAPI_Feature
+{
+ typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator> MapShapeSubs;
+
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("Fillet1D");
+ return MY_ID;
+ }
+
+ /// \return the kind of a feature.
+ FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = FeaturesPlugin_Fillet1D::ID();
+ return MY_KIND;
+ }
+
+ inline static const std::string& CREATION_METHOD()
+ {
+ static std::string MY_CREATION_METHOD("creation_method");
+ return MY_CREATION_METHOD;
+ }
+
+ inline static const std::string CREATION_BY_WIRES()
+ {
+ static std::string MY_SINGLE_RADIUS("by_wires");
+ return MY_SINGLE_RADIUS;
+ }
+
+ inline static const std::string CREATION_BY_VERTICES()
+ {
+ static std::string MY_VARYING_RADIUS("by_vertices");
+ return MY_VARYING_RADIUS;
+ }
+
+ /// Attribute name of selected wires.
+ inline static const std::string& WIRE_LIST_ID()
+ {
+ static const std::string MY_OBJECT_LIST_ID("main_wires");
+ return MY_OBJECT_LIST_ID;
+ }
+
+ /// Attribute name of selected vertices.
+ inline static const std::string& VERTEX_LIST_ID()
+ {
+ static const std::string MY_OBJECT_LIST_ID("main_vertices");
+ return MY_OBJECT_LIST_ID;
+ }
+
+ /// Attribute name of radius.
+ inline static const std::string& RADIUS_ID()
+ {
+ static const std::string MY_RADIUS_ID("radius");
+ return MY_RADIUS_ID;
+ }
+
+ /// Request for initialization of data model of the feature: adding all attributes.
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Performs the fillet algorithm and stores it in the data structure.
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Use plugin manager for features creation.
+ FeaturesPlugin_Fillet1D();
+
+private:
+ /// Get the list of wires and fillet vertices
+ /// \retun \c false if errors occured
+ bool baseShapes(MapShapeSubs& theWireVertices);
+
+ /// Run fillet operation and store result.
+ /// \return \c false if fillet failed.
+ bool performFillet(const GeomShapePtr& theWire,
+ const ListOfShape& theVertices,
+ const int theResultIndex);
+};
+
+#endif
#include <FeaturesPlugin_ExtrusionCut.h>
#include <FeaturesPlugin_ExtrusionFuse.h>
#include <FeaturesPlugin_Fillet.h>
+#include <FeaturesPlugin_Fillet1D.h>
#include <FeaturesPlugin_Intersection.h>
#include <FeaturesPlugin_Measurement.h>
#include <FeaturesPlugin_MultiRotation.h>
new FeaturesPlugin_ValidatorConcealedResult);
aFactory->registerValidator("FeaturesPlugin_ValidatorFilletSelection",
new FeaturesPlugin_ValidatorFilletSelection);
+ aFactory->registerValidator("FeaturesPlugin_ValidatorFillet1DSelection",
+ new FeaturesPlugin_ValidatorFillet1DSelection);
aFactory->registerValidator("FeaturesPlugin_ValidatorCircular",
new FeaturesPlugin_ValidatorCircular);
aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanArguments",
return FeaturePtr(new FeaturesPlugin_MultiRotation);
} else if (theFeatureID == FeaturesPlugin_Fillet::ID()) {
return FeaturePtr(new FeaturesPlugin_Fillet);
+ } else if (theFeatureID == FeaturesPlugin_Fillet1D::ID()) {
+ return FeaturePtr(new FeaturesPlugin_Fillet1D);
} else if (theFeatureID == FeaturesPlugin_Measurement::ID()) {
return FeaturePtr(new FeaturesPlugin_Measurement);
} else if (theFeatureID == FeaturesPlugin_RemoveResults::ID()) {
#include <GeomAPI_ShapeIterator.h>
#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
#include <GeomAlgoAPI_Prism.h>
#include <GeomAlgoAPI_ShapeBuilder.h>
#include <GeomAlgoAPI_ShapeTools.h>
return true;
}
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorFillet1DSelection::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ AttributeSelectionListPtr anAttrSelectionList =
+ std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+ if (!anAttrSelectionList.get()) {
+ // LCOV_EXCL_START
+ theError =
+ "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+
+ // check each selected vertex is a sharp corner between adjacent edges,
+ // and these edges are in the same plane
+ std::map<GeomShapePtr, MapShapeToShapes> aWireSubshapes;
+ int aNbSel = anAttrSelectionList->size();
+ for (int ind = 0; ind < aNbSel; ++ind) {
+ AttributeSelectionPtr aCurSel = anAttrSelectionList->value(ind);
+ GeomShapePtr aContext = aCurSel->context()->shape();
+ GeomShapePtr aVertex = aCurSel->value();
+ // check wire already processed, if not, store all vertices and edges, sharing them
+ std::map<GeomShapePtr, MapShapeToShapes>::iterator aProcessed = aWireSubshapes.find(aContext);
+ if (aProcessed == aWireSubshapes.end()) {
+ if (aContext->shapeType() != GeomAPI_Shape::WIRE) {
+ theError = "Selected vertex is not a wire corner";
+ return false;
+ }
+ if (aVertex->shapeType() != GeomAPI_Shape::VERTEX) {
+ theError = "Selected shape it not a vertex";
+ return false;
+ }
+
+ GeomAlgoAPI_MapShapesAndAncestors aMapVE(aContext, GeomAPI_Shape::VERTEX,
+ GeomAPI_Shape::EDGE);
+ aWireSubshapes[aContext] = aMapVE.map();
+ aProcessed = aWireSubshapes.find(aContext);
+ }
+
+ // check the vertex
+ MapShapeToShapes::iterator aFound = aProcessed->second.find(aVertex);
+ if (aFound == aProcessed->second.end()) {
+ theError = "Selected vertex does not exist in the wire";
+ return true;
+ }
+ else if (aFound->second.size() != 2) {
+ theError = "Vertex should be shared between 2 edges exactly";
+ return false;
+ }
+
+ ListOfShape anEdges;
+ anEdges.insert(anEdges.end(), aFound->second.begin(), aFound->second.end());
+ GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+ if (!aPlane) {
+ theError = "Error: Edges are not planar";
+ return false;
+ }
+
+ GeomEdgePtr anEdge1(new GeomAPI_Edge(anEdges.front()));
+ GeomEdgePtr anEdge2(new GeomAPI_Edge(anEdges.back()));
+ GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(aVertex));
+ if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex)) {
+ theError = "Error: Edges are tangent";
+ return false;
+ }
+ }
+
+ return true;
+}
+
//==================================================================================================
bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
const std::list<std::string>& theArguments,
Events_InfoMessage& theError) const;
};
+/// \class FeaturesPlugin_ValidatorFillet1DSelection
+/// \ingroup Validators
+/// \brief Validates selection for 1d-fillet operation.
+class FeaturesPlugin_ValidatorFillet1DSelection : public ModelAPI_AttributeValidator
+{
+public:
+ /// \return True if the attribute is valid. It checks whether the selection
+ /// is acceptable for fillet on wire (vertex is a sharp corner).
+ /// \param[in] theAttribute an attribute to check.
+ /// \param[in] theArguments a filter parameters.
+ /// \param[out] theError error message.
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
/// \class FeaturesPlugin_ValidatorPartitionSelection
/// \ingroup Validators
/// \brief Validates selection for partition.
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(35.66344827586208, 18.52827586206897, -10.58758620689655, 18.52827586206897)
+Sketch_1.setHorizontal(SketchLine_1.result())
+
+### Create SketchProjection
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_1.createdFeature()
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-10.58758620689655, 34.59034482758621, -10.58758620689655, 18.52827586206897, 0, 46.66896551724138, True)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_1.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchLine_2.result(), SketchArc_1.endPoint())
+model.do()
+
+### Create Sketch
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+
+### Create SketchLine
+SketchLine_3 = Sketch_2.addLine(46.66896551724138, 0, 49.59252615395944, 57.3324122669822)
+
+### Create SketchProjection
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_1_2_StartVertex"), False)
+SketchPoint_1 = SketchProjection_2.createdFeature()
+Sketch_2.setCoincident(SketchLine_3.startPoint(), SketchPoint_1.result())
+model.do()
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchArc_1_2"), model.selection("EDGE", "Sketch_2/SketchLine_3")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+model.end()
+
+
+### Check errors on 1D-fillet
+vertices = ["Sketch_1/SketchLine_1_StartVertex",
+ "Sketch_2/SketchLine_3_EndVertex",
+ "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchArc_1_2]e",
+ "[Wire_1_1/Modified_Edge&Sketch_1/SketchArc_1_2]e[Wire_1_1/Modified_Edge&Sketch_2/SketchLine_3]e"]
+for v in vertices:
+ model.begin()
+ Fillet1D = model.addFillet(Part_1_doc, [model.selection("VERTEX", v)], 1)
+ model.end()
+ assert(Fillet1D.feature().error() != "")
+
+### Wire has no vertices applicable for 1D-fillet
+model.begin()
+Fillet1D = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 1)
+model.end()
+assert(Fillet1D.feature().error() != "")
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_2]e")], 2)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [6])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [12])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[(Wire_1_1/Edge_4)(Wire_1_1/Edge_5)2_Fillet1D_1_1]e[Wire_1_1/Edge_4]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_4]e[Wire_1_1/Edge_6]e")], 2)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [9])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [18])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_3]e")], 1)
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [10])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [20])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+### Create Fillet1D
+Fillet1D_3 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[(Wire_1_1/Edge_8)4(Wire_1_1/Edge_5)4_Fillet1D_2_1]e[(Wire_1_1/Edge_8)3(Wire_1_1/Edge_7)4_Fillet1D_2_1]e")], 5)
+
+model.testHaveNamingByType(Fillet1D_3, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_3, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_3, 1)
+model.testNbSubResults(Fillet1D_3, [0])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.EDGE, [11])
+model.testNbSubShapes(Fillet1D_3, GeomAPI_Shape.VERTEX, [22])
+model.testResultsVolumes(Fillet1D_3, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 45)
+Wire_1_objects = [model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_2]"), model.selection("EDGE", "[Cylinder_1_1/Face_2][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_4][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_3][Cylinder_1_1/Face_4]"), model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_3]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_2]e")], 1)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [6])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [12])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_4]e[Wire_1_1/Edge_3]e")], 3)
+
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(-21.09850585253612, 7.838733928946021, 28.18352301808598, -36.47460859551143)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(28.18352301808598, -36.47460859551143, -24.86780397022334, -36.47460859551143)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-24.86780397022334, -14.15762886307242, -24.86780397022334, -36.47460859551143, -21.09850585253612, 7.838733928946021, True)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_2]e")], 2)
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [4])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [8])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Fillet1D_1_1/ME:Fillet1D&Sketch_1/SketchLine_1]e[_weak_name_1_Fillet1D_1_1]e")], 20)
+
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_2, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_2, 1)
+model.testNbSubResults(Fillet1D_2, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Fillet1D_2, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_2]e[Wire_1_1/Edge_3]e"), model.selection("VERTEX", "[Wire_1_1/Edge_3]e[Wire_1_1/Edge_4]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_4]e[Wire_1_1/Edge_6]e"), model.selection("VERTEX", "[Wire_1_1/Edge_2]e[Wire_1_1/Edge_4]e"), model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_3]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [11])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [22])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 45)
+Wire_1_objects = [model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_2]"), model.selection("EDGE", "[Cylinder_1_1/Face_2][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_4][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_3][Cylinder_1_1/Face_4]"), model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_3]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Edge_1]e[Wire_1_1/Edge_2]e"), model.selection("VERTEX", "[Wire_1_1/Edge_3]e[Wire_1_1/Edge_4]e")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [7])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [14])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(-21.09850585253612, 7.838733928946021, 28.18352301808598, -36.47460859551143)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(28.18352301808598, -36.47460859551143, -24.86780397022334, -36.47460859551143)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-24.86780397022334, -14.15762886307242, -24.86780397022334, -36.47460859551143, -21.09850585253612, 7.838733928946021, True)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_2]e"), model.selection("VERTEX", "[Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1]e[Wire_1_1/Modified_Edge&Sketch_1/SketchArc_1_2]e")], 15)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [9])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [18])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+### Create Wire
+Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Left]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 45)
+Wire_1_objects = [model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_2]"), model.selection("EDGE", "[Cylinder_1_1/Face_2][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_4][Cylinder_1_1/Face_5]"), model.selection("EDGE", "[Cylinder_1_1/Face_3][Cylinder_1_1/Face_4]"), model.selection("EDGE", "[Cylinder_1_1/Face_1][Cylinder_1_1/Face_3]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 1)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [9])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [18])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+# Copyright (C) 2020 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
+#
+
+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 Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(-21.09850585253612, 7.838733928946021, 28.18352301808598, -36.47460859551143)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(28.18352301808598, -36.47460859551143, -24.86780397022334, -36.47460859551143)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(-24.86780397022334, -14.15762886307242, -24.86780397022334, -36.47460859551143, -21.09850585253612, 7.838733928946021, True)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], 2)
+
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.VERTEX)
+model.testHaveNamingByType(Fillet1D_1, model, Part_1_doc, GeomAPI_Shape.EDGE)
+model.end()
+
+model.testNbResults(Fillet1D_1, 1)
+model.testNbSubResults(Fillet1D_1, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Fillet1D_1, [0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
--- /dev/null
+<source>
+ <toolbox id="creation_method">
+ <box id="by_wires"
+ title="Wires"
+ tooltip="Fillet each sharp corner of the wire"
+ icon="icons/Features/fillet1d_wire.png">
+ <multi_selector id="main_wires"
+ label="Wires"
+ icon=""
+ tooltip="Select wires"
+ shape_types="wires"
+ use_choice="false"
+ concealment="true">
+ <validator id="PartSet_DifferentObjects"/>
+ </multi_selector>
+ </box>
+ <box id="by_vertices"
+ title="Vertices"
+ tooltip="Fillet the specified corners of the wire"
+ icon="icons/Features/fillet1d_points.png">
+ <multi_selector id="main_vertices"
+ label="Vertices"
+ icon=""
+ tooltip="Select vertices"
+ shape_types="vertices"
+ use_choice="false"
+ concealment="true">
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="FeaturesPlugin_ValidatorFillet1DSelection"/>
+ </multi_selector>
+ </box>
+ </toolbox>
+ <doublevalue id="radius"
+ label="Radius"
+ tooltip="Fillet radius."
+ min="0"
+ default="0">
+ <validator id="GeomValidators_Positive"/>
+ </doublevalue>
+</source>
</feature>
</group>
<group id="Features">
+ <feature id="Fillet1D"
+ title="1D-fillet"
+ tooltip="Perform fillet on vertices of a wire"
+ icon="icons/Features/fillet1d.png"
+ auto_preview="true"
+ apply_continue="true"
+ helpfile="fillet1dFeature.html">
+ <source path="fillet1d_widget.xml"/>
+ </feature>
<feature id="Fillet" title="Fillet" tooltip="Perform fillet on face or edge"
icon="icons/Features/fillet.png" auto_preview="true" helpfile="filletFeature.html">
<source path="fillet_widget.xml"/>
#include <ModelAPI_ResultBody.h>
#include <ModelAPI_Tools.h>
+#include <GeomAPI_Edge.h>
#include <GeomAPI_Shape.h>
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_Wire.h>
BRep_Builder().UpdateVertex(aVLast, theTolerance);
}
+double GeomAPI_Edge::firstPointTolerance() const
+{
+ TopoDS_Edge anEdge = impl<TopoDS_Edge>();
+ TopoDS_Vertex aVFirst, aVLast;
+ TopExp::Vertices(anEdge, aVFirst, aVLast);
+ return BRep_Tool::Tolerance(aVFirst);
+}
+
+double GeomAPI_Edge::lastPointTolerance() const
+{
+ TopoDS_Edge anEdge = impl<TopoDS_Edge>();
+ TopoDS_Vertex aVFirst, aVLast;
+ TopExp::Vertices(anEdge, aVFirst, aVLast);
+ return BRep_Tool::Tolerance(aVLast);
+}
+
GeomPointPtr GeomAPI_Edge::middlePoint() const
{
GeomPointPtr aMiddlePoint;
GEOMAPI_EXPORT
void setLastPointTolerance(const double theTolerance);
+ GEOMAPI_EXPORT double firstPointTolerance() const;
+
+ GEOMAPI_EXPORT double lastPointTolerance() const;
+
/// Return middle point on the edge
GEOMAPI_EXPORT
virtual std::shared_ptr<GeomAPI_Pnt> middlePoint() const;
//
#include <GeomAPI_WireExplorer.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Vertex.h>
#include <GeomAPI_Wire.h>
#include <BRepTools_WireExplorer.hxx>
MY_EXPLORER->Next();
}
-std::shared_ptr<GeomAPI_Shape> GeomAPI_WireExplorer::current()
+std::shared_ptr<GeomAPI_Edge> GeomAPI_WireExplorer::current()
+{
+ const TopoDS_Edge& aShape = MY_EXPLORER->Current();
+ std::shared_ptr<GeomAPI_Edge> aGeomShape(new GeomAPI_Edge());
+ aGeomShape->setImpl(new TopoDS_Edge(aShape));
+ return aGeomShape;
+}
+
+std::shared_ptr<GeomAPI_Vertex> GeomAPI_WireExplorer::currentVertex()
{
- const TopoDS_Shape& aShape = MY_EXPLORER->Current();
- std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape());
- aGeomShape->setImpl(new TopoDS_Shape(aShape));
+ const TopoDS_Vertex& aShape = MY_EXPLORER->CurrentVertex();
+ std::shared_ptr<GeomAPI_Vertex> aGeomShape(new GeomAPI_Vertex());
+ aGeomShape->setImpl(new TopoDS_Vertex(aShape));
return aGeomShape;
}
#include <GeomAPI.h>
#include <GeomAPI_Interface.h>
+class GeomAPI_Edge;
class GeomAPI_Shape;
+class GeomAPI_Vertex;
class GeomAPI_Wire;
/** \class GeomAPI_WireExplorer
/// if there are no more shapes to explore.
GEOMAPI_EXPORT void next();
- /// \return the current shape in the exploration or empty pointer
+ /// \return the current edge in the exploration or empty pointer
/// if this explorer has no more shapes to explore.
- GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Shape> current();
+ GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Edge> current();
+
+ /// \return the current vertex in the exploration or empty pointer
+ /// if this explorer has no more shapes to explore.
+ GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Vertex> currentVertex();
/// Clears the content of the explorer. It will return False on more().
GEOMAPI_EXPORT void clear();
GeomAlgoAPI_Circ2dBuilder.h
GeomAlgoAPI_UnifySameDomain.h
GeomAlgoAPI_Fillet.h
+ GeomAlgoAPI_Fillet1D.h
GeomAlgoAPI_SortListOfShapes.h
GeomAlgoAPI_Filling.h
GeomAlgoAPI_CurveBuilder.h
GeomAlgoAPI_Circ2dBuilder.cpp
GeomAlgoAPI_UnifySameDomain.cpp
GeomAlgoAPI_Fillet.cpp
+ GeomAlgoAPI_Fillet1D.cpp
GeomAlgoAPI_SortListOfShapes.cpp
GeomAlgoAPI_Filling.cpp
GeomAlgoAPI_CurveBuilder.cpp
--- /dev/null
+// Copyright (C) 2020 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 <GeomAlgoAPI_Fillet1D.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pln.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Wire.h>
+#include <GeomAPI_WireExplorer.h>
+
+#include <GEOMImpl_Fillet1d.hxx>
+
+#include <BRep_Builder.hxx>
+#include <BRepTools_WireExplorer.hxx>
+#include <ShapeFix_Wire.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Wire.hxx>
+
+static GeomShapePtr convert(const TopoDS_Shape& theShape)
+{
+ GeomShapePtr aNewShape(new GeomAPI_Shape);
+ aNewShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(theShape));
+ return aNewShape;
+}
+
+static void substituteNewEdge(GeomEdgePtr theEdge,
+ std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>& theMap)
+{
+ std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>::iterator anIt = theMap.begin();
+ for (; anIt != theMap.end(); ++anIt) {
+ for (ListOfShape::iterator aEIt = anIt->second.begin(); aEIt != anIt->second.end(); ++aEIt)
+ if (theEdge->isEqual(*aEIt)) {
+ // substitute edge and stop iteration
+ *aEIt = theEdge;
+ return;
+ }
+ }
+}
+
+
+GeomAlgoAPI_Fillet1D::GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
+ const ListOfShape& theFilletVertices,
+ const double theFilletRadius)
+{
+ build(theBaseWire, theFilletVertices, theFilletRadius);
+}
+
+void GeomAlgoAPI_Fillet1D::build(const GeomShapePtr& theBaseWire,
+ const ListOfShape& theFilletVertices,
+ const double theRadius)
+{
+ if (!theBaseWire || theFilletVertices.empty() || theRadius < 0.)
+ return;
+
+ GeomAlgoAPI_MapShapesAndAncestors aMapVE(theBaseWire, GeomAPI_Shape::VERTEX,
+ GeomAPI_Shape::EDGE);
+
+ for (ListOfShape::const_iterator aVIt = theFilletVertices.begin();
+ aVIt != theFilletVertices.end(); ++aVIt) {
+ // get edges to perform fillet
+ MapShapeToShapes::const_iterator aVE = aMapVE.map().find(*aVIt);
+ if (aVE == aMapVE.map().end())
+ continue;
+ ListOfShape anEdges;
+ for (SetOfShapes::const_iterator aEIt = aVE->second.begin();
+ aEIt != aVE->second.end(); ++aEIt) {
+ ListOfShape aNewEdges;
+ modified(*aEIt, aNewEdges);
+ if (aNewEdges.empty())
+ anEdges.push_back(*aEIt);
+ else
+ anEdges.insert(anEdges.end(), aNewEdges.begin(), aNewEdges.end());
+ }
+
+ GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+ if (!aPlane)
+ return; // non-planar edges
+
+ TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.front()->impl<TopoDS_Shape>());
+ TopoDS_Edge anEdge2 = TopoDS::Edge(anEdges.back()->impl<TopoDS_Shape>());
+
+ // create fillet builder
+ GEOMImpl_Fillet1d aFilletBuilder(anEdge1, anEdge2, aPlane->impl<gp_Pln>());
+ if (!aFilletBuilder.Perform(theRadius))
+ return; // fillet is failed, no way to continue
+
+ GeomPointPtr aPoint = aVE->first->vertex()->point();
+ TopoDS_Edge aFilletEdge = aFilletBuilder.Result(aPoint->impl<gp_Pnt>(), anEdge1, anEdge2);
+
+ // store modified shapes
+ myGenerated[aVE->first].push_back(convert(aFilletEdge));
+ SetOfShapes::const_iterator aEIt = aVE->second.begin();
+ myModified[*aEIt].clear();
+ myModified[*aEIt].push_back(convert(anEdge1));
+ myModified[*(++aEIt)].clear();
+ myModified[*aEIt].push_back(convert(anEdge2));
+ }
+
+ // compose a new wire
+ TopoDS_Wire aNewWire;
+ BRep_Builder aBuilder;
+ aBuilder.MakeWire(aNewWire);
+ GeomWirePtr aBaseWire = theBaseWire->wire();
+ GeomAPI_WireExplorer aWExp(aBaseWire);
+ GeomShapePtr aBaseFirstEdge = aWExp.current();
+ for (; aWExp.more(); aWExp.next()) {
+ ListOfShape aNewEdges;
+ modified(aWExp.current(), aNewEdges);
+ if (aNewEdges.empty())
+ aNewEdges.push_back(aWExp.current());
+ for (ListOfShape::iterator anIt = aNewEdges.begin(); anIt != aNewEdges.end(); ++anIt)
+ aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
+ }
+ for (MapModified::iterator aGenIt = myGenerated.begin(); aGenIt != myGenerated.end(); ++aGenIt) {
+ for (ListOfShape::iterator anIt = aGenIt->second.begin(); anIt != aGenIt->second.end(); ++anIt)
+ aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
+ }
+ // fix the wire connectivity
+ ShapeFix_Wire aFixWire;
+ aFixWire.Load(aNewWire);
+ aFixWire.ClosedWireMode() = aBaseWire->isClosed();
+ aFixWire.FixReorder();
+ aNewWire = aFixWire.WireAPIMake();
+ if (aNewWire.IsNull())
+ return;
+
+ // update the map of modified shapes, because the edges are changed by ShapeFix
+ for (BRepTools_WireExplorer anExp(aNewWire); anExp.More(); anExp.Next()) {
+ GeomEdgePtr aCurrent(new GeomAPI_Edge);
+ aCurrent->setImpl(new TopoDS_Edge(anExp.Current()));
+ substituteNewEdge(aCurrent, myGenerated);
+ substituteNewEdge(aCurrent, myModified);
+ }
+
+ // rebuild the wire once again to get the first edge of fillet wire correspond
+ // to the first edge of original wire
+ TopoDS_Edge aFirstEdge = TopoDS::Edge(aBaseFirstEdge->impl<TopoDS_Shape>());
+ ListOfShape aNewEdges;
+ modified(aBaseFirstEdge, aNewEdges);
+ if (!aNewEdges.empty())
+ aFirstEdge = TopoDS::Edge(aNewEdges.front()->impl<TopoDS_Shape>());
+ TopTools_ListOfShape aKeptForEnd;
+ BRepTools_WireExplorer aNewExp(aNewWire);
+ for (; aNewExp.More(); aNewExp.Next())
+ if (aNewExp.Current().IsEqual(aFirstEdge))
+ break;
+ if (aNewExp.More()) {
+ TopoDS_Wire aReorderedWire;
+ aBuilder.MakeWire(aReorderedWire);
+ for (; aNewExp.More(); aNewExp.Next())
+ aBuilder.Add(aReorderedWire, aNewExp.Current());
+ for (aNewExp.Init(aNewWire); aNewExp.More(); aNewExp.Next()) {
+ if (aNewExp.Current().IsEqual(aFirstEdge))
+ break;
+ aBuilder.Add(aReorderedWire, aNewExp.Current());
+ }
+ aNewWire = aReorderedWire;
+ }
+
+ std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+ aShape->setImpl(new TopoDS_Shape(aNewWire));
+ myModified[theBaseWire].push_back(aShape);
+
+ setShape(aShape);
+ setDone(true);
+}
+
+void GeomAlgoAPI_Fillet1D::generated(const GeomShapePtr theOldShape,
+ ListOfShape& theNewShapes)
+{
+ MapModified::iterator aFound = myGenerated.find(theOldShape);
+ if (aFound != myGenerated.end())
+ theNewShapes = aFound->second;
+}
+
+void GeomAlgoAPI_Fillet1D::modified(const GeomShapePtr theOldShape,
+ ListOfShape& theNewShapes)
+{
+ MapModified::iterator aFound = myModified.find(theOldShape);
+ if (aFound != myModified.end())
+ theNewShapes = aFound->second;
+}
--- /dev/null
+// Copyright (C) 2020 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_Fillet1D_H_
+#define GeomAlgoAPI_Fillet1D_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+#include <GeomAPI_Shape.h>
+
+/// \class GeomAlgoAPI_Fillet1D
+/// \ingroup DataAlgo
+/// \brief Perform fillet on vertices of a wire
+class GeomAlgoAPI_Fillet1D : public GeomAlgoAPI_MakeShape
+{
+ typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator> MapModified;
+
+public:
+ /// Run fillet operation on a set of vertices with fixed radius.
+ /// \param theBaseWire a changing Wire
+ /// \param theFilletVertices list of edges the fillet is performed on
+ /// \param theFilletRadius radius of the fillet
+ GEOMALGOAPI_EXPORT GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
+ const ListOfShape& theFilletVertices,
+ const double theFilletRadius);
+
+ /// \return the list of shapes generated from the shape \a theShape.
+ /// \param[in] theOldShape base shape.
+ /// \param[out] theNewShapes shapes generated from \a theShape. Does not cleared!
+ GEOMALGOAPI_EXPORT virtual void generated(const GeomShapePtr theOldShape,
+ ListOfShape& theNewShapes);
+
+ /// \return the list of shapes modified from the shape \a theShape.
+ /// \param[in] theOldShape base shape.
+ /// \param[out] theNewShapes shapes modified from \a theShape. Does not cleared!
+ GEOMALGOAPI_EXPORT virtual void modified(const GeomShapePtr theOldShape,
+ ListOfShape& theNewShapes);
+
+private:
+ /// Perform 1d-fillet on wire
+ /// \param theBaseWire a changing wire
+ /// \param theFilletVertices list of vertices of filler
+ /// \param theRadius fillet radius
+ void build(const GeomShapePtr& theBaseWire,
+ const ListOfShape& theFilletVertices,
+ const double theRadius);
+
+private:
+ MapModified myGenerated;
+ MapModified myModified;
+};
+
+#endif
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRepClass_FaceClassifier.hxx>
#include <BRepLib_CheckCurveOnSurface.hxx>
+#include <BRepLProp.hxx>
#include <BOPAlgo_Builder.hxx>
return anOuterWire;
}
+//==================================================================================================
+static bool boundaryOfEdge(const std::shared_ptr<GeomAPI_Edge> theEdge,
+ const std::shared_ptr<GeomAPI_Vertex> theVertex,
+ double& theParam)
+{
+ GeomPointPtr aPoint = theVertex->point();
+ GeomPointPtr aFirstPnt = theEdge->firstPoint();
+ double aFirstPntTol = theEdge->firstPointTolerance();
+ GeomPointPtr aLastPnt = theEdge->lastPoint();
+ double aLastPntTol = theEdge->lastPointTolerance();
+
+ double aFirst, aLast;
+ theEdge->getRange(aFirst, aLast);
+
+ bool isFirst = aPoint->distance(aFirstPnt) <= aFirstPntTol;
+ bool isLast = aPoint->distance(aLastPnt) <= aLastPntTol;
+ if (isFirst)
+ theParam = aFirst;
+ else if (isLast)
+ theParam = aLast;
+
+ return isFirst != isLast;
+}
+
+bool GeomAlgoAPI_ShapeTools::isTangent(const std::shared_ptr<GeomAPI_Edge> theEdge1,
+ const std::shared_ptr<GeomAPI_Edge> theEdge2,
+ const std::shared_ptr<GeomAPI_Vertex> theTgPoint)
+{
+ double aParE1 = 0, aParE2 = 0;
+ if (!boundaryOfEdge(theEdge1, theTgPoint, aParE1) ||
+ !boundaryOfEdge(theEdge2, theTgPoint, aParE2))
+ return false;
+
+ BRepAdaptor_Curve aC1(theEdge1->impl<TopoDS_Edge>());
+ BRepAdaptor_Curve aC2(theEdge2->impl<TopoDS_Edge>());
+ return BRepLProp::Continuity(aC1, aC2, aParE1, aParE2) >= GeomAbs_G1;
+}
+
//==================================================================================================
bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
const std::shared_ptr<GeomAPI_Face> theFace)
GEOMALGOAPI_EXPORT static
std::shared_ptr<GeomAPI_Shape> getFaceOuterWire(const std::shared_ptr<GeomAPI_Shape> theFace);
+ /// \return \c true if edges are tangent in the specified point
+ GEOMALGOAPI_EXPORT static bool isTangent(const std::shared_ptr<GeomAPI_Edge> theEdge1,
+ const std::shared_ptr<GeomAPI_Edge> theEdge2,
+ const std::shared_ptr<GeomAPI_Vertex> theTgPoint);
+
/// \return true if edge is parallel to face.
GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
const std::shared_ptr<GeomAPI_Face> theFace);
SET(PROJECT_HEADERS
GeomAlgoImpl.h
GEOMAlgo_Splitter.hxx
+ GEOMImpl_Fillet1d.hxx
)
SET(PROJECT_SOURCES
GEOMAlgo_Splitter.cxx
+ GEOMImpl_Fillet1d.cxx
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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
+//
+
+// File : GEOMImpl_Fillet1d.cxx
+// Module : GEOMImpl
+
+#include "GEOMImpl_Fillet1d.hxx"
+
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <ElCLib.hxx>
+#include <ElSLib.hxx>
+#include <gp_Circ.hxx>
+#include <Geom2d_Line.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <Geom2dAPI_InterCurveCurve.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <GeomProjLib.hxx>
+#include <Geom_Circle.hxx>
+#include <Precision.hxx>
+#include <TColStd_ListIteratorOfListOfReal.hxx>
+#include <IntRes2d_IntersectionSegment.hxx>
+#include <TopExp.hxx>
+
+#include <Standard_NotImplemented.hxx>
+
+
+/**
+ * This function returns Standard_True if it is possible to divide edge, i.e.
+ * if one parameter either start or end one is inside the edge. This function
+ * is used in the method GEOMImpl_Fillet1d::Result.
+ *
+ * \param theEdge the edge
+ * \param theStart the start parameter
+ * \param theEnd the end parameter
+ * \return Standard_True if it is possible to split edge;
+ * Standard_False otherwise.
+ */
+static Standard_Boolean IsDivideEdge(const TopoDS_Edge &theEdge,
+ const Standard_Real theStart,
+ const Standard_Real theEnd)
+{
+ Standard_Real aFirst;
+ Standard_Real aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
+ gp_Pnt aPStart = aCurve->Value(theStart);
+ gp_Pnt aPEnd = aCurve->Value(theEnd);
+ TopoDS_Vertex aVFirst = TopExp::FirstVertex(theEdge);
+ TopoDS_Vertex aVLast = TopExp::LastVertex(theEdge);
+ Standard_Real aTolFirst = BRep_Tool::Tolerance(aVFirst);
+ Standard_Real aTolLast = BRep_Tool::Tolerance(aVLast);
+ Standard_Real aTolConf = Precision::Confusion();
+ gp_Pnt aPFirst = BRep_Tool::Pnt(aVFirst);
+ gp_Pnt aPLast = BRep_Tool::Pnt(aVLast);
+ Standard_Real aDistSF = aPStart.Distance(aPFirst);
+ Standard_Real aDistSL = aPStart.Distance(aPLast);
+ Standard_Real aDistEF = aPEnd.Distance(aPFirst);
+ Standard_Real aDistEL = aPEnd.Distance(aPLast);
+ Standard_Boolean isSplit = Standard_True;
+
+ if (aDistSF <= aTolFirst + aTolConf ||
+ aDistSL <= aTolLast + aTolConf) {
+ if (aDistEF <= aTolFirst + aTolConf ||
+ aDistEL <= aTolLast + aTolConf) {
+
+ isSplit = Standard_False;
+ // in this case the original edge is thrown, and distance (gap) from new arc end
+ // to a vertex of original wire can reach (aVertexTolerance + Precision::Confusion()).
+ // Resulting wire is fixed (Mantis issue 0023411) in GEOMImpl_Fillet1dDriver::MakeFillet()
+ }
+ }
+
+ return isSplit;
+}
+
+/**
+ * class GEOMImpl_Fillet1d
+ */
+
+//=======================================================================
+//function : Constructor
+//purpose :
+//=======================================================================
+GEOMImpl_Fillet1d::GEOMImpl_Fillet1d(const TopoDS_Edge& theEdge1,
+ const TopoDS_Edge& theEdge2,
+ const gp_Pln& thePlane)
+: myEdgesExchnged( Standard_False )
+{
+ myPlane = new Geom_Plane(thePlane);
+
+ BRepAdaptor_Curve aBAC1(theEdge1);
+ BRepAdaptor_Curve aBAC2(theEdge2);
+ if (aBAC1.GetType() < aBAC2.GetType())
+ { // first curve must be more complicated
+ myEdge1 = theEdge2;
+ myEdge2 = theEdge1;
+ myEdgesExchnged = Standard_True;
+ }
+ else
+ {
+ myEdge1 = theEdge1;
+ myEdge2 = theEdge2;
+ }
+
+ Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(myEdge1, myStart1, myEnd1);
+ Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(myEdge2, myStart2, myEnd2);
+
+ myCurve1 = GeomProjLib::Curve2d(aCurve1, myStart1, myEnd1, myPlane);
+ myCurve2 = GeomProjLib::Curve2d(aCurve2, myStart2, myEnd2, myPlane);
+
+ while (myCurve1->IsPeriodic() && myStart1 >= myEnd1)
+ myEnd1 += myCurve1->Period();
+ while (myCurve2->IsPeriodic() && myStart2 >= myEnd2)
+ myEnd2 += myCurve2->Period();
+
+ if (aBAC1.GetType() == aBAC2.GetType())
+ {
+ if (myEnd2 - myStart2 < myEnd1 - myStart1)
+ { // first curve must be parametrically shorter
+ TopoDS_Edge anEdge = myEdge1;
+ myEdge1 = myEdge2;
+ myEdge2 = anEdge;
+ Handle(Geom2d_Curve) aCurve = myCurve1;
+ myCurve1 = myCurve2;
+ myCurve2 = aCurve;
+ Standard_Real a = myStart1;
+ myStart1 = myStart2;
+ myStart2 = a;
+ a = myEnd1;
+ myEnd1 = myEnd2;
+ myEnd2 = a;
+ myEdgesExchnged = Standard_True;
+ }
+ }
+}
+
+//=======================================================================
+//function : isRadiusIntersected
+//purpose : local function
+//=======================================================================
+static Standard_Boolean isRadiusIntersected(const Handle(Geom2d_Curve)& theCurve,
+ const gp_Pnt2d theStart,
+ const gp_Pnt2d theEnd,
+ const Standard_Boolean theStartConnected)
+{
+ const Standard_Real aTol = Precision::Confusion();
+ const Standard_Real anAngTol = Precision::Angular();
+ Handle(Geom2d_Line) aRadiusLine = new Geom2d_Line (theStart, gp_Dir2d(gp_Vec2d(theStart, theEnd)));
+ Geom2dAPI_InterCurveCurve anInter (theCurve, aRadiusLine, aTol);
+ Standard_Integer a;
+ gp_Pnt2d aPoint;
+ for(a = anInter.NbPoints(); a > 0; a--)
+ {
+ aPoint = anInter.Point(a);
+ if ( aPoint.Distance(theStart) < aTol && !theStartConnected )
+ return Standard_True;
+ if (aPoint.Distance(theEnd) < aTol * 200)
+ return Standard_True;
+ if (gp_Vec2d(aPoint, theStart).IsOpposite(gp_Vec2d(aPoint, theEnd), anAngTol))
+ return Standard_True;
+ }
+ Handle(Geom2d_Curve) aCurve;
+ for(a = anInter.NbSegments(); a > 0; a--)
+ {
+ // Porting to DEV version of OCCT 10.02.2017 BEGIN
+ Standard_NotImplemented::Raise("The treatment of tangential intersection is not implemented");
+ // Porting to DEV version of OCCT 10.02.2017 END
+ }
+ return Standard_False;
+}
+
+
+//=======================================================================
+//function : fillPoint
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1d::fillPoint(GEOMImpl_Fillet1dPoint* thePoint)
+{
+ gp_Pnt2d aPoint;
+ gp_Vec2d aVec;
+ const Standard_Real aTol = Precision::Confusion();
+ myCurve1->D1(thePoint->GetParam(), aPoint, aVec);
+ if (aVec.SquareMagnitude() < aTol)
+ return;
+
+ gp_Vec2d aPerp(((myStartSide)?-1:1) * aVec.Y(), ((myStartSide)?1:-1) * aVec.X());
+ aPerp.Normalize();
+ aPerp.Multiply(myRadius);
+ gp_Pnt2d aCenter = aPoint.Translated(aPerp);
+ thePoint->SetCenter(aCenter);
+
+ // on the intersection point
+ Standard_Boolean aValid = Standard_True;
+ Geom2dAPI_ProjectPointOnCurve aProjInt(aPoint, myCurve2);
+ if (aProjInt.NbPoints() && aPoint.Distance(aProjInt.NearestPoint()) < aTol)
+ aValid = Standard_False;
+ else
+ aValid = !isRadiusIntersected(myCurve2, aPoint, aCenter, Standard_True);
+
+ Geom2dAPI_ProjectPointOnCurve aProj(aCenter, myCurve2);
+ Standard_Integer a, aNB = aProj.NbPoints();
+ for(a = aNB; a > 0; a--)
+ {
+ if (aPoint.Distance(aProj.Point(a)) < aTol)
+ continue;
+
+ Standard_Boolean aValid2 = aValid;
+ if (aValid2)
+ aValid2 = !isRadiusIntersected(myCurve1, aCenter, aProj.Point(a), Standard_False);
+
+ // checking the right parameter
+ Standard_Real aParam = aProj.Parameter(a);
+ while(myCurve2->IsPeriodic() && aParam < myStart2)
+ aParam += myCurve2->Period();
+
+ thePoint->AddValue(aProj.Distance(a) * aProj.Distance(a) - myRadius * myRadius,
+ (aParam >= myStart2 && aParam <= myEnd2 && aValid2));
+ if (fabs(fabs(aProj.Distance(a)) - myRadius) < aTol)
+ thePoint->SetParam2(aParam);
+ }
+}
+
+//=======================================================================
+//function : fillDiff
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1d::fillDiff(GEOMImpl_Fillet1dPoint* thePoint, Standard_Real theDiffStep, Standard_Boolean theFront)
+{
+ GEOMImpl_Fillet1dPoint* aDiff =
+ new GEOMImpl_Fillet1dPoint(thePoint->GetParam() + (theFront?(theDiffStep):(-theDiffStep)));
+ fillPoint(aDiff);
+ if (!thePoint->ComputeDifference(aDiff))
+ {
+ aDiff->SetParam(thePoint->GetParam() + (theFront?(-theDiffStep):(theDiffStep)));
+ fillPoint(aDiff);
+ thePoint->ComputeDifference(aDiff);
+ }
+ delete aDiff;
+}
+
+//=======================================================================
+//function : Perform
+//purpose :
+//=======================================================================
+Standard_Boolean GEOMImpl_Fillet1d::Perform(const Standard_Real theRadius)
+{
+ myDegreeOfRecursion = 0;
+ myResultParams.Clear();
+ myResultOrientation.Clear();
+
+ Standard_Integer aNBSteps = 100;
+ Geom2dAdaptor_Curve aGAC(myCurve1);
+ switch (aGAC.GetType())
+ {
+ case GeomAbs_Line:
+ aNBSteps = 2;
+ break;
+ case GeomAbs_Circle:
+ aNBSteps = 4;
+ break;
+ case GeomAbs_Ellipse:
+ aNBSteps = 5;
+ break;
+ case GeomAbs_BezierCurve:
+ case GeomAbs_BSplineCurve:
+ aNBSteps = 2 + aGAC.Degree() * aGAC.NbPoles();
+ break;
+ default: // unknown: maximum
+ aNBSteps = 100;
+ }
+
+ myRadius = theRadius;
+
+ // Compute the intervals.
+ const Standard_Real aTol = Precision::Confusion();
+ Geom2dAPI_InterCurveCurve anAPIInter(myCurve1, myCurve2, aTol);
+ const Geom2dInt_GInter &anInter = anAPIInter.Intersector();
+ Standard_Integer aNb = anInter.NbPoints();
+ Standard_Integer i;
+ TColStd_ListOfReal aParams;
+ TColStd_ListIteratorOfListOfReal anIter;
+
+ // Treat intersection points.
+ for(i = 1; i <= aNb; i++) {
+ const IntRes2d_IntersectionPoint &aPoint = anInter.Point(i);
+ Standard_Real aParam = aPoint.ParamOnFirst();
+
+ // Adjust parameter on periodic curve.
+ if (myCurve1->IsPeriodic()) {
+ aParam = ElCLib::InPeriod
+ (aParam, myStart1, myStart1 + myCurve1->Period());
+ }
+
+ if (aParam > myStart1 + aTol && aParam < myEnd1 - aTol) {
+ // Add the point in the list in increasing order.
+ for(anIter.Initialize(aParams); anIter.More(); anIter.Next()) {
+ if (anIter.Value() > aParam) {
+ aParams.InsertBefore(aParam, anIter);
+ break;
+ }
+ }
+
+ if (!anIter.More()) {
+ aParams.Append(aParam);
+ }
+ }
+ }
+
+ // Treat intersection segments.
+ aNb = anInter.NbSegments();
+
+ for(i = 1; i <= aNb; i++) {
+ const IntRes2d_IntersectionSegment &aSegment = anInter.Segment(i);
+
+ if (aSegment.HasFirstPoint() && aSegment.HasLastPoint()) {
+ Standard_Real aParam1 = aSegment.FirstPoint().ParamOnFirst();
+ Standard_Real aParam2 = aSegment.LastPoint().ParamOnFirst();
+
+ // Adjust parameters on periodic curve.
+ if (myCurve1->IsPeriodic()) {
+ ElCLib::AdjustPeriodic(myStart1, myStart1 + myCurve1->Period(),
+ aTol, aParam1, aParam2);
+ }
+
+ if (aParam1 > myStart1 + aTol && aParam1 < myEnd1 - aTol &&
+ aParam2 > myStart1 + aTol && aParam2 < myEnd1 - aTol) {
+ // Add the point in the list in increasing order.
+ const Standard_Real aParam = 0.5*(aParam1 + aParam2);
+
+ for(anIter.Initialize(aParams); anIter.More(); anIter.Next()) {
+ if (anIter.Value() > aParam) {
+ aParams.InsertBefore(aParam, anIter);
+ break;
+ }
+ }
+
+ if (!anIter.More()) {
+ aParams.Append(aParam);
+ }
+ }
+ }
+ }
+
+ // Add start and end parameters to the list.
+ aParams.Prepend(myStart1);
+ aParams.Append(myEnd1);
+ anIter.Initialize(aParams);
+
+ // Perform each interval.
+ Standard_Real aStart = anIter.Value();
+
+ for (anIter.Next(); anIter.More(); anIter.Next()) {
+ const Standard_Real anEnd = anIter.Value();
+
+ // Perform the interval.
+ performInterval(aStart, anEnd, aNBSteps);
+ aStart = anEnd;
+ }
+
+ if (myResultParams.Extent())
+ return Standard_True;
+
+ return Standard_False;
+}
+
+//=======================================================================
+//function : performInterval
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1d::performInterval(const Standard_Real theStart,
+ const Standard_Real theEnd,
+ const Standard_Integer theNBSteps)
+{
+ Standard_Real aParam, aStep, aDStep;
+ aStep = (theEnd - theStart) / theNBSteps;
+ aDStep = aStep/1000.;
+
+ Standard_Integer aCycle;
+ for(aCycle = 2, myStartSide = Standard_False; aCycle; myStartSide = !myStartSide, aCycle--)
+ {
+ GEOMImpl_Fillet1dPoint *aLeft = NULL, *aRight = NULL;
+
+ for(aParam = theStart + aStep; aParam < theEnd || fabs(theEnd - aParam) < Precision::Confusion(); aParam += aStep)
+ {
+ if (!aLeft)
+ {
+ aLeft = new GEOMImpl_Fillet1dPoint(aParam - aStep);
+ fillPoint(aLeft);
+ fillDiff(aLeft, aDStep, Standard_True);
+ }
+
+ aRight = new GEOMImpl_Fillet1dPoint(aParam);
+ fillPoint(aRight);
+ fillDiff(aRight, aDStep, Standard_False);
+
+ aLeft->FilterPoints(aRight);
+ performNewton(aLeft, aRight);
+
+ delete aLeft;
+ aLeft = aRight;
+ }
+ delete aLeft;
+ }
+}
+
+//=======================================================================
+//function : processPoint
+//purpose :
+//=======================================================================
+Standard_Boolean GEOMImpl_Fillet1d::processPoint(GEOMImpl_Fillet1dPoint* theLeft,
+ GEOMImpl_Fillet1dPoint* theRight,
+ Standard_Real theParameter)
+{
+ if (theParameter >= theLeft->GetParam() && theParameter < theRight->GetParam())
+ {
+ Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
+ if (theParameter - theLeft->GetParam() < aDX / 100.)
+ {
+ theParameter = theLeft->GetParam() + aDX / 100.;
+ }
+ if (theRight->GetParam() - theParameter < aDX / 100.)
+ {
+ theParameter = theRight->GetParam() - aDX / 100.;
+ }
+
+ // Protection on infinite loop.
+ myDegreeOfRecursion++;
+ Standard_Real diffx = 0.001 * aDX;
+ if (myDegreeOfRecursion > 1000)
+ {
+ diffx *= 10.0;
+ if (myDegreeOfRecursion > 10000)
+ {
+ diffx *= 10.0;
+ if (myDegreeOfRecursion > 100000)
+ {
+ return Standard_True;
+ }
+ }
+ }
+
+ GEOMImpl_Fillet1dPoint* aPoint1 = theLeft->Copy();
+ GEOMImpl_Fillet1dPoint* aPoint2 = new GEOMImpl_Fillet1dPoint(theParameter);
+ fillPoint(aPoint2);
+ fillDiff(aPoint2, diffx, Standard_True);
+
+ aPoint1->FilterPoints(aPoint2);
+ performNewton(aPoint1, aPoint2);
+ aPoint2->FilterPoints(theRight);
+ performNewton(aPoint2, theRight);
+
+ delete aPoint1;
+ delete aPoint2;
+ return Standard_True;
+ }
+
+ return Standard_False;
+}
+
+//=======================================================================
+//function : performNewton
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1d::performNewton(GEOMImpl_Fillet1dPoint* theLeft,
+ GEOMImpl_Fillet1dPoint* theRight)
+{
+ Standard_Integer a;
+ // check the left: if this is solution store it and remove it from the list of researching points of theLeft
+ a = theLeft->HasSolution(myRadius);
+ if (a)
+ {
+ if (theLeft->IsValid(a))
+ {
+ myResultParams.Append(theLeft->GetParam());
+ myResultOrientation.Append(myStartSide);
+ }
+ return;
+ }
+
+ Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
+ if ( aDX < Precision::Confusion() / 1000000.)
+ {
+ a = theRight->HasSolution(myRadius);
+ if (a)
+ if (theRight->IsValid(a))
+ {
+ myResultParams.Append(theRight->GetParam());
+ myResultOrientation.Append(myStartSide);
+ }
+ return;
+ }
+
+ for(a = 1; a <= theLeft->GetNBValues(); a++)
+ {
+ Standard_Integer aNear = theLeft->GetNear(a);
+
+ Standard_Real aA = (theRight->GetDiff(aNear) - theLeft->GetDiff(a)) / aDX;
+ Standard_Real aB = theLeft->GetDiff(a) - aA * theLeft->GetParam();
+ Standard_Real aC = theLeft->GetValue(a) - theLeft->GetDiff(a) * theLeft->GetParam() +
+ aA * theLeft->GetParam() * theLeft->GetParam() / 2.0;
+ Standard_Real aDet = aB * aB - 2.0 * aA * aC;
+
+ if ( fabs(aDet) < gp::Resolution() )
+ continue;
+
+ if (fabs(aA) < Precision::Confusion())
+ { // linear case
+ if (fabs(aB) > 10e-20)
+ {
+ Standard_Real aX0 = - aC / aB; // use extremum
+ if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
+ processPoint(theLeft, theRight, aX0);
+ }
+ else
+ {
+ processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+ }
+ }
+ else
+ {
+ if (fabs(aB) > fabs(aDet * 1000000.))
+ { // possible floating point operations accuracy errors
+ processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+ }
+ else
+ {
+ if (aDet > 0)
+ { // two solutions
+ aDet = sqrt(aDet);
+ Standard_Boolean aRes = processPoint(theLeft, theRight, (- aB + aDet) / aA);
+ if (!aRes)
+ aRes = processPoint(theLeft, theRight, (- aB - aDet) / aA);
+ if (!aRes)
+ processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+ }
+ else
+ {
+ Standard_Real aX0 = - aB / aA; // use extremum
+ if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
+ processPoint(theLeft, theRight, aX0);
+ else
+ processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
+ }
+ }
+ }
+ }
+}
+
+//=======================================================================
+//function : Result
+//purpose :
+//=======================================================================
+TopoDS_Edge GEOMImpl_Fillet1d::Result(const gp_Pnt& thePoint,
+ TopoDS_Edge& theEdge1,
+ TopoDS_Edge& theEdge2)
+{
+ TopoDS_Edge aResult;
+ gp_Pnt2d aTargetPoint2d;
+ Standard_Real aX, aY;
+ ElSLib::PlaneParameters(myPlane->Pln().Position(), thePoint, aX, aY);
+ aTargetPoint2d.SetCoord(aX, aY);
+
+ // choose the nearest circle
+ Standard_Real aDistance, aP;
+ GEOMImpl_Fillet1dPoint *aNearest;
+ Standard_Integer a;
+ TColStd_ListIteratorOfListOfReal anIter(myResultParams);
+ for(aNearest = NULL, a = 1; anIter.More(); anIter.Next(), a++)
+ {
+ myStartSide = (myResultOrientation.Value(a)) ? Standard_True : Standard_False;
+ GEOMImpl_Fillet1dPoint *aPoint = new GEOMImpl_Fillet1dPoint(anIter.Value());
+ fillPoint(aPoint);
+ if (!aPoint->HasSolution(myRadius))
+ continue;
+ aP = fabs(aPoint->GetCenter().Distance(aTargetPoint2d) - myRadius);
+ if (!aNearest || aP < aDistance)
+ {
+ aNearest = aPoint;
+ aDistance = aP;
+ }
+ else
+ {
+ delete aPoint;
+ }
+ }
+
+ if (!aNearest)
+ return aResult;
+
+ // create circle edge
+ gp_Pnt aCenter = ElSLib::PlaneValue(aNearest->GetCenter().X(),
+ aNearest->GetCenter().Y(),
+ myPlane->Pln().Position());
+ Handle(Geom_Circle) aCircle =
+ new Geom_Circle(gp_Ax2(aCenter, myPlane->Pln().Axis().Direction()), myRadius);
+ gp_Pnt2d aPoint2d1, aPoint2d2;
+ myCurve1->D0(aNearest->GetParam(), aPoint2d1);
+ myCurve2->D0(aNearest->GetParam2(), aPoint2d2);
+ gp_Pnt aPoint1 = ElSLib::PlaneValue(aPoint2d1.X(), aPoint2d1.Y(), myPlane->Pln().Position());
+ gp_Pnt aPoint2 = ElSLib::PlaneValue(aPoint2d2.X(), aPoint2d2.Y(), myPlane->Pln().Position());
+
+ GeomAPI_ProjectPointOnCurve aProj(thePoint, aCircle);
+ Standard_Real aTarGetParam = aProj.LowerDistanceParameter();
+ gp_Pnt aPointOnCircle = aProj.NearestPoint();
+
+ // Check extrema point manually, because there is a bug in Open CASCADE
+ // in calculation of nearest point to a circle near the parameter 0.0
+ gp_Pnt p0 = ElCLib::Value(0.0, aCircle->Circ());
+ if (p0.Distance(thePoint) < aPointOnCircle.Distance(thePoint))
+ {
+ aTarGetParam = 0.0;
+ aPointOnCircle = p0;
+ }
+
+ aProj.Perform(aPoint1);
+ Standard_Real aParam1 = aProj.LowerDistanceParameter();
+ aProj.Perform(aPoint2);
+ Standard_Real aParam2 = aProj.LowerDistanceParameter();
+ Standard_Boolean aIsOut = ((aParam1 < aTarGetParam && aParam2 < aTarGetParam) ||
+ (aParam1 > aTarGetParam && aParam2 > aTarGetParam));
+ if (aParam1 > aParam2)
+ aIsOut = !aIsOut;
+ BRepBuilderAPI_MakeEdge aBuilder(aCircle->Circ(),
+ aIsOut ? aParam2 : aParam1,
+ aIsOut? aParam1 : aParam2);
+ aResult = aBuilder.Edge();
+
+ // divide edges
+ Standard_Real aStart, anEnd;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(myEdge1, aStart, anEnd);
+ gp_Vec aDir;
+ aCurve->D1(aNearest->GetParam(), aPoint1, aDir);
+
+ gp_Vec aCircleDir;
+ aCircle->D1(aParam1, aPoint1, aCircleDir);
+ if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ aIsOut)
+ aStart = aNearest->GetParam();
+ else
+ anEnd = aNearest->GetParam();
+
+ if (IsDivideEdge(myEdge1, aStart, anEnd))
+ {
+ //Divide edge
+ BRepBuilderAPI_MakeEdge aDivider1(aCurve, aStart, anEnd);
+ if (myEdgesExchnged)
+ theEdge2 = aDivider1.Edge();
+ else
+ theEdge1 = aDivider1.Edge();
+ }
+
+ aCurve = BRep_Tool::Curve(myEdge2, aStart, anEnd);
+ aCurve->D1(aNearest->GetParam2(), aPoint2, aDir);
+
+ aCircle->D1(aParam2, aPoint2, aCircleDir);
+ if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ (!aIsOut))
+ aStart = aNearest->GetParam2();
+ else
+ anEnd = aNearest->GetParam2();
+
+ if (IsDivideEdge(myEdge2, aStart, anEnd))
+ {
+ BRepBuilderAPI_MakeEdge aDivider2(aCurve, aStart, anEnd);
+ if (myEdgesExchnged)
+ theEdge1 = aDivider2.Edge();
+ else
+ theEdge2 = aDivider2.Edge();
+ }
+
+ delete aNearest;
+ return aResult;
+}
+
+//=======================================================================
+//function : AddValue
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1dPoint::AddValue(Standard_Real theValue, Standard_Boolean theValid)
+{
+ Standard_Integer a;
+ for(a = 1; a <= myV.Length(); a++)
+ {
+ if (theValue < myV.Value(a))
+ {
+ myV.InsertBefore(a, theValue);
+ myValid.InsertBefore(a, (Standard_Integer)theValid);
+ return;
+ }
+ }
+ myV.Append(theValue);
+ myValid.Append((Standard_Integer)theValid);
+}
+
+//=======================================================================
+//function : ComputeDifference
+//purpose :
+//=======================================================================
+Standard_Boolean GEOMImpl_Fillet1dPoint::ComputeDifference(GEOMImpl_Fillet1dPoint* thePoint)
+{
+ Standard_Integer a;
+ Standard_Boolean aDiffsSet = (myD.Length() != 0);
+ Standard_Real aDX = thePoint->GetParam() - myParam, aDY;
+ if (thePoint->myV.Length() == myV.Length())
+ { // absolutely the same points
+ for(a = 1; a <= myV.Length(); a++)
+ {
+ aDY = thePoint->myV.Value(a) - myV.Value(a);
+ if ( aDiffsSet )
+ myD.SetValue(a, fabs(aDX) > gp::Resolution() ? (aDY/aDX) : 0);
+ else
+ myD.Append( fabs(aDX) > gp::Resolution() ? (aDY/aDX) : 0);
+ }
+ return Standard_True;
+ }
+ // between the diffeerent points searching for nearest analogs
+ Standard_Integer b;
+ for(a = 1; a <= myV.Length(); a++)
+ {
+ for(b = 1; b <= thePoint->myV.Length(); b++)
+ {
+ if (b == 1 || fabs(thePoint->myV.Value(b) - myV.Value(a)) < fabs(aDY))
+ aDY = thePoint->myV.Value(b) - myV.Value(a);
+ }
+ if (aDiffsSet)
+ {
+ if ( fabs(aDX) > gp::Resolution() && fabs(aDY / aDX) < fabs(myD.Value(a)))
+ myD.SetValue(a, aDY / aDX);
+ else
+ myD.SetValue(a, 0);
+ }
+ else
+ {
+ myD.Append( fabs(aDX) > gp::Resolution() ? aDY/aDX : 0);
+ }
+ }
+
+ return Standard_False;
+}
+
+//=======================================================================
+//function : FilterPoints
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1dPoint::FilterPoints(GEOMImpl_Fillet1dPoint* thePoint)
+{
+ Standard_Integer a, b;
+ TColStd_SequenceOfReal aDiffs;
+ Standard_Real aY, aY2, aDX = thePoint->GetParam() - myParam;
+ for(a = 1; a <= myV.Length(); a++)
+ {
+ // searching for near point from thePoint
+ Standard_Integer aNear = 0;
+ Standard_Real aDiff = aDX * 10000.;
+ aY = myV.Value(a) + myD.Value(a) * aDX;
+ for(b = 1; b <= thePoint->myV.Length(); b++)
+ {
+ // calculate hypothesis value of the Y2 with the constant first and second derivative
+ aY2 = aY + aDX * (thePoint->myD.Value(b) - myD.Value(a)) / 2.0;
+ if (aNear == 0 || fabs(aY2 - thePoint->myV.Value(b)) < fabs(aDiff))
+ {
+ aNear = b;
+ aDiff = aY2 - thePoint->myV.Value(b);
+ }
+ }//for b...
+
+ if (aNear)
+ {
+ if (myV.Value(a) * thePoint->myV.Value(aNear) > 0)
+ {// the same sign at the same sides of the interval
+ if (myV.Value(a) * myD.Value(a) > 0)
+ {
+ if (fabs(myD.Value(a)) > Precision::Confusion())
+ aNear = 0;
+ }
+ else
+ {
+ if (fabs(myV.Value(a)) > fabs(thePoint->myV.Value(aNear)))
+ if (thePoint->myV.Value(aNear) * thePoint->myD.Value(aNear) < 0 &&
+ fabs(thePoint->myD.Value(aNear)) > Precision::Confusion())
+ {
+ aNear = 0;
+ }
+ }
+ }
+ }
+
+ if (aNear)
+ {
+ if (myV.Value(a) * thePoint->myV.Value(aNear) > 0)
+ {
+ if ((myV.Value(a) + myD.Value(a) * aDX) * myV.Value(a) > Precision::Confusion() &&
+ (thePoint->myV.Value(aNear) + thePoint->myD.Value(aNear) * aDX) * thePoint->myV.Value(aNear) > Precision::Confusion())
+ {
+ aNear = 0;
+ }
+ }
+ }
+
+ if (aNear)
+ {
+ if ( fabs(aDX) < gp::Resolution() || fabs(aDiff / aDX) > 1.e+7)
+ {
+ aNear = 0;
+ }
+ }
+
+ if (aNear == 0)
+ { // there is no near: remove it from the list
+ myV.Remove(a);
+ myD.Remove(a);
+ myValid.Remove(a);
+ a--;
+ }
+ else
+ {
+ Standard_Boolean aFound = Standard_False;
+ for(b = 1; b <= myNear.Length(); b++)
+ {
+ if (myNear.Value(b) == aNear)
+ {
+ if (fabs(aDiffs.Value(b)) < fabs(aDiff))
+ { // return this 'near'
+ aFound = Standard_True;
+ myV.Remove(a);
+ myD.Remove(a);
+ myValid.Remove(a);
+ a--;
+ break;
+ }
+ else
+ { // remove the old 'near'
+ myV.Remove(b);
+ myD.Remove(b);
+ myValid.Remove(b);
+ myNear.Remove(b);
+ aDiffs.Remove(b);
+ a--;
+ break;
+ }
+ }
+ }//for b...
+ if (!aFound)
+ {
+ myNear.Append(aNear);
+ aDiffs.Append(aDiff);
+ }
+ }
+ }//for a...
+}
+
+//=======================================================================
+//function : Copy
+//purpose :
+//=======================================================================
+GEOMImpl_Fillet1dPoint* GEOMImpl_Fillet1dPoint::Copy()
+{
+ GEOMImpl_Fillet1dPoint* aCopy = new GEOMImpl_Fillet1dPoint(myParam);
+ Standard_Integer a;
+ for(a = 1; a <= myV.Length(); a++)
+ {
+ aCopy->myV.Append(myV.Value(a));
+ aCopy->myD.Append(myD.Value(a));
+ aCopy->myValid.Append(myValid.Value(a));
+ }
+ return aCopy;
+}
+
+//=======================================================================
+//function : HasSolution
+//purpose :
+//=======================================================================
+Standard_Integer GEOMImpl_Fillet1dPoint::HasSolution(const Standard_Real theRadius)
+{
+ Standard_Integer a;
+ for(a = 1; a <= myV.Length(); a++)
+ {
+ if (fabs(sqrt(fabs(fabs(myV.Value(a)) + theRadius * theRadius)) - theRadius) < Precision::Confusion() / 10.)
+ return a;
+ }
+ return 0;
+}
+
+//=======================================================================
+//function : RemoveSolution
+//purpose :
+//=======================================================================
+void GEOMImpl_Fillet1dPoint::RemoveSolution(Standard_Integer theIndex)
+{
+ myV.Remove(theIndex);
+ myD.Remove(theIndex);
+ myValid.Remove(theIndex);
+ myNear.Remove(theIndex);
+}
--- /dev/null
+// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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
+//
+
+// File : GEOMImpl_Fillet1d.hxx
+// Module : GEOMImpl
+
+#ifndef _GEOMImpl_Fillet1d_HeaderFile
+#define _GEOMImpl_Fillet1d_HeaderFile
+
+#include <TopoDS_Edge.hxx>
+
+#include <Geom_Plane.hxx>
+#include <Geom2d_Curve.hxx>
+
+#include <gp_Pnt.hxx>
+
+#include <TColStd_ListOfReal.hxx>
+#include <TColStd_SequenceOfReal.hxx>
+#include <TColStd_SequenceOfInteger.hxx>
+
+class GEOMImpl_Fillet1dPoint;
+
+/**
+* GEOMImpl_Fillet1d is 1D fillet algorithm on two planar edges with given radius
+*/
+
+class GEOMImpl_Fillet1d
+{
+public:
+ //! Constructor
+ //! The fillet 1D algorithm is initialised by two edges and plane
+ Standard_EXPORT GEOMImpl_Fillet1d(const TopoDS_Edge& theEdge1,
+ const TopoDS_Edge& theEdge2,
+ const gp_Pln& thePlane);
+ //! Makes fillet with given radius
+ //! @returns Standard_True, if at least one result computed
+ Standard_EXPORT Standard_Boolean Perform(const Standard_Real theRadius);
+
+ //! Returns result fillet edge and modified edges as out parameters
+ Standard_EXPORT TopoDS_Edge Result(const gp_Pnt& thePoint, TopoDS_Edge& theEdge1, TopoDS_Edge& theEdge2);
+
+private:
+ //! private methods
+ void performInterval(const Standard_Real theStart,
+ const Standard_Real theEnd,
+ const Standard_Integer theNBSteps);
+ void fillPoint(GEOMImpl_Fillet1dPoint*);
+ void fillDiff(GEOMImpl_Fillet1dPoint*, Standard_Real, Standard_Boolean);
+ void performNewton(GEOMImpl_Fillet1dPoint*, GEOMImpl_Fillet1dPoint*);
+ Standard_Boolean processPoint(GEOMImpl_Fillet1dPoint*, GEOMImpl_Fillet1dPoint*, Standard_Real);
+
+private:
+ //! private fields
+ TopoDS_Edge myEdge1, myEdge2;
+ Handle(Geom_Plane) myPlane;
+ Handle(Geom2d_Curve) myCurve1, myCurve2;
+ Standard_Real myStart1, myEnd1, myStart2, myEnd2, myRadius;
+ TColStd_ListOfReal myResultParams;
+ TColStd_SequenceOfInteger myResultOrientation;
+ Standard_Boolean myStartSide, myEdgesExchnged;
+ Standard_Integer myDegreeOfRecursion;
+};
+
+
+/**
+* GEOMImpl_Fillet1dPoint is an internal class for 1D fillet algorithm
+* to store and compare computed solutions on edges
+*/
+
+class GEOMImpl_Fillet1dPoint
+{
+public:
+ //! Puiblic methods
+
+ //! Constructor
+ Standard_EXPORT GEOMImpl_Fillet1dPoint(Standard_Real theParam)
+ {myParam = theParam;}
+
+ //! Make copy of point
+ //!WARNING: Copies only field values: myParam, myV, myD, myValid
+ Standard_EXPORT GEOMImpl_Fillet1dPoint* Copy(); // warning: this is not the full copy!
+
+ //! Set/Get parameter
+ Standard_EXPORT inline void SetParam(Standard_Real theParam)
+ {myParam = theParam;}
+ Standard_EXPORT inline Standard_Real GetParam() const
+ {return myParam;}
+ Standard_EXPORT inline void SetParam2(const Standard_Real theParam2)
+ {myParam2 = theParam2;}
+ Standard_EXPORT inline Standard_Real GetParam2()
+ { return myParam2 ; }
+
+ //! Returns validity
+ Standard_EXPORT inline Standard_Boolean IsValid(int theIndex)
+ {return (Standard_Boolean)myValid.Value(theIndex);}
+
+ //! Get values
+ Standard_EXPORT inline Standard_Integer GetNBValues() {return myV.Length();}
+ Standard_EXPORT inline Standard_Real GetValue(Standard_Integer theIndex)
+ {return myV.Value(theIndex);}
+ Standard_EXPORT inline Standard_Real GetDiff(Standard_Integer theIndex)
+ {return myD.Value(theIndex);}
+ Standard_EXPORT inline Standard_Integer GetNear(Standard_Integer theIndex)
+ {return myNear.Value(theIndex);}
+
+ //! Set/Get center point
+ Standard_EXPORT inline void SetCenter(const gp_Pnt2d thePoint)
+ {myCenter = thePoint;}
+ Standard_EXPORT inline const gp_Pnt2d GetCenter()
+ {return myCenter;}
+
+ Standard_EXPORT void AddValue(Standard_Real theValue, Standard_Boolean theIsValid);
+
+ //! compute difference between this and given point
+ Standard_EXPORT Standard_Boolean ComputeDifference(GEOMImpl_Fillet1dPoint*);
+ Standard_EXPORT void FilterPoints(GEOMImpl_Fillet1dPoint*);
+
+ //! Checks if point contains solution and returns the index of it if any
+ Standard_EXPORT Standard_Integer HasSolution(Standard_Real theRadius);
+ //! Remove solution by index
+ void RemoveSolution(Standard_Integer theIndex);
+
+private:
+ //! Private fields
+ gp_Pnt2d myCenter;
+ Standard_Real myParam, myParam2;
+ TColStd_SequenceOfReal myV, myD;
+ TColStd_SequenceOfInteger myValid, myNear;
+};
+
+#endif
// Used in INTERFACE_N for create variable and getter
#define DEFINE_ATTRIBUTE(NAME, TYPE, COMMENT) \
COMMENT \
- std::shared_ptr<TYPE> NAME() const { return VAR_NAME(NAME); } \
+ virtual std::shared_ptr<TYPE> NAME() const { return VAR_NAME(NAME); } \
protected: \
std::shared_ptr<TYPE> VAR_NAME(NAME); \
public: