This child result can be restored using **Recover** feature.
-Each feature, result, construction, group, field, parameter can be renamed using *Rename* pop-up menu command.
+Each feature, result, construction, group, field, parameter can be renamed using *Rename* pop-up menu command (hotkey "F2").
.. figure:: /images/popup_menu_object_browser_feature.png
:align: center
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
Test19066.py
Test19115.py
Test19196.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_Vertices_9.py
+ TestFillet1D_Wire_1.py
+ TestFillet1D_Wire_2.py
+ TestFillet1D_Wire_3.py
+ TestFillet1D_Wire_4.py
+ TestFillet1D_Wire_5.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>
+#include <ModelAPI_Events.h>
+
+void sendMessageWithFailedShapes(const ListOfShape& theVertices)
+{
+ std::shared_ptr<ModelAPI_ShapesFailedMessage> aMessage(
+ new ModelAPI_ShapesFailedMessage(Events_Loop::eventByName(EVENT_OPERATION_SHAPES_FAILED)));
+ aMessage->setShapes(theVertices);
+ Events_Loop::loop()->send(aMessage);
+}
+
+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()
+{
+ ListOfShape aWires;
+ MapShapeSubs aVertices;
+ if (!baseShapes(aWires, aVertices))
+ return;
+
+ int aResultIndex = 0;
+ for (ListOfShape::iterator anIt = aWires.begin(); anIt != aWires.end(); ++anIt)
+ if (!performFillet(*anIt, aVertices[*anIt], aResultIndex++))
+ break;
+ removeResults(aResultIndex);
+}
+
+void FeaturesPlugin_Fillet1D::attributeChanged(const std::string& theID)
+{
+ if (theID == CREATION_METHOD()) {
+ // creation method is changed, drop failed vertices and send the message
+ removeResults(0);
+ sendMessageWithFailedShapes(ListOfShape());
+ }
+}
+
+bool FeaturesPlugin_Fillet1D::baseShapes(ListOfShape& theWires, MapShapeSubs& theWireVertices)
+{
+ std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aProcessedWires;
+ std::string aMethod = string(CREATION_METHOD())->value();
+ if (aMethod == CREATION_BY_WIRES()) {
+ AttributeSelectionListPtr aSelList = selectionList(WIRE_LIST_ID());
+
+ 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 wires and fillet vertices stable
+ theWires.push_back(aWire);
+ 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();
+
+ // keep the sequence of wires stable
+ if (aProcessedWires.find(aWire) == aProcessedWires.end()) {
+ theWires.push_back(aWire);
+ aProcessedWires.insert(aWire);
+ }
+
+ 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));
+
+ bool isOk = true;
+ bool isSendMessage = !myFailedVertices.empty();
+ myFailedVertices = aFilletBuilder->failedVertices();
+
+ std::string anError;
+ if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilletBuilder, getKind(), anError)) {
+ isOk = false;
+ // in case of vertices, the fillet completed, send message to highlight them in the viewer
+ isSendMessage = true;
+ bool isAllFailed = myFailedVertices.size() == theVertices.size();
+ setError(anError, isAllFailed);
+ if (isAllFailed)
+ return isOk;
+ }
+
+ if (isSendMessage) {
+ // send message to highlight the failed vertices
+ sendMessageWithFailedShapes(myFailedVertices);
+ }
+
+ 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 isOk;
+}
--- /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();
+
+ /// Called on change of any argument-attribute of this object
+ /// \param theID identifier of changed attribute
+ FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// 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(ListOfShape& theWires, 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);
+
+private:
+ ListOfShape myFailedVertices;
+};
+
+#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 is 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.
<translation>Base shape is not selected.</translation>
</message>
</context>
+
+ <!-- 1D-fillet -->
+ <context>
+ <name>Fillet1D</name>
+ <message>
+ <source>1D-fillet</source>
+ <translation>1D-fillet</translation>
+ </message>
+ <message>
+ <source>Perform fillet on vertices of a wire</source>
+ <translation>Perform fillet on vertices of a wire</translation>
+ </message>
+ <message>
+ <source>Wire has no vertices for fillet.</source>
+ <translation>Wire has no vertices for fillet.</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_wires</name>
+ <message>
+ <source>Wires</source>
+ <translation>Wires</translation>
+ </message>
+ <message>
+ <source>Select wires</source>
+ <translation>Select wires</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Select wires.</translation>
+ </message>
+ <message>
+ <source>Fillet each sharp corner of the wire</source>
+ <translation>Fillet each sharp corner of the wire</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_vertices</name>
+ <message>
+ <source>Vertices</source>
+ <translation>Vertices</translation>
+ </message>
+ <message>
+ <source>Select vertices</source>
+ <translation>Select vertices</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Select vertices on wires.</translation>
+ </message>
+ <message>
+ <source>Fillet the specified corners of the wire</source>
+ <translation>Fillet the specified corners of the wire</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_vertices:FeaturesPlugin_ValidatorFillet1DSelection</name>
+ <message>
+ <source>Selected vertex is not a wire corner</source>
+ <translation>Selected vertex is not a wire corner</translation>
+ </message>
+ <message>
+ <source>Selected shape is not a vertex</source>
+ <translation>Selected shape is not a vertex</translation>
+ </message>
+ <message>
+ <source>Selected vertex does not exist in the wire</source>
+ <translation>Selected vertex does not exist in the wire</translation>
+ </message>
+ <message>
+ <source>Vertex should be shared between 2 edges exactly</source>
+ <translation>Vertex should be shared between 2 edges exactly</translation>
+ </message>
+ <message>
+ <source>Error: Edges are not planar</source>
+ <translation>Error: Edges are not planar</translation>
+ </message>
+ <message>
+ <source>Error: Edges are tangent</source>
+ <translation>Error: Edges are tangent</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:creation_method</name>
+ <message>
+ <source>Wires</source>
+ <translation>Wires</translation>
+ </message>
+ <message>
+ <source>Vertices</source>
+ <translation>Vertices</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:radius</name>
+ <message>
+ <source>Radius</source>
+ <translation>Radius</translation>
+ </message>
+ <message>
+ <source>Fillet radius</source>
+ <translation>Fillet radius</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Specify fillet radius.</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:radius:GeomValidators_Positive</name>
+ <message>
+ <source>Value is too small.</source>
+ <translation>Value is too small.</translation>
+ </message>
+ </context>
+
</TS>
<source>Fillet</source>
<translation>Congé</translation>
</message>
+ <message>
+ <source>1D-fillet</source>
+ <translation>1D-congé</translation>
+ </message>
<message>
<source>Fuse</source>
<translation>Fusionner</translation>
</message>
</context>
+ <!-- 1D-fillet -->
+ <context>
+ <name>Fillet1D</name>
+ <message>
+ <source>1D-fillet</source>
+ <translation>1D-congé</translation>
+ </message>
+ <message>
+ <source>Perform fillet on vertices of a wire</source>
+ <translation>Effectuer un congé sur les sommets d'un contour</translation>
+ </message>
+ <message>
+ <source>Wire has no vertices for fillet.</source>
+ <translation>Le contour n'a pas de sommet pour le congé.</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_wires</name>
+ <message>
+ <source>Wires</source>
+ <translation>Contours</translation>
+ </message>
+ <message>
+ <source>Select wires</source>
+ <translation>Sélectionnez les contours</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Sélectionnez les contours.</translation>
+ </message>
+ <message>
+ <source>Fillet each sharp corner of the wire</source>
+ <translation>Raccordez chaque coin pointu du contour</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_vertices</name>
+ <message>
+ <source>Vertices</source>
+ <translation>Sommets</translation>
+ </message>
+ <message>
+ <source>Select vertices</source>
+ <translation>Sélectionnez les sommets</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Sélectionnez des sommets sur les contours.</translation>
+ </message>
+ <message>
+ <source>Fillet the specified corners of the wire</source>
+ <translation>Raccorder les coins spécifiés du contour</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_vertices:FeaturesPlugin_ValidatorFillet1DSelection</name>
+ <message>
+ <source>Selected vertex is not a wire corner</source>
+ <translation>Le sommet sélectionné n'est pas un coin de contour</translation>
+ </message>
+ <message>
+ <source>Selected shape is not a vertex</source>
+ <translation>La forme sélectionnée n'est pas un sommet</translation>
+ </message>
+ <message>
+ <source>Selected vertex does not exist in the wire</source>
+ <translation>Le sommet sélectionné n'existe pas dans le contour</translation>
+ </message>
+ <message>
+ <source>Vertex should be shared between 2 edges exactly</source>
+ <translation>Le sommet doit être partagé entre 2 bords exactement</translation>
+ </message>
+ <message>
+ <source>Error: Edges are not planar</source>
+ <translation>Erreur: les arêtes ne sont pas planes</translation>
+ </message>
+ <message>
+ <source>Error: Edges are tangent</source>
+ <translation>Erreur: les bords sont tangents</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:creation_method</name>
+ <message>
+ <source>Wires</source>
+ <translation>Contours</translation>
+ </message>
+ <message>
+ <source>Vertices</source>
+ <translation>Sommets</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:radius</name>
+ <message>
+ <source>Radius</source>
+ <translation>Rayon</translation>
+ </message>
+ <message>
+ <source>Fillet radius</source>
+ <translation>Rayon de congé</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Spécifiez le rayon du congé.</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:radius:GeomValidators_Positive</name>
+ <message>
+ <source>Value is too small.</source>
+ <translation>La valeur est trop petite.</translation>
+ </message>
+ </context>
+
<!-- Fuse -->
<context>
<name>Fuse</name>
<translation>Ошибка: не все выбранные объекты являются подэлементами твердых тел.</translation>
</message>
</context>
+
+ <!-- 1D-fillet -->
+ <context>
+ <name>Fillet1D</name>
+ <message>
+ <source>1D-fillet</source>
+ <translation>1D-сглаживание</translation>
+ </message>
+ <message>
+ <source>Perform fillet on vertices of a wire</source>
+ <translation>Выполнить сглаживание в узлах контура</translation>
+ </message>
+ <message>
+ <source>Wire has no vertices for fillet.</source>
+ <translation>Контур не имеет узлов, подходящих для сглаживания.</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_wires</name>
+ <message>
+ <source>Wires</source>
+ <translation>Контуры</translation>
+ </message>
+ <message>
+ <source>Select wires</source>
+ <translation>Выберите контуры</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Выберите контуры.</translation>
+ </message>
+ <message>
+ <source>Fillet each sharp corner of the wire</source>
+ <translation>Сгладить все острые углы контура</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_vertices</name>
+ <message>
+ <source>Vertices</source>
+ <translation>Узлы</translation>
+ </message>
+ <message>
+ <source>Select vertices</source>
+ <translation>Выберите узлы</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Выберите острые углы на контуре.</translation>
+ </message>
+ <message>
+ <source>Fillet the specified corners of the wire</source>
+ <translation>Сгладить выбранные узлы контура</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:main_vertices:FeaturesPlugin_ValidatorFillet1DSelection</name>
+ <message>
+ <source>Selected vertex is not a wire corner</source>
+ <translation>Выбранный узел не принадлежит контуру</translation>
+ </message>
+ <message>
+ <source>Selected shape is not a vertex</source>
+ <translation>Выбранный объект не является узлом</translation>
+ </message>
+ <message>
+ <source>Selected vertex does not exist in the wire</source>
+ <translation>Выбранный узел не принадлежит контуру</translation>
+ </message>
+ <message>
+ <source>Vertex should be shared between 2 edges exactly</source>
+ <translation>Узел должен примыкать ровно к двум рёбрам</translation>
+ </message>
+ <message>
+ <source>Error: Edges are not planar</source>
+ <translation>Ошибка: рёбра не лежат на одной плоскости</translation>
+ </message>
+ <message>
+ <source>Error: Edges are tangent</source>
+ <translation>Ошибка: рёбра касаются друг друга</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:creation_method</name>
+ <message>
+ <source>Wires</source>
+ <translation>Контуры</translation>
+ </message>
+ <message>
+ <source>Vertices</source>
+ <translation>Узлы</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:radius</name>
+ <message>
+ <source>Radius</source>
+ <translation>Радиус</translation>
+ </message>
+ <message>
+ <source>Fillet radius</source>
+ <translation>Радиус сглаживания</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Задайте радиус сглаживания.</translation>
+ </message>
+ </context>
+ <context>
+ <name>Fillet1D:radius:GeomValidators_Positive</name>
+ <message>
+ <source>Value is too small.</source>
+ <translation>Значение радиуса слишком мало.</translation>
+ </message>
+ </context>
+
</TS>
--- /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", "[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_1]e[Fillet1D_1_1/ME:Fillet1D&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", "[Fillet1D_2_1/ME:Fillet1D&Wire_1_1/Edge_2]e[Fillet1D_2_1/ME:Fillet1D&Wire_1_1/Edge_4]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", "[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_4]e[Fillet1D_1_1/ME:Fillet1D&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)
+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]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Recover
+Recover_1 = model.addRecover(Part_1_doc, Wire_1, [Box_1.result()])
+
+### Create Wire
+Wire_2_objects = [model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Right][Recover_1_1/Modified_Face&Box_1_1/Bottom]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Right]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Top]")]
+Wire_2 = model.addWire(Part_1_doc, Wire_2_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_2_1/Edge_2]e[Wire_2_1/Edge_3]e")], 2)
+
+model.testNbResults(Fillet1D_1, 2)
+model.testNbSubResults(Fillet1D_1, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [4, 4])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [8, 8])
+model.testResultsVolumes(Fillet1D_1, [0, 0])
+
+### Create Fillet1D
+Fillet1D_2 = model.addFillet(Part_1_doc, [model.selection("VERTEX", "[Fillet1D_1_2/ME:Fillet1D&Wire_2_1/Edge_1]e[Fillet1D_1_2/ME:Fillet1D&Wire_2_1/Edge_2]e"), model.selection("VERTEX", "[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_2]e[Fillet1D_1_1/ME:Fillet1D&Wire_1_1/Edge_3]e")], 5)
+
+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, 2)
+model.testNbSubResults(Fillet1D_2, [0, 0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.SOLID, [0, 0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.FACE, [0, 0])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.EDGE, [5, 5])
+model.testNbSubShapes(Fillet1D_2, GeomAPI_Shape.VERTEX, [10, 10])
+model.testResultsVolumes(Fillet1D_2, [0, 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
+# 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)
+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]")]
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Recover
+Recover_1 = model.addRecover(Part_1_doc, Wire_1, [Box_1.result()])
+
+### Create Wire
+Wire_2_objects = [model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Right][Recover_1_1/Modified_Face&Box_1_1/Bottom]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Right]"), model.selection("EDGE", "[Recover_1_1/Modified_Face&Box_1_1/Back][Recover_1_1/Modified_Face&Box_1_1/Top]")]
+Wire_2 = model.addWire(Part_1_doc, Wire_2_objects, False)
+
+### Create Fillet1D
+Fillet1D_1 = model.addFillet(Part_1_doc, [model.selection("WIRE", "Wire_1_1"), model.selection("WIRE", "Wire_2_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, 2)
+model.testNbSubResults(Fillet1D_1, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.SOLID, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.FACE, [0, 0])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.EDGE, [5, 5])
+model.testNbSubShapes(Fillet1D_1, GeomAPI_Shape.VERTEX, [10, 10])
+model.testResultsVolumes(Fillet1D_1, [0, 0])
+
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
extrusionCutFeature.rst
extrusionFeature.rst
extrusionFuseFeature.rst
+ fillet1dFeature.rst
filletFeature.rst
fuseFeatureFaces.rst
importResultFeature.rst
--- /dev/null
+
+ .. _tui_create_fillet1d_vertices:
+
+Create 1D-fillet for special vertices on a wire
+===============================================
+
+.. literalinclude:: examples/fillet1d_vertices.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/fillet1d_vertices.py >`
+
--- /dev/null
+
+ .. _tui_create_fillet1d_wire:
+
+Create 1D-fillet on a wire
+==========================
+
+.. literalinclude:: examples/fillet1d_wire.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/fillet1d_wire.py >`
+
--- /dev/null
+from salome.shaper import model
+
+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]")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+
+### Create Fillet1D
+Fillet1D_1_objects = [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")]
+Fillet1D_1 = model.addFillet(Part_1_doc, Fillet1D_1_objects, 3)
+
+model.end()
--- /dev/null
+from salome.shaper import model
+
+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]")]
+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")], 3)
+
+model.end()
--- /dev/null
+.. |fillet1d.icon| image:: images/fillet1d.png
+
+.. _featureFillet1D:
+
+1D-fillet
+=========
+
+**1D-fillet** feature creates fillets on the vertices of a wire.
+The fillet may be performed on sharp corners of a wire, which are shared exactly between 2 edges, and which are placed ona single plane.
+
+To create a 1D-fillet in the active part:
+
+#. select in the Main Menu *Feature - > 1D-fillet* item or
+#. click |fillet1d.icon| **1D-fillet** button in the toolbar
+
+There are 2 types of fillet:
+
+ .. image:: images/fillet1d_wire.png
+ :align: left
+ fillet all sharp corners on a wire
+
+ .. image:: images/fillet1d_points.png
+ :align: left
+ fillet only the specified corners
+
+Fillet a wire
+-------------
+
+The property panel for this mode is shown below.
+
+.. image:: images/Fillet1DPanel_Wire.png
+ :align: center
+
+.. centered::
+ Property panel of an operation to fillet all sharp corners on a wire
+
+Input fields:
+
+- **Wires** panel contains the list of wires for the operation. The fillet will be performed to the applicable corners. If the wire has no such corner, the error message will be shown;
+- **Radius** defines the fillet radius.
+
+**TUI Command**:
+
+.. py:function:: model.addFillet(Part_doc, [wires], radius)
+
+ :param part: The current part object.
+ :param list: A list of wires subject to fillet operation in format *model.selection(TYPE, shape)*.
+ :param number: Radius value.
+ :return: Created object.
+
+Result
+""""""
+
+Result of **Fillet a wire** is shown below. In this case all vertices were sharp, thus, filleted.
+
+.. image:: images/Fillet1DResult_Wire.png
+ :align: center
+
+.. centered::
+ Result of filleting a wire
+
+**See Also** a sample TUI Script of :ref:`tui_create_fillet1d_wire` operation.
+
+Fillet the specified vertices on a wire
+---------------------------------------
+
+Alternatively, there is a possibility to create a fillet on a special sharp corners of a wire.
+
+.. image:: images/Fillet1DPanel_Vertices.png
+ :align: center
+
+.. centered::
+ Property panel to fillet the specified vertices of a wire
+
+Input fields:
+
+- **Vertices** panel contains list of vertices on a wires applicable for fillet operation;
+- **Radius** defines the fillet radius.
+
+**TUI Command**:
+
+.. py:function:: model.addFillet(Part_doc, [vertices], radius)
+
+ :param part: The current part object.
+ :param list: A list of vertices subject to fillet operation in format *model.selection(TYPE, shape)*.
+ :param number: Radius value.
+ :return: Created object.
+
+Result
+""""""
+
+Result of **Fillet by vertices** is shown below. The only 2 corners of the wire become smooth.
+
+.. image:: images/Fillet1DResult_Vertices.png
+ :align: center
+
+.. centered::
+ Result of filleting the specified vertices of a wire
+
+**See Also** a sample TUI Script of :ref:`tui_create_fillet1d_vertices` operation.
--- /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>
#include <Geom_BSplineCurve.hxx>
+#include <GeomConvert.hxx>
+
#define MY_BSPLINE (*(implPtr<Handle_Geom_BSplineCurve>()))
-GeomAPI_BSpline::GeomAPI_BSpline(const GeomCurvePtr& theCurve)
+GeomAPI_BSpline::GeomAPI_BSpline (const GeomCurvePtr& theCurve)
{
GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve();
Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl<Handle(Geom_Curve)>();
{
return MY_BSPLINE->IsPeriodic();
}
+
+GeomBSplinePtr GeomAPI_BSpline::convertToBSpline (const GeomCurvePtr& theCurve)
+{
+ GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve();
+ Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl<Handle(Geom_Curve)>();
+ Handle(Geom_BSplineCurve) aBSpl = Handle(Geom_BSplineCurve)::DownCast(aCurve);
+ if (aBSpl.IsNull()) {
+ // convert to b-spline
+ aBSpl = GeomConvert::CurveToBSplineCurve(aCurve);
+ }
+ if (aBSpl.IsNull())
+ throw Standard_ConstructionError("GeomAPI_BSpline: Conversion to B-spline failed");
+ GeomCurvePtr aResCurve (new GeomAPI_Curve());
+ aResCurve->setImpl(new Handle_Geom_BSplineCurve(aBSpl));
+ GeomBSplinePtr aResult (new GeomAPI_BSpline(aResCurve));
+ return aResult;
+}
#include <memory>
class GeomAPI_Pnt;
+class GeomAPI_BSpline;
+
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_BSpline> GeomBSplinePtr;
/**\class GeomAPI_BSpline
* \ingroup DataModel
{
public:
/// Creation of B-spline defined by a curve
- GEOMAPI_EXPORT GeomAPI_BSpline(const GeomCurvePtr& theCurve);
+ GEOMAPI_EXPORT GeomAPI_BSpline (const GeomCurvePtr& theCurve);
/// Degree of B-spline curve
GEOMAPI_EXPORT int degree() const;
/// Return \c true if the curve is periodic
GEOMAPI_EXPORT bool isPeriodic() const;
-};
-//! Pointer on the object
-typedef std::shared_ptr<GeomAPI_BSpline> GeomBSplinePtr;
+ /// Convert any curve into a B-spline curve
+ GEOMAPI_EXPORT static GeomBSplinePtr convertToBSpline (const GeomCurvePtr& theCurve);
+};
#endif
Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
if (aCurve.IsNull()) // degenerative edge
return false;
- if (aCurve->IsKind(STANDARD_TYPE(Geom_Ellipse)))
- return true;
- return false;
+ while (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
+ aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
+ return aCurve->IsKind(STANDARD_TYPE(Geom_Ellipse));
}
bool GeomAPI_Edge::isBSpline() const
double aFirst, aLast;
Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
if (!aCurve.IsNull()) {
+ while (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
+ aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
Handle(Geom_Ellipse) aElips = Handle(Geom_Ellipse)::DownCast(aCurve);
if (!aElips.IsNull()) {
gp_Elips aGpElips = aElips->Elips();
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
%shared_ptr(GeomAlgoAPI_Copy)
%shared_ptr(GeomAlgoAPI_Symmetry)
%shared_ptr(GeomAlgoAPI_MapShapesAndAncestors)
+%shared_ptr(GeomAlgoAPI_WireBuilder)
// all supported interfaces
%include "GeomAlgoAPI_MakeShape.h"
#include <GeomAPI_Vertex.h>
#include <GeomAPI_ShapeExplorer.h>
+#include <Approx_ParametrizationType.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Edge.hxx>
-#include <TopExp_Explorer.hxx>
-#include <TColgp_HArray1OfPnt.hxx>
+#include <BSplSLib.hxx>
+#include <Geom_BSplineCurve.hxx>
+#include <Geom_BSplineSurface.hxx>
#include <GeomAPI_Interpolate.hxx>
+#include <GeomAPI_PointsToBSplineSurface.hxx>
#include <gp_Pnt.hxx>
#include <Precision.hxx>
+#include <TColgp_Array2OfPnt.hxx>
+#include <TColgp_HArray1OfPnt.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
-static void reorder(Handle(TColgp_HArray1OfPnt)& thePoints);
-
-//=================================================================================================
GeomEdgePtr GeomAlgoAPI_CurveBuilder::edge(const std::list<GeomPointPtr>& thePoints,
- const bool theIsClosed,
- const bool theIsToReorder,
- const GeomDirPtr& theStartTangent,
- const GeomDirPtr& theEndTangent)
+ const bool thePeriodic,
+ const bool theIsToReorder,
+ const GeomDirPtr& theStartTangent,
+ const GeomDirPtr& theEndTangent)
{
- // Prepare points array
- Handle(TColgp_HArray1OfPnt) aPoints = new TColgp_HArray1OfPnt(1, (int)thePoints.size());
- std::list<GeomPointPtr>::const_iterator anIt = thePoints.begin();
- for (int i = 1; anIt != thePoints.end(); anIt++, i++) {
- GeomPointPtr aPoint = *anIt;
- aPoints->SetValue(i, aPoint->impl<gp_Pnt>());
- }
+ std::list<GeomPointPtr> aPointsCopy = thePoints;
// If the curve to be closed - remove last point if it is too close to the first one
- bool isClose = aPoints->First().Distance(aPoints->Last()) <= gp::Resolution();
- if (isClose && theIsClosed) {
- aPoints->Resize(aPoints->Lower(), aPoints->Upper() - 1, Standard_True);
+ bool isClose = aPointsCopy.front()->distance(aPointsCopy.back()) <= gp::Resolution();
+ if (isClose && thePeriodic) {
+ aPointsCopy.pop_back();
}
// Reorder points if required
if (theIsToReorder) {
- reorder(aPoints);
+ reorderPoints(aPointsCopy);
+ }
+
+ // Prepare points array
+ Handle(TColgp_HArray1OfPnt) aPoints = new TColgp_HArray1OfPnt(1, (int)aPointsCopy.size());
+ std::list<GeomPointPtr>::const_iterator anIt = aPointsCopy.begin();
+ for (int i = 1; anIt != aPointsCopy.end(); anIt++, i++) {
+ GeomPointPtr aPoint = *anIt;
+ aPoints->SetValue(i, aPoint->impl<gp_Pnt>());
}
// Initialize interpolator
- GeomAPI_Interpolate anInterp(aPoints, theIsClosed, gp::Resolution());
+ GeomAPI_Interpolate anInterp(aPoints, thePeriodic, gp::Resolution());
// Assign tangents if defined
if (theStartTangent && theEndTangent) {
return aResultShape;
}
-//================ Auxiliary functions ========================================================
-void reorder(Handle(TColgp_HArray1OfPnt)& thePoints)
+GeomEdgePtr GeomAlgoAPI_CurveBuilder::approximate(const std::list<GeomPointPtr>& thePoints,
+ const bool thePeriodic,
+ const double thePrecision)
+{
+ // Prepare points array to be able to build a surface.
+ // This surface is based on two sets of points: the first is an original and
+ // the second is shifted along orthogonal direction.
+ // This is a workaround, because GeomAPI_PointsToBSpline algorithm cannot produce
+ // the periodic curve, but GeomAPI_PointsToBSplineSurface can.
+ TColgp_Array2OfPnt aPoints(1, (int)thePoints.size(), 1, 2);
+ gp_Pnt aPlaneBase[3]; // base points to calculate the normal direction
+ int aNbPlanePoints = 0;
+ gp_Dir aNormal;
+ std::list<GeomPointPtr>::const_iterator anIt = thePoints.begin();
+ for (int i = 1; anIt != thePoints.end(); anIt++, i++) {
+ const gp_Pnt& aPoint = (*anIt)->impl<gp_Pnt>();
+ aPoints.SetValue(i, 1, aPoint);
+ aPoints.SetValue(i, 2, aPoint);
+ if (aNbPlanePoints < 3) {
+ if (aNbPlanePoints == 0 ||
+ aPoint.SquareDistance(aPlaneBase[0]) > Precision::SquareConfusion())
+ aPlaneBase[aNbPlanePoints++] = aPoint;
+ if (aNbPlanePoints == 3) {
+ gp_Vec aVec12(aPlaneBase[0], aPlaneBase[1]);
+ gp_Vec aVec13(aPlaneBase[0], aPlaneBase[2]);
+ if (aVec12.CrossSquareMagnitude(aVec13) > Precision::SquareConfusion())
+ aNormal = gp_Dir(aVec12 ^ aVec13);
+ else
+ --aNbPlanePoints;
+ }
+ }
+ }
+ if (aNbPlanePoints < 3)
+ aNormal = gp::DZ();
+ // shifted points
+ for (int i = aPoints.LowerRow(); i <= aPoints.UpperRow(); i++)
+ aPoints.ChangeValue(i, 2).ChangeCoord() += aNormal.XYZ();
+
+ // If the curve to be closed - remove last point if it is too close to the first one
+ bool isClose = aPoints.Value(aPoints.LowerRow(), 1).Distance(
+ aPoints.Value(aPoints.UpperRow(), 1)) <= gp::Resolution();
+ if (isClose && thePeriodic) {
+ aPoints.Resize(aPoints.LowerRow(), aPoints.UpperRow() - 1,
+ aPoints.LowerCol(), aPoints.UpperCol(), Standard_True);
+ }
+
+ // Initialize and perform approximator
+ static const Standard_Integer DEGREE_MIN = 3;
+ static const Standard_Integer DEGREE_MAX = 8;
+ GeomAPI_PointsToBSplineSurface anApprox;
+ anApprox.Init(aPoints, Approx_ChordLength, DEGREE_MIN, DEGREE_MAX,
+ GeomAbs_C2, thePrecision, thePeriodic);
+
+ // Set result in form of edge
+ TopoDS_Edge anEdge;
+ if (anApprox.IsDone()) {
+ // build a curve along U-direction of the surface
+ Handle(Geom_BSplineSurface) aSurface = anApprox.Surface();
+ Handle(Geom_Curve) aCurve = aSurface->VIso(aSurface->VKnots().First());
+
+ anEdge = BRepBuilderAPI_MakeEdge(aCurve).Edge();
+ }
+
+ GeomEdgePtr aResultShape(new GeomAPI_Edge);
+ aResultShape->setImpl(new TopoDS_Shape(anEdge));
+
+ return aResultShape;
+}
+
+void GeomAlgoAPI_CurveBuilder::reorderPoints(std::list<GeomPointPtr>& thePoints)
{
- if (thePoints->Length() < 3) {
+ if (thePoints.size() < 3) {
return;
}
- int aNbPoints = thePoints->Length();
int aNbDup = 0;
- gp_Pnt aPrevPnt = thePoints->Value(1);
- for (int i = 1; i < aNbPoints; i++) {
- gp_Pnt aPnt = thePoints->Value(i);
- int aNearest = 0;
+ std::list<GeomPointPtr>::iterator aPIt = thePoints.begin();
+ GeomPointPtr aPrevPnt = *aPIt;
+ for (; aPIt != thePoints.end(); ++aPIt) {
+ GeomPointPtr aPnt = *aPIt;
+ std::list<GeomPointPtr>::iterator aNextIt = aPIt;
+ std::list<GeomPointPtr>::iterator aNearestIt = ++aNextIt;
double aMinDist = RealLast();
- for (int j = i + 1; j <= aNbPoints; j++) {
- double aDist = aPnt.SquareDistance(thePoints->Value(j));
+ while (aNextIt != thePoints.end()) {
+ double aDist = aPnt->distance(*aNextIt);
+ if (aDist < Precision::Confusion()) {
+ // remove duplicates
+ std::list<GeomPointPtr>::iterator aRemoveIt = aNextIt++;
+ thePoints.erase(aRemoveIt);
+ // update iterator showing the nearest point, because it may become invalid
+ aNearestIt = aPIt; ++aNearestIt;
+ continue;
+ }
if (aDist < aMinDist && (aMinDist - aDist) > Precision::Confusion()) {
- aNearest = j;
+ aNearestIt = aNextIt;
aMinDist = aDist;
}
+ ++aNextIt;
}
- if (aNearest > 0 && aNearest != i + 1) {
+ aNextIt = aPIt; ++aNextIt;
+ if (aNearestIt != aNextIt) {
// Keep given order of points to use it in case of equidistant candidates
// .--<---<--.
// | |
// o o o c o->o->o->o->n o o
// | | |
// i i+1 nearest
- gp_Pnt aNearestPnt = thePoints->Value(aNearest);
- for (int j = aNearest; j > i + 1; j--) {
- thePoints->SetValue(j, thePoints->Value(j - 1));
- }
- thePoints->SetValue(i + 1, aNearestPnt);
- }
- if (aPrevPnt.Distance(thePoints->Value(i + 1)) <= Precision::Confusion())
- aNbDup++;
- else
- aPrevPnt = thePoints->Value(i + 1);
- }
-
- if (aNbDup > 0) {
- Handle(TColgp_HArray1OfPnt) aTmpPoints = new TColgp_HArray1OfPnt(1, aNbPoints - aNbDup);
- for (int j = 1, i = 1; i <= aNbPoints; i++) {
- if (i == 1 || aPrevPnt.Distance(thePoints->Value(i)) > Precision::Confusion()) {
- aTmpPoints->SetValue(j++, thePoints->Value(i));
- aPrevPnt = thePoints->Value(i);
- }
+ GeomPointPtr aPointToMove = *aNearestIt;
+ thePoints.erase(aNearestIt);
+ thePoints.insert(aNextIt, aPointToMove);
}
- thePoints = aTmpPoints;
}
}
\ No newline at end of file
/// \class GeomAlgoAPI_CurveBuilder
/// \ingroup DataAlgo
-/// \brief Allows to create interpolation curve.
+/// \brief Allows to create a curve by the list of point.
class GeomAlgoAPI_CurveBuilder
{
public:
/// \brief Creates an interpolation curve from points.
/// \param[in] thePoints list of points.
- /// \param[in] theIsClosed defines whether the curve to be closed.
+ /// \param[in] thePeriodic defines whether the curve to be periodic.
/// \param[in] theIsToReorder defines whether to change the order of points to construct
/// the shortest curve.
/// \param[in] theStartTangent vector tangent to the start of curve.
/// \param[in] theEndTangent vector tangent to the end of curve.
/// \return Interpolation curve (edge). Empty in case of error or bad input.
GEOMALGOAPI_EXPORT static GeomEdgePtr edge(const std::list<GeomPointPtr>& thePoints,
- const bool theIsClosed,
+ const bool thePeriodic,
const bool theIsToReorder,
const GeomDirPtr& theStartTangent,
const GeomDirPtr& theEndTangent);
+
+ /// \brief Approximate the given points by a curve.
+ /// \param[in] thePoints list of points.
+ /// \param[in] thePeriodic defines whether the curve to be periodic.
+ /// \param[in] thePrecision how close the curve should be to the points.
+ /// \return Apporimation curve (edge). Empty in case of error or bad input.
+ GEOMALGOAPI_EXPORT static GeomEdgePtr approximate(const std::list<GeomPointPtr>& thePoints,
+ const bool thePeriodic,
+ const double thePrecision);
+
+ /// \brief Reoder the list of points to get a polyline of minimal length
+ GEOMALGOAPI_EXPORT static void reorderPoints(std::list<GeomPointPtr>& thePoints);
};
#endif
--- /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_Copy.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;
+
+ myFailedVertices.clear();
+ // store all edges of a base wire as modified, because they will be rebuild by ShapeFix
+ for (GeomAPI_WireExplorer aWExp(theBaseWire->wire()); aWExp.more(); aWExp.next()) {
+ GeomShapePtr aCurrent = aWExp.current();
+ GeomAlgoAPI_Copy aCopy(aCurrent);
+ myModified[aCurrent].push_back(aCopy.shape());
+ }
+
+ 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)) {
+ // store the failed vertex and continue
+ myFailedVertices.push_back(*aVIt);
+ 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()) {
+ myFailedVertices = theFilletVertices;
+ 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(myFailedVertices.empty());
+}
+
+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);
+
+ /// \return List of failed vertices
+ const ListOfShape& failedVertices() const { return myFailedVertices; }
+
+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;
+
+ ListOfShape myFailedVertices;
+};
+
+#endif
#include "GeomAlgoAPI_Offset.h"
+#include <GeomAPI_Pln.h>
+
#include <BRepOffsetAPI_MakeOffsetShape.hxx>
+#include <BRepOffsetAPI_MakeOffset.hxx>
+
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Wire.hxx>
GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
const double theOffsetValue)
// nothing is generated
}
}
+
+GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomPlanePtr& thePlane,
+ const GeomShapePtr& theEdgeOrWire,
+ const double theOffsetValue)
+{
+ // 1. Make wire from edge, if need
+ TopoDS_Wire aWire;
+ TopoDS_Shape anEdgeOrWire = theEdgeOrWire->impl<TopoDS_Shape>();
+ if (anEdgeOrWire.ShapeType() == TopAbs_WIRE) {
+ aWire = TopoDS::Wire(anEdgeOrWire);
+ } else {
+ if (anEdgeOrWire.ShapeType() == TopAbs_EDGE) {
+ BRepBuilderAPI_MakeWire aWireBuilder;
+ aWireBuilder.Add(TopoDS::Edge(anEdgeOrWire));
+ if (aWireBuilder.IsDone()) {
+ aWire = aWireBuilder.Wire();
+ }
+ }
+ }
+ if (aWire.IsNull())
+ return;
+
+ // 2. Make invalid face to pass it in Offset algorithm
+ BRepBuilderAPI_MakeFace aFaceBuilder (thePlane->impl<gp_Pln>(), aWire);
+ const TopoDS_Face& aFace = aFaceBuilder.Face();
+
+ // 3. Make Offset
+ BRepOffsetAPI_MakeOffset* aParal = new BRepOffsetAPI_MakeOffset;
+ setImpl(aParal);
+ setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+ Standard_Boolean isOpenResult = !aWire.Closed();
+ aParal->Init(aFace, GeomAbs_Arc, isOpenResult);
+ aParal->Perform(theOffsetValue, 0.);
+ if (aParal->IsDone()) {
+ TopoDS_Shape anOffset = aParal->Shape();
+ GeomShapePtr aResult(new GeomAPI_Shape());
+ aResult->setImpl(new TopoDS_Shape(anOffset));
+ setShape(aResult);
+ setDone(true);
+ }
+}
#include <GeomAlgoAPI.h>
#include <GeomAlgoAPI_MakeShape.h>
+class GeomAPI_Pln;
+
/// \class GeomAlgoAPI_Offset
/// \ingroup DataAlgo
/// \brief Perform 3D offset for the shape
GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
const double theOffsetValue);
+ /// \brief Perform the offset algorithm on the plane
+ /// \param[in] thePlane base plane for all offsets
+ /// \param[in] theEdgesOrWire base shapes
+ /// \param[in] theOffsetValue offset distance, it can be negative
+ GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const std::shared_ptr<GeomAPI_Pln>& thePlane,
+ const GeomShapePtr& theEdgeOrWire,
+ const double theOffsetValue);
+
/// \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);
+
private:
/// \brief Perform offset operation
void build(const GeomShapePtr& theShape, const double theOffsetValue);
Handle(Geom_Curve) aCurve = theCurve->impl<Handle_Geom_Curve>();
Handle(Geom_Plane) aPlane = new Geom_Plane(myPlane->impl<gp_Ax3>());
- Handle(Geom_Curve) aProj = GeomProjLib::Project(aCurve, aPlane);
+ Handle(Geom_Curve) aProj =
+ GeomProjLib::ProjectOnPlane(aCurve, aPlane, aPlane->Axis().Direction(), false);
GeomCurvePtr aProjCurve(new GeomAPI_Curve);
aProjCurve->setImpl(new Handle_Geom_Curve(aProj));
#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);
#include <GeomAPI_Vertex.h>
#include <GeomAPI_ShapeExplorer.h>
+#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepTools_ReShape.hxx>
#include <Geom_Curve.hxx>
#include <Precision.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
+#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <cmath>
}
};
-//=================================================================================================
-GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
+static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
+{
+ GeomShapePtr aResultShape(new GeomAPI_Shape());
+ aResultShape->setImpl(new TopoDS_Shape(theShape));
+ return aResultShape;
+}
+
+GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
+ const bool theForceOpenWire)
{
TopTools_ListOfShape aListOfEdges;
SetOfEdges aProcessedEdges;
ListOfShape::const_iterator anIt = theShapes.cbegin();
- for(; anIt != theShapes.cend(); ++anIt) {
+ for (; anIt != theShapes.cend(); ++anIt) {
TopoDS_Shape aShape = (*anIt)->impl<TopoDS_Shape>();
switch(aShape.ShapeType()) {
case TopAbs_EDGE: {
break;
}
case TopAbs_WIRE: {
- for(TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+ for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
TopoDS_Shape anEdge = anExp.Current();
anEdge.Orientation(TopAbs_FORWARD);
// if the edge was already processed, remove it to keep original order of the current wire
}
break;
}
- default: {
- return GeomShapePtr();
- }
+ default:
+ break;
}
}
- BRepBuilderAPI_MakeWire aWireBuilder;
- aWireBuilder.Add(aListOfEdges);
- if(aWireBuilder.Error() != BRepBuilderAPI_WireDone) {
- return GeomShapePtr();
+ bool isSplitWire = false;
+ gp_Pnt aSplitPoint;
+ if (theForceOpenWire && aListOfEdges.Size() > 1) {
+ // find a vertex to split the wire
+ TopoDS_Vertex V1[2];
+ TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]);
+ TopoDS_Vertex V2[2];
+ TopExp::Vertices(TopoDS::Edge(aListOfEdges.Last()), V2[0], V2[1]);
+ gp_Pnt P1[2] = { BRep_Tool::Pnt(V1[0]), BRep_Tool::Pnt(V1[1]) };
+ gp_Pnt P2[2] = { BRep_Tool::Pnt(V2[0]), BRep_Tool::Pnt(V2[1]) };
+ double Tol1[2] = { BRep_Tool::Tolerance(V1[0]), BRep_Tool::Tolerance(V1[1]) };
+ double Tol2[2] = { BRep_Tool::Tolerance(V2[0]), BRep_Tool::Tolerance(V2[1]) };
+ for (int i = 0; i < 2 && !isSplitWire; ++i)
+ for (int j = 0; j < 2 && !isSplitWire; ++j)
+ if (P1[i].Distance(P2[j]) < Max(Tol1[i], Tol2[j])) {
+ aSplitPoint = P1[i];
+ isSplitWire = true;
+ }
}
- GeomShapePtr aResultShape(new GeomAPI_Shape());
- aResultShape->setImpl(new TopoDS_Shape(aWireBuilder.Wire()));
- return aResultShape;
+ BRepBuilderAPI_MakeWire* aWireBuilder = new BRepBuilderAPI_MakeWire;
+ aWireBuilder->Add(aListOfEdges);
+ if (aWireBuilder->Error() == BRepBuilderAPI_WireDone) {
+ setImpl(aWireBuilder);
+ setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+ // split the result wire
+ TopoDS_Wire aWire = aWireBuilder->Wire();
+ if (isSplitWire && BRep_Tool::IsClosed(aWire)) {
+ TopoDS_Wire aNewWire;
+ BRep_Builder aBuilder;
+ aBuilder.MakeWire(aNewWire);
+ for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+ TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
+ if (isSplitWire) {
+ bool isToReshape = false;
+ BRepTools_ReShape aReshape;
+ TopoDS_Vertex aVF, aVL;
+ TopExp::Vertices(aNewCurrent, aVF, aVL);
+ gp_Pnt aPF = BRep_Tool::Pnt(aVF);
+ double aTolF = BRep_Tool::Tolerance(aVF);
+ gp_Pnt aPL = BRep_Tool::Pnt(aVL);
+ double aTolL = BRep_Tool::Tolerance(aVL);
+ if (aSplitPoint.SquareDistance(aPF) < aTolF * aTolF) {
+ aReshape.Replace(aVF, aReshape.CopyVertex(aVF));
+ isToReshape = true;
+ }
+ else if (aSplitPoint.SquareDistance(aPL) < aTolL * aTolL) {
+ aReshape.Replace(aVL, aReshape.CopyVertex(aVL));
+ isToReshape = true;
+ }
+ if (isToReshape) {
+ aNewCurrent = TopoDS::Edge(aReshape.Apply(aNewCurrent));
+ isSplitWire = false; // no need to continue splitting
+ }
+ }
+ aBuilder.Add(aNewWire, aNewCurrent);
+ }
+ aWire = aNewWire;
+ }
+
+ // store generated/modified shapes
+ for (TopTools_ListOfShape::Iterator aBaseIt(aListOfEdges); aBaseIt.More(); aBaseIt.Next()) {
+ TopoDS_Edge aBaseCurrent = TopoDS::Edge(aBaseIt.Value());
+ Standard_Real aFirst, aLast;
+ Handle(Geom_Curve) aBaseCurve = BRep_Tool::Curve(aBaseCurrent, aFirst, aLast);
+
+ for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+ TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
+ Handle(Geom_Curve) aNewCurve = BRep_Tool::Curve(aNewCurrent, aFirst, aLast);
+ if (aBaseCurve == aNewCurve) {
+ GeomShapePtr aBaseShape = fromTopoDS(aBaseCurrent);
+ GeomShapePtr aNewShape = fromTopoDS(aNewCurrent);
+ addGenerated(aBaseShape, aNewShape);
+ addModified(aBaseShape, aNewShape);
+ }
+ }
+ }
+
+ setShape(fromTopoDS(aWire));
+ setDone(true);
+ }
+}
+
+//=================================================================================================
+GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
+{
+ return GeomAlgoAPI_WireBuilder(theShapes).shape();
}
//=================================================================================================
#define GeomAlgoAPI_WireBuilder_H_
#include "GeomAlgoAPI.h"
+#include "GeomAlgoAPI_MakeShapeCustom.h"
#include <GeomAPI_Shape.h>
/// \class GeomAlgoAPI_WireBuilder
/// \ingroup DataAlgo
/// \brief Allows to create wire-shapes by different parameters.
-class GeomAlgoAPI_WireBuilder
+class GeomAlgoAPI_WireBuilder : public GeomAlgoAPI_MakeShapeCustom
{
public:
+ /// \brief Creates a wire from edges and wires.
+ /// \param[in] theShapes list of shapes. Only edges and wires allowed.
+ /// \param[in] theForceOpenWire indicates the necessity to split wire
+ /// in the first vertex if it becomes closed.
+ /// The edges are not to be consecutive.
+ /// But they are to be all connected geometrically or topologically.
+ GEOMALGOAPI_EXPORT GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
+ const bool theForceOpenWire = false);
+
/// \brief Creates a wire from edges and wires.
/// \param[in] theShapes list of shapes. Only edges and wires allowed.
/// The edges are not to be consecutive.
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
const int theValue,
bool sendUpdated)
{
- if (myArray->Value(theIndex) != theValue) {
+ if (!isInitialized() || myArray->Value(theIndex) != theValue) {
setInitialized();
myArray->SetValue(theIndex, theValue);
if (sendUpdated)
/// Reference to the parent attribute, if any (to split selection compounds in issue 1799)
Model_AttributeSelectionList* myParent;
- std::shared_ptr<Model_Document> myRestoreDocument; // current document to restore by name
+ /// current document to restore by name
+ std::shared_ptr<Model_Document> myRestoreDocument;
/// If true attribute selects geometry instead of shape.
bool myIsGeometricalSelection;
#include <ModelAPI_Events.h>
#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Shape.h>
//#define DEBUG_OBJECT_MOVED_MESSAGE
#ifdef DEBUG_OBJECT_MOVED_MESSAGE
<< myCurrentPosition->y() - myOriginalPosition->y() << std::endl;
#endif
}
+
+
+// ===== ModelAPI_ShapesFailedMessage =====
+ModelAPI_ShapesFailedMessage::ModelAPI_ShapesFailedMessage(const Events_ID theID,
+ const void* theSender)
+ : Events_Message(theID, theSender)
+{}
+
+ModelAPI_ShapesFailedMessage::~ModelAPI_ShapesFailedMessage()
+{}
+
+void ModelAPI_ShapesFailedMessage::setShapes(const ListOfShape& theShapes)
+{
+ myShapes = theShapes;
+}
+
+const ListOfShape& ModelAPI_ShapesFailedMessage::shapes() const
+{
+ return myShapes;
+}
class ModelAPI_Document;
class ModelAPI_ResultParameter;
class GeomAPI_Pnt2d;
+class GeomAPI_Shape;
#if defined __GNUC__ || defined __clang__
#define MAYBE_UNUSED __attribute__((unused))
MAYBE_UNUSED static const char * EVENT_VISUAL_ATTRIBUTES = "UpdateVisualAttributes";
+/// Event ID that 1D-fillet failed (comes with ModelAPI_ShapesFailedMessage)
+static const char * EVENT_OPERATION_SHAPES_FAILED = "OperationShapesFailed";
+
/// Message that feature was changed (used for Object Browser update): moved, updated and deleted
class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup
{
{ return myCurrentPosition; }
};
+/// Message that sends the failed vertices of 1D-fillet to highlight them in 3D viewer
+class ModelAPI_ShapesFailedMessage : public Events_Message
+{
+public:
+ /// Creates an message
+ MODELAPI_EXPORT ModelAPI_ShapesFailedMessage(const Events_ID theID, const void* theSender = 0);
+ /// Default destructor
+ MODELAPI_EXPORT virtual ~ModelAPI_ShapesFailedMessage();
+ /// Static. Returns EventID of the message.
+ MODELAPI_EXPORT static Events_ID eventId()
+ {
+ return Events_Loop::eventByName(EVENT_OPERATION_SHAPES_FAILED);
+ }
+
+ /// Sets list of failed vertices
+ MODELAPI_EXPORT void setShapes(const std::list< std::shared_ptr<GeomAPI_Shape> >& theVertices);
+ /// Returns list of failed vertices
+ MODELAPI_EXPORT const std::list< std::shared_ptr<GeomAPI_Shape> >& shapes() const;
+
+private:
+ std::list< std::shared_ptr<GeomAPI_Shape> > myShapes;
+};
+
#endif
{
return data()->refattr(theID);
}
+ /// Returns the refattrlist attribute by the identifier
+ inline std::shared_ptr<ModelAPI_AttributeRefAttrList> refattrlist(const std::string& theID)
+ {
+ return data()->refattrlist(theID);
+ }
/// Returns the reference attribute by the identifier
inline std::shared_ptr<ModelAPI_AttributeReference> reference(const std::string& theID)
{
Pipe_5 = model.addPipe(Part_1_doc, [model.selection("WIRE", "Wire_39_1")], model.selection("EDGE", "PartSet/OZ"))
Pipe_6 = model.addPipe(Part_1_doc, [model.selection("FACE", "Face_3_1")], model.selection("EDGE", "PartSet/OY"))
Common_3 = model.addCommon(Part_1_doc, [model.selection("FACE", "Pipe_5_1"), model.selection("SOLID", "Pipe_6_1")])
-Filling_1 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_41&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_41&Wire_13_1/Wire_13_1")])
-Filling_2 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_7_2&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_7_2&Wire_13_1/Wire_13_1")])
-Filling_3 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_8_2&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_8_2&Wire_13_1/Wire_13_1")])
-Filling_4 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_5_2&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_5_2&Wire_13_1/Wire_13_1")])
-Filling_5 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_44&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_44&Wire_26_1/Wire_26_1")])
-Filling_6 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_6_2&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_6_2&Wire_26_1/Wire_26_1")])
-Filling_7 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_3_2&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_3_2&Wire_26_1/Wire_26_1")])
-Filling_8 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_2_2&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_2_2&Wire_26_1/Wire_26_1")])
-Filling_9 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_23&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_23&Wire_26_1/Wire_26_1")])
-Filling_10 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_1_2&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_1_2&Wire_26_1/Wire_26_1")])
-Filling_11 = model.addFilling(Part_1_doc, [model.selection("EDGE", "(Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_8_2&Wire_26_1/Wire_26_1)(Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_41&Wire_26_1/Wire_26_1)2(Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_1_2&Wire_26_1/Wire_26_1)2"), model.selection("EDGE", "(Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_8_2&Wire_13_1/Wire_13_1)(Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_41&Wire_13_1/Wire_13_1)2(Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_1_2&Wire_13_1/Wire_13_1)2")])
-Filling_12 = model.addFilling(Part_1_doc, [model.selection("EDGE", "(Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_1_2&Wire_26_1/Wire_26_1)(Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_8_2&Wire_26_1/Wire_26_1)2(Scale_2_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_23&Wire_26_1/Wire_26_1)2"), model.selection("EDGE", "(Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_1_2&Wire_13_1/Wire_13_1)(Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchArc_8_2&Wire_13_1/Wire_13_1)2(Scale_1_1/ME:Scaled&PartSet/OY/OY&PartSet/Shape/SketchLine_23&Wire_13_1/Wire_13_1)2")])
+Filling_1 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_9_1/Edge&Wire_22_1/Edge&Wire_35_1/Edge&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_9_1/Edge&Wire_22_1/Edge&Wire_35_1/Edge&Wire_13_1/Wire_13_1")])
+Filling_2 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_6_1/Edge&Wire_19_1/Edge&Wire_32_1/Edge&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_6_1/Edge&Wire_19_1/Edge&Wire_32_1/Edge&Wire_13_1/Wire_13_1")])
+Filling_3 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_10_1/Edge&Wire_23_1/Edge&Wire_36_1/Edge&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_10_1/Edge&Wire_23_1/Edge&Wire_36_1/Edge&Wire_13_1/Wire_13_1")])
+Filling_4 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_8_1/Edge&Wire_21_1/Edge&Wire_34_1/Edge&Wire_26_1/Wire_26_1"), model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_8_1/Edge&Wire_21_1/Edge&Wire_34_1/Edge&Wire_13_1/Wire_13_1")])
+Filling_5 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_7_1/Edge&Wire_20_1/Edge&Wire_33_1/Edge&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_7_1/Edge&Wire_20_1/Edge&Wire_33_1/Edge&Wire_26_1/Wire_26_1")])
+Filling_6 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_5_1/Edge&Wire_18_1/Edge&Wire_31_1/Edge&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_5_1/Edge&Wire_18_1/Edge&Wire_31_1/Edge&Wire_26_1/Wire_26_1")])
+Filling_7 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_4_1/Edge&Wire_17_1/Edge&Wire_30_1/Edge&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_4_1/Edge&Wire_17_1/Edge&Wire_30_1/Edge&Wire_26_1/Wire_26_1")])
+Filling_8 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_3_1/Edge&Wire_16_1/Edge&Wire_29_1/Edge&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_3_1/Edge&Wire_16_1/Edge&Wire_29_1/Edge&Wire_26_1/Wire_26_1")])
+Filling_9 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_2_1/Edge&Wire_15_1/Edge&Wire_28_1/Edge&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_2_1/Edge&Wire_15_1/Edge&Wire_28_1/Edge&Wire_26_1/Wire_26_1")])
+Filling_10 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_1_1/Edge&Wire_14_1/Edge&Wire_27_1/Edge&Wire_13_1/Wire_13_1"), model.selection("EDGE", "Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_1_1/Edge&Wire_14_1/Edge&Wire_27_1/Edge&Wire_26_1/Wire_26_1")])
+Filling_11 = model.addFilling(Part_1_doc, [model.selection("EDGE", "(Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_10_1/Edge&Wire_23_1/Edge&Wire_36_1/Edge&Wire_26_1/Wire_26_1)(Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_9_1/Edge&Wire_22_1/Edge&Wire_35_1/Edge&Wire_26_1/Wire_26_1)2(Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_1_1/Edge&Wire_14_1/Edge&Wire_27_1/Edge&Wire_26_1/Wire_26_1)2"), model.selection("EDGE", "(Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_10_1/Edge&Wire_23_1/Edge&Wire_36_1/Edge&Wire_13_1/Wire_13_1)(Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_9_1/Edge&Wire_22_1/Edge&Wire_35_1/Edge&Wire_13_1/Wire_13_1)2(Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_1_1/Edge&Wire_14_1/Edge&Wire_27_1/Edge&Wire_13_1/Wire_13_1)2")])
+Filling_12 = model.addFilling(Part_1_doc, [model.selection("EDGE", "(Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_1_1/Edge&Wire_14_1/Edge&Wire_27_1/Edge&Wire_26_1/Wire_26_1)(Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_10_1/Edge&Wire_23_1/Edge&Wire_36_1/Edge&Wire_26_1/Wire_26_1)2(Scale_2_1/ME:Scaled&PartSet/OY/OY&Wire_2_1/Edge&Wire_15_1/Edge&Wire_28_1/Edge&Wire_26_1/Wire_26_1)2"), model.selection("EDGE", "(Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_1_1/Edge&Wire_14_1/Edge&Wire_27_1/Edge&Wire_13_1/Wire_13_1)(Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_10_1/Edge&Wire_23_1/Edge&Wire_36_1/Edge&Wire_13_1/Wire_13_1)2(Scale_1_1/ME:Scaled&PartSet/OY/OY&Wire_2_1/Edge&Wire_15_1/Edge&Wire_28_1/Edge&Wire_13_1/Wire_13_1)2")])
Shell_1_objects = [model.selection("FACE", "Scale_1_1"), model.selection("FACE", "Scale_2_1"), model.selection("FACE", "Filling_1_1"), model.selection("FACE", "Filling_2_1"), model.selection("FACE", "Filling_3_1"), model.selection("FACE", "Filling_4_1"), model.selection("FACE", "Filling_5_1"), model.selection("FACE", "Filling_6_1"), model.selection("FACE", "Filling_7_1"), model.selection("FACE", "Filling_8_1"), model.selection("FACE", "Filling_9_1"), model.selection("FACE", "Filling_10_1"), model.selection("FACE", "Filling_11_1"), model.selection("FACE", "Filling_12_1")]
Shell_1 = model.addShell(Part_1_doc, Shell_1_objects)
Solid_1 = model.addSolid(Part_1_doc, [model.selection("SHELL", "Shell_1_1")])
Recover_1 = model.addRecover(Part_1_doc, Wire_1, [Extrusion_1.result().subResult(0), Extrusion_1.result().subResult(1)])
Recover_1.result().setName("BaseHorizontale")
Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Recover_1_2/Modified_Face&Extrusion_1_1_1/To_Face")], model.selection(), 40, 10)
-Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "_weak_name_8_Extrusion_2_1")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Extrusion_2_1/Generated_Face&Wire_1_1/Edge_16")])
Recover_2 = model.addRecover(Part_1_doc, Shell_1, [Extrusion_2.result()])
Recover_2.result().setName("BaseVerticale")
Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("SHELL", "Shell_1_1")], model.selection(), 0, 67)
SketchLine_3 = Sketch_1.addLine(-25.74772708486752, -20, -17.21320343559642, -20)
SketchLine_4 = Sketch_1.addLine(-13.67766952966368, -21.46446609406726, 2.928932188134523, -38.07106781186547)
SketchArc_1 = Sketch_1.addArc(-17.21320343559642, -25, -13.67766952966368, -21.46446609406726, -17.21320343559642, -20, False)
-SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_4.startPoint())
-SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_3.endPoint())
-SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_4.result())
-SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_3.result())
-SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
-SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_4.startPoint())
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_3.endPoint())
+Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_4.result())
+Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_3.result())
+Sketch_1.setHorizontal(SketchLine_3.result())
+Sketch_1.setVertical(SketchLine_2.result())
SketchArc_2 = Sketch_1.addArc(0, 6.520200294596256e-23, -4.760492650097915, 19.42518236023452, 20, 2.492755359431925e-15, True)
-SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_2.startPoint())
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_2.startPoint())
SketchArc_3 = Sketch_1.addArc(-12, -5, -29.79117622747561, -17.94117647058824, -17.23654191510763, 16.36770059625792, True)
-SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_1.startPoint())
-SketchConstraintCoincidence_4.setName("SketchConstraintCoincidence_5")
-SketchConstraintTangent_3 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_1.result())
-SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.startPoint())
-SketchConstraintCoincidence_5.setName("SketchConstraintCoincidence_6")
+Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_1.startPoint())
+Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_1.result())
+Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.startPoint())
SketchArc_4 = Sketch_1.addArc(-25.74772708486752, -15, -29.79117622747561, -17.94117647058824, -25.74772708486752, -20, False)
-SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_4.startPoint(), SketchArc_3.startPoint())
-SketchConstraintCoincidence_6.setName("SketchConstraintCoincidence_7")
-SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_4.endPoint(), SketchLine_3.startPoint())
-SketchConstraintCoincidence_7.setName("SketchConstraintCoincidence_8")
-SketchConstraintTangent_4 = Sketch_1.setTangent(SketchArc_4.results()[1], SketchLine_3.result())
-SketchConstraintTangent_5 = Sketch_1.setTangent(SketchArc_4.results()[1], SketchArc_3.results()[1])
+Sketch_1.setCoincident(SketchArc_4.startPoint(), SketchArc_3.startPoint())
+Sketch_1.setCoincident(SketchArc_4.endPoint(), SketchLine_3.startPoint())
+Sketch_1.setTangent(SketchArc_4.results()[1], SketchLine_3.result())
+Sketch_1.setTangent(SketchArc_4.results()[1], SketchArc_3.results()[1])
SketchArc_5 = Sketch_1.addArc(10, -31, 20, -31, 2.928932188134523, -38.07106781186547, True)
-SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_5.startPoint())
-SketchConstraintCoincidence_8.setName("SketchConstraintCoincidence_9")
-SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchArc_5.endPoint(), SketchLine_4.endPoint())
-SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
-SketchConstraintTangent_6 = Sketch_1.setTangent(SketchArc_5.results()[1], SketchLine_4.result())
-SketchConstraintTangent_7 = Sketch_1.setTangent(SketchLine_2.result(), SketchArc_5.results()[1])
-SketchConstraintTangent_8 = Sketch_1.setTangent(SketchLine_1.result(), SketchArc_2.results()[1])
-SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 31)
-SketchConstraintTangent_9 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchLine_2.result())
-SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_4.result(), 135)
-SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 5)
-SketchConstraintEqual_1 = Sketch_1.setEqual(SketchArc_4.results()[1], SketchArc_1.results()[1])
-SketchConstraintRadius_2 = Sketch_1.setRadius(SketchArc_5.results()[1], 10)
-SketchConstraintRadius_3 = Sketch_1.setRadius(SketchArc_2.results()[1], 20)
-SketchConstraintRadius_4 = Sketch_1.setRadius(SketchArc_3.results()[1], 22)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_5.startPoint())
+Sketch_1.setCoincident(SketchArc_5.endPoint(), SketchLine_4.endPoint())
+Sketch_1.setTangent(SketchArc_5.results()[1], SketchLine_4.result())
+Sketch_1.setTangent(SketchLine_2.result(), SketchArc_5.results()[1])
+Sketch_1.setTangent(SketchLine_1.result(), SketchArc_2.results()[1])
+Sketch_1.setLength(SketchLine_2.result(), 31)
+Sketch_1.setTangent(SketchArc_2.results()[1], SketchLine_2.result())
+Sketch_1.setAngle(SketchLine_3.result(), SketchLine_4.result(), 135)
+Sketch_1.setRadius(SketchArc_1.results()[1], 5)
+Sketch_1.setEqual(SketchArc_4.results()[1], SketchArc_1.results()[1])
+Sketch_1.setRadius(SketchArc_5.results()[1], 10)
+Sketch_1.setRadius(SketchArc_2.results()[1], 20)
+Sketch_1.setRadius(SketchArc_3.results()[1], 22)
SketchCircle_1 = Sketch_1.addCircle(-22, -5, 7.5)
SketchLine_5 = Sketch_1.addLine(-22, -5, -12, -5)
SketchLine_5.setAuxiliary(True)
-SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_5.startPoint())
-SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
-SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchArc_3.center(), SketchLine_5.endPoint())
-SketchConstraintCoincidence_11.setName("SketchConstraintCoincidence_12")
-SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
-SketchConstraintRadius_5 = Sketch_1.setRadius(SketchCircle_1.results()[1], 7.5)
+Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_5.startPoint())
+Sketch_1.setCoincident(SketchArc_3.center(), SketchLine_5.endPoint())
+Sketch_1.setHorizontal(SketchLine_5.result())
+Sketch_1.setRadius(SketchCircle_1.results()[1], 7.5)
SketchCircle_2 = Sketch_1.addCircle(0, 6.520200294596256e-23, 10)
-SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchArc_2.center(), SketchCircle_2.center())
-SketchConstraintCoincidence_12.setName("SketchConstraintCoincidence_13")
-SketchConstraintRadius_6 = Sketch_1.setRadius(SketchCircle_2.results()[1], 10)
-SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchCircle_2.center(), SketchArc_3.center(), 5)
+Sketch_1.setCoincident(SketchArc_2.center(), SketchCircle_2.center())
+Sketch_1.setRadius(SketchCircle_2.results()[1], 10)
+Sketch_1.setVerticalDistance(SketchCircle_2.center(), SketchArc_3.center(), 5)
SketchCircle_3 = Sketch_1.addCircle(7, -25, 7.5)
-SketchConstraintRadius_7 = Sketch_1.setRadius(SketchCircle_3.results()[1], 7.5)
-SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchArc_2.center(), SketchCircle_3.center(), 7)
-SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_2.center(), SketchLine_3.result(), 20, True)
-SketchConstraintDistanceVertical_2 = Sketch_1.setVerticalDistance(SketchArc_2.center(), SketchCircle_3.center(), 25)
-SketchConstraintDistanceHorizontal_2 = Sketch_1.setHorizontalDistance(SketchLine_5.endPoint(), SketchArc_2.center(), 12)
-SketchConstraintDistanceHorizontal_3 = Sketch_1.setHorizontalDistance(SketchCircle_1.center(), SketchArc_2.center(), 22)
+Sketch_1.setRadius(SketchCircle_3.results()[1], 7.5)
+Sketch_1.setHorizontalDistance(SketchArc_2.center(), SketchCircle_3.center(), 7)
+Sketch_1.setDistance(SketchCircle_2.center(), SketchLine_3.result(), 20, True)
+Sketch_1.setVerticalDistance(SketchArc_2.center(), SketchCircle_3.center(), 25)
+Sketch_1.setHorizontalDistance(SketchLine_5.endPoint(), SketchArc_2.center(), 12)
+Sketch_1.setHorizontalDistance(SketchCircle_1.center(), SketchArc_2.center(), 22)
SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
SketchPoint_1 = SketchProjection_1.createdFeature()
-SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchCircle_2.center(), SketchAPI_Point(SketchPoint_1).coordinates())
-SketchConstraintCoincidence_13.setName("SketchConstraintCoincidence_14")
+Sketch_1.setCoincident(SketchCircle_2.center(), SketchAPI_Point(SketchPoint_1).coordinates())
model.do()
Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_3_2f-SketchArc_4_2f-SketchLine_3f-SketchArc_1_2r-SketchLine_4f-SketchArc_5_2f-SketchLine_2r-SketchArc_2_2f-SketchLine_1r-SketchCircle_1_2r-SketchCircle_2_2r-SketchCircle_3_2r")], model.selection(), 6.5, 0)
Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2"))
SketchLine_7 = Sketch_2.addLine(-12.15814035598059, 5.092287733454298, -12.15814035598059, 23.78152371848275)
SketchLine_8 = Sketch_2.addLine(-12.15814035598059, 23.78152371848275, 14.45330132699559, 23.78152371848275)
SketchLine_9 = Sketch_2.addLine(14.45330132699559, 23.78152371848275, 14.45330132699559, 5.092287733454298)
-SketchConstraintCoincidence_14 = Sketch_2.setCoincident(SketchLine_9.endPoint(), SketchLine_6.startPoint())
-SketchConstraintCoincidence_14.setName("SketchConstraintCoincidence_15")
-SketchConstraintCoincidence_15 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
-SketchConstraintCoincidence_15.setName("SketchConstraintCoincidence_16")
-SketchConstraintCoincidence_16 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
-SketchConstraintCoincidence_16.setName("SketchConstraintCoincidence_17")
-SketchConstraintCoincidence_17 = Sketch_2.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
-SketchConstraintCoincidence_17.setName("SketchConstraintCoincidence_18")
-SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
-SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_7.result())
-SketchConstraintHorizontal_4 = Sketch_2.setHorizontal(SketchLine_8.result())
-SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_9.result())
+Sketch_2.setCoincident(SketchLine_9.endPoint(), SketchLine_6.startPoint())
+Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+Sketch_2.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+Sketch_2.setHorizontal(SketchLine_6.result())
+Sketch_2.setVertical(SketchLine_7.result())
+Sketch_2.setHorizontal(SketchLine_8.result())
+Sketch_2.setVertical(SketchLine_9.result())
model.do()
ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_9r-SketchLine_8r-SketchLine_7r-SketchLine_6r")], model.selection(), 0, 100, [model.selection("SOLID", "Extrusion_1_1")])
model.do()
// directors
%feature("director") ModelHighAPI_Dumper;
+// renamed methods
+%rename(__print__) ModelHighAPI_Dumper::operator<<;
+
// shared pointers
%shared_ptr(ModelHighAPI_Interface)
%shared_ptr(ModelHighAPI_Folder)
const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity,
bool theSaveNotDumped,
- bool theUseEntityName)
-{
- EntityNameMap::const_iterator aFound = myNames.find(theEntity);
- if (aFound != myNames.end())
+ bool theUseEntityName,
+ bool theSetIsDumped)
+{
+ EntityNameMap::iterator aFound = myNames.find(theEntity);
+ if (aFound != myNames.end()) {
+ // Set dumped flag for postponed constraints which are without names
+ if (!aFound->second.myIsDumped)
+ aFound->second.myIsDumped = theSetIsDumped;
return aFound->second.myCurrentName;
-
+ }
// entity is not found, store it
std::string aName, aKind;
bool isDefaultName = false;
if (aFeature)
saveResultNames(aFeature);
+ myNames[theEntity].myIsDumped = theSetIsDumped;
+
return myNames[theEntity].myCurrentName;
}
// dump features in the document
bool aRes = process(aSubDoc);
if (isDumpModelDo)
- *this << "model.do()\n";
+ *this << "\nmodel.do()\n";
*this << std::endl;
return aRes;
}
return fabs(anAttribute->value()) < 1.e-12;
}
+bool ModelHighAPI_Dumper::dumpCommentBeforeFeature(const FeaturePtr& theFeature) const
+{
+ // currently, the comment should not be dumped only before the filters
+ FiltersFeaturePtr aFilters = std::dynamic_pointer_cast<ModelAPI_FiltersFeature>(theFeature);
+ if (aFilters)
+ return false;
+ // all other features should be commented before the dump
+ return true;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
{
*myDumpStorage << theChar;
const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
{
static const int aThreshold = 2;
- static bool aDumpAsIs = false;
+ static int aNbSpaces = 0;
// if number of elements in the list if greater than a threshold,
// dump it in a separate line with specific name
- if (aDumpAsIs || theAttrSelList->size() <= aThreshold) {
+ if (aNbSpaces > 0 || theAttrSelList->size() <= aThreshold) {
*myDumpStorage << "[";
GeomShapePtr aShape;
if(isAdded) {
*myDumpStorage << ", ";
+ // print each attribute on separate line with the appropriate shift
+ if (aNbSpaces > 0) {
+ std::string aSpaces(aNbSpaces + 1, ' ');
+ *myDumpStorage << "\n" << aSpaces;
+ }
} else {
isAdded = true;
}
}
// reserve dumped buffer and store list "as is"
myDumpStorage->reserveBuffer();
- aDumpAsIs = true;
+ aNbSpaces = (int)aListName.size() + 3;
*this << aListName << " = " << theAttrSelList << "\n";
- aDumpAsIs = false;
+ aNbSpaces = 0;
// append reserved data to the end of the current buffer
myDumpStorage->restoreReservedBuffer();
*myDumpStorage << aListName;
return *this;
}
+void ModelHighAPI_Dumper::newline()
+{
+ *this << std::endl;
+}
+
/// Dump std::endl
ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
// store all not-dumped entities first
std::set<EntityPtr> aNotDumped = theDumper.myNotDumpedEntities;
+ theDumper.clearNotDumped();
theDumper.myDumpStorage->reserveBuffer();
std::set<EntityPtr>::const_iterator anIt = aNotDumped.begin();
for (; anIt != aNotDumped.end(); ++anIt) {
/// \return name of the entity
MODELHIGHAPI_EXPORT
const std::string& name(const EntityPtr& theEntity, bool theSaveNotDumped = true,
- bool theUseEntityName = false);
+ bool theUseEntityName = false, bool theSetIsDumped = false);
/// Returns name of parent composite feature for specified entity
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&));
+ /// Print std::endl from Python
+ MODELHIGHAPI_EXPORT void newline();
+
/// Dump GeomAPI_Pnt in the following form:
/// "GeomAPI_Pnt(X, Y, Z)"
MODELHIGHAPI_EXPORT
MODELHIGHAPI_EXPORT virtual void exportVariable(const std::string& /*theEntry*/,
const std::string& /*theVarName*/) const {}
+ /// Returns \c true if the special comment line to improve the readability
+ /// should be printed before the feature of the given kind.
+ MODELHIGHAPI_EXPORT bool dumpCommentBeforeFeature(const FeaturePtr& theFeature) const;
+
protected:
/// Dump "setName" command if last entity had user-defined name
MODELHIGHAPI_EXPORT void dumpEntitySetName();
if (isSketchFeatures) {
// do not control construction features of an ellipse and other
FeaturePtr aFeature = ModelAPI_Feature::feature(*aL);
- if (aFeature->getKind() == "SketchConstraintCoincidenceInternal")
- continue; // skip internal constraints
+ //if (aFeature->getKind() == "SketchConstraintCoincidenceInternal")
+ // continue; // skip internal constraints
+ std::string aStr = aFeature->getKind().substr(0, 16);
+ if (aStr == "SketchConstraint")
+ continue; // no need to dump and check constraints
}
aResList.push_back((*aL)->data()->name());
} else if (!isSketchFeatures) {
// 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:
for(; allIter != allObjects.end(); allIter++) {
ObjectPtr anObject = *allIter;
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
- if (aFeature && aFeature->getKind() == "SketchConstraintCoincidenceInternal")
- continue; // no need to dump and check internal constraints
+ //if (aFeature && aFeature->getKind() == "SketchConstraintCoincidenceInternal")
+ if (aFeature) {
+ std::string aStr = aFeature->getKind().substr(0, 16);
+ if (aStr == "SketchConstraint")
+ continue; // no need to dump and check constraints
+ }
if (theCompare) {
std::map<std::string, ModelHighAPI_FeatureStore>::iterator
anObjFind = aDocFind->second.find(anObject->data()->name());
aCaseId = QString::fromStdString(aStringAttr->value());
else
aCaseId = QString::fromStdString(aDefVal.empty() ? aStringAttr->value() : aDefVal);
- myIsFirst = false;
+ if (myIsFirst)
+ storeValueCustom();
int idx = myCaseIds.indexOf(aCaseId);
if (idx == -1)
idx = currentPageIndex();
myHaveFrame = theData->getBooleanAttribute("has_frame", true);
myEnableOnCheck = theData->getBooleanAttribute("enable_on_check", true);
+ myAlwaysShowTitle = theData->getBooleanAttribute("show_title", false);
bool isChecked = theData->getBooleanAttribute(ATTR_DEFAULT, false);
setDefaultValue(isChecked ? "true" : "false");
myCheckBoxLayout = new QHBoxLayout(myCheckBoxFrame);
ModuleBase_Tools::adjustMargins(myCheckBoxLayout);
- myCheckBox = new QCheckBox(myCheckBoxFrame);
+ if (myAlwaysShowTitle)
+ myCheckBox = new QCheckBox(translate(myGroupTitle), myCheckBoxFrame);
+ else
+ myCheckBox = new QCheckBox(myCheckBoxFrame);
myCheckBox->setChecked(getDefaultValue() == "true");
myCheckBoxLayout->addWidget(myCheckBox);
bool myHaveFrame;
bool myEnableOnCheck;
+ bool myAlwaysShowTitle;
};
#endif /* ModuleBase_WidgetOptionalBox_H_ */
#include <ModuleBase_WidgetRadiobox.h>
#include <ModuleBase_PageBase.h>
+#include <Config_WidgetAPI.h>
+
#include <QFormLayout>
#include <QRadioButton>
#include <QFrame>
#include <QButtonGroup>
-
ModuleBase_WidgetRadiobox::ModuleBase_WidgetRadiobox(QWidget* theParent,
const Config_WidgetAPI* theData)
: ModuleBase_PagedContainer(theParent, theData)
myGroup = new QButtonGroup(this);
myGroup->setExclusive(true);
+ myVerticalAlignment = theData->getProperty("align_subs").find("vert") == 0;
+
connect(myGroup, SIGNAL(buttonToggled(int, bool)), SLOT(onPageChanged()));
}
//QFrame* aFrame = dynamic_cast<QFrame*>(thePage);
QWidget* aPage = thePage->pageWidget();
- myLayout->addRow(aWgt, aPage);
+ if (myVerticalAlignment) {
+ myLayout->addRow(aWgt);
+ myLayout->addRow(aPage);
+ } else
+ myLayout->addRow(aWgt, aPage);
myGroup->addButton(aButton, myGroup->buttons().count());
bool isDefault = theCaseId.toStdString() == getDefaultValue();
private:
QFormLayout* myLayout;
QButtonGroup* myGroup;
+ bool myVerticalAlignment;
};
#endif
\ No newline at end of file
#include <Config_PropManager.h>
#include <Events_Loop.h>
#include <ModelAPI_Events.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
#include <AIS_InteractiveContext.hxx>
#include <AIS_InteractiveObject.hxx>
{
Events_Loop* aLoop = Events_Loop::loop();
aLoop->registerListener(this, Events_Loop::eventByName(EVENT_EMPTY_OPERATION_PRESENTATION));
+ aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OPERATION_SHAPES_FAILED));
initPresentation(ModuleBase_IModule::CustomizeArguments);
initPresentation(ModuleBase_IModule::CustomizeResults);
{
myIsActive[theFlag] = false;
erasePresentation(theFlag, theUpdateViewer);
+ if (theFlag == ModuleBase_IModule::CustomizeResults)
+ clearErrorShape();
return true;
}
clearPresentation(ModuleBase_IModule::CustomizeArguments);
clearPresentation(ModuleBase_IModule::CustomizeResults);
clearPresentation(ModuleBase_IModule::CustomizeHighlightedObjects);
+ clearErrorShape();
+}
+
+void PartSet_CustomPrs::clearErrorShape()
+{
+ if (!myErrorShapes.IsNull()) {
+ Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
+ if (aContext->IsDisplayed(myErrorShapes)) {
+ aContext->Remove(myErrorShapes, true);
+ myErrorShapes.Nullify();
+ }
+ }
}
void PartSet_CustomPrs::processEvent(const std::shared_ptr<Events_Message>& theMessage)
{
if (theMessage->eventID() == Events_Loop::eventByName(EVENT_EMPTY_OPERATION_PRESENTATION))
myPresentationIsEmpty = true; /// store state to analize it after display/erase is finished
+ else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_OPERATION_SHAPES_FAILED)) {
+ std::shared_ptr<ModelAPI_ShapesFailedMessage> aErrMsg =
+ std::dynamic_pointer_cast<ModelAPI_ShapesFailedMessage>(theMessage);
+ Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
+ ListOfShape aShapes = aErrMsg->shapes();
+ if (aShapes.size() > 0) {
+ GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+ TopoDS_Shape aErrShape = aCompound->impl<TopoDS_Shape>();
+ if (myErrorShapes.IsNull()) {
+ myErrorShapes = new AIS_Shape(aErrShape);
+ myErrorShapes->SetColor(Quantity_NOC_RED);
+ Handle(Prs3d_Drawer) aDrawer = myErrorShapes->Attributes();
+ aDrawer->SetPointAspect(new Prs3d_PointAspect(Aspect_TOM_RING1, Quantity_NOC_RED, 2.));
+ aDrawer->SetLineAspect(new Prs3d_LineAspect(Quantity_NOC_RED, Aspect_TOL_SOLID, 2.));
+ aContext->Display(myErrorShapes, true);
+ aContext->Deactivate(myErrorShapes);
+ }
+ else {
+ myErrorShapes->Set(aErrShape);
+ aContext->Redisplay(myErrorShapes, true);
+ }
+ }
+ else {
+ if (!myErrorShapes.IsNull()) {
+ aContext->Remove(myErrorShapes, true);
+ myErrorShapes.Nullify();
+ }
+ }
+ }
}
void PartSet_CustomPrs::initPresentation(
/// \return theShapeColor a color
Quantity_Color getShapeColor(const ModuleBase_IModule::ModuleBase_CustomizeFlag& theFlag);
+ /// Removes error shapes presentation
+ void clearErrorShape();
+
private:
ModuleBase_IWorkshop* myWorkshop; /// current workshop
FeaturePtr myFeature; /// Reference to a feature object
QMap<ModuleBase_IModule::ModuleBase_CustomizeFlag, bool> myIsActive;
int myDisabledMode;
+
+ Handle(AIS_Shape) myErrorShapes;
};
#endif
#include <SelectMgr_ListIteratorOfListOfFilter.hxx>
+#define FEATURE_ITEM_COLOR "0,0,225"
+
+
/*!Create and return new instance of XGUI_Module*/
extern "C" PARTSET_EXPORT ModuleBase_IModule* createModule(ModuleBase_IWorkshop* theWshop)
{
"Dimension color",
Config_Prop::Color, SKETCH_DIMENSION_COLOR);
+ Config_PropManager::registerProp("Visualization", "feature_objectbrowser_color",
+ "Feature items in Object Browser",
+ Config_Prop::Color, FEATURE_ITEM_COLOR);
+
Config_PropManager::registerProp("Shortcuts", "add_parameter_shortcut",
"Add parameter in parameters manager dialog",
Config_Prop::Shortcut, "Ctrl+A");
GeomShapePtr theGeomShape,
QMap<ObjectPtr, QList<GeomShapePtr> >& theObjectShapes)
{
- //XGUI_Displayer* aDisplayer = XGUI_Tools::workshop(theWorkshop)->displayer();
- //// VSV: Do not use isVisible checking because it can be used when state "Show Only" is ON
- //if (XGUI_Displayer::isVisible(aDisplayer, theObject)) {
- if (theGeomShape.get()) {
- if (theObjectShapes.contains(theObject))
- theObjectShapes[theObject].append(theGeomShape);
- else {
- QList<GeomShapePtr> aShapes;
- aShapes.append(theGeomShape);
- theObjectShapes[theObject] = aShapes;
- }
- } else {
- #ifdef DEBUG_EMPTY_SHAPE
- qDebug(QString("Empty shape in result, result: %1")
- .arg(ModuleBase_Tools::objectInfo(theObject)).toStdString().c_str());
- #endif
+ if (theGeomShape.get()) {
+ if (theObjectShapes.contains(theObject))
+ theObjectShapes[theObject].append(theGeomShape);
+ else {
+ QList<GeomShapePtr> aShapes;
+ aShapes.append(theGeomShape);
+ theObjectShapes[theObject] = aShapes;
}
- //}
+ } else {
+#ifdef DEBUG_EMPTY_SHAPE
+ qDebug(QString("Empty shape in result, result: %1")
+ .arg(ModuleBase_Tools::objectInfo(theObject)).toStdString().c_str());
+#endif
+ }
}
void PartSet_OperationPrs::getFeatureShapes(const FeaturePtr& theFeature,
myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
if (isRelaunchEditing)
launchEditing();
+ else {
+ if (myCurrentSelection.size() > 1)
+ aFOperation->propertyPanel()->cleanContent();
+ }
myIsEditLaunching = aPrevLaunchingState;
if (aFeature.get() != NULL) {
std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
for (aIt = aRefsToMe.cbegin(); aIt != aRefsToMe.cend(); ++aIt) {
if ((*aIt)->id() == SketchPlugin_Projection::PROJECTED_FEATURE_ID()) {
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
- if (aFeature.get()) {
+ if (aFeature.get() && !aFeature->isMacro()) {
anAttr = aFeature->data()->boolean(SketchPlugin_Projection::INCLUDE_INTO_RESULT());
if (anAttr.get())
return anAttr->value();
thePrs->setWidth(17);
// thePrs->setPointMarker(1, 1.); // Set point as a '+' symbol
}
- if (isCopy(aFeature) && !isIncludeToResult(aFeature)) {
+ if (isCopy(aFeature) || !isIncludeToResult(aFeature)) {
double aPrsWidth = thePrs->width();
thePrs->setWidth(aPrsWidth / 2.5);
}
std::shared_ptr<GeomAPI_Pnt2d> myClickedSketchPoint; /// cashed clicked point
bool myIsAutoConstraints;
+ void* myLastAutoConstraint; //< Stores address of last automatic constraint.
+ //< Cannot be used as a pointer!!!
};
#endif
#include <ModelAPI_Folder.h>
#include <ModelAPI_AttributeReference.h>
+#include <Config_PropManager.h>
+
#include <QBrush>
#include <QMap>
else
return QIcon();
}
+ case Qt::ForegroundRole:
+ if (myObject->groupName() == ModelAPI_Feature::group()) {
+ std::vector<int> aColor =
+ Config_PropManager::color("Visualization", "feature_objectbrowser_color");
+ return QColor(aColor[0], aColor[1], aColor[2]);
+ }
+ break;
}
return PartSet_TreeNode::data(theColumn, theRole);
}
return aResult;
}
+QVariant PartSet_ObjectFolderNode::data(int theColumn, int theRole) const
+{
+ if (theRole == Qt::ForegroundRole) {
+ std::vector<int> aColor =
+ Config_PropManager::color("Visualization", "feature_objectbrowser_color");
+ return QColor(aColor[0], aColor[1], aColor[2]);
+ }
+ return PartSet_ObjectNode::data(theColumn, theRole);
+}
//////////////////////////////////////////////////////////////////////////////////
QVariant PartSet_StepNode::data(int theColumn, int theRole) const
/// \param theDoc a document where objects were deleted
/// \param theGroup a name of group where objects were deleted
virtual QTreeNodesList objectsDeleted(const DocumentPtr& theDoc, const QString& theGroup);
+
+ /// Returns the node representation according to theRole.
+ virtual QVariant data(int theColumn, int theRole) const;
};
ModuleBase_Tools::zeroMargins(aLayout);
QGroupBox* aViewBox = new QGroupBox(tr("Sketcher plane"), this);
- QVBoxLayout* aViewLayout = new QVBoxLayout(aViewBox);
+ QGridLayout* aViewLayout = new QGridLayout(aViewBox);
myViewInverted = new QCheckBox(tr("Reversed"), aViewBox);
- aViewLayout->addWidget(myViewInverted);
+ aViewLayout->addWidget(myViewInverted, 0, 0);
+
+ myViewVisible = new QCheckBox(tr("Visible"), aViewBox);
+ myViewVisible->setChecked(true);
+ aViewLayout->addWidget(myViewVisible, 0, 1, Qt::AlignRight);
+ connect(myViewVisible, SIGNAL(toggled(bool)), this, SLOT(onShowViewPlane(bool)));
QPushButton* aSetViewBtn =
new QPushButton(QIcon(":icons/plane_view.png"), tr("Set plane view"), aViewBox);
connect(aSetViewBtn, SIGNAL(clicked(bool)), this, SLOT(onSetPlaneView()));
- aViewLayout->addWidget(aSetViewBtn);
+ aViewLayout->addWidget(aSetViewBtn, 1, 0, 1, 2);
aLayout->addWidget(aViewBox);
bool aDone = false;
if (theValues.empty()) {
// In order to make reselection possible, set empty object and shape should be done
- setSelectionCustom(std::shared_ptr<ModuleBase_ViewerPrs>(
+ setSelectionCustom(ModuleBase_ViewerPrsPtr(
new ModuleBase_ViewerPrs(ObjectPtr(), GeomShapePtr(), NULL)));
aDone = false;
}
CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
aModule->sketchMgr()->previewSketchPlane()->setSizeOfView(aSizeOfView, isSetSizeOfView);
// Call of createSketchPlane is managed by events Loop
- //aModule->sketchMgr()->previewSketchPlane()->createSketchPlane(aSketch, myWorkshop);
+ //if (myViewVisible->isChecked())
+ // aModule->sketchMgr()->previewSketchPlane()->createSketchPlane(aSketch, myWorkshop);
}
// 2. if the planes were displayed, change the view projection
//******************************************************
-QList<std::shared_ptr<ModuleBase_ViewerPrs>> PartSet_WidgetSketchLabel::findCircularEdgesInPlane()
+QList<ModuleBase_ViewerPrsPtr> PartSet_WidgetSketchLabel::findCircularEdgesInPlane()
{
QList<std::shared_ptr<ModuleBase_ViewerPrs>> aResult;
XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
bool isContains = false;
// Check that edge is not used.
// It is possible that the same edge will be taken from different faces
- foreach(std::shared_ptr<ModuleBase_ViewerPrs> aPrs, aResult) {
+ foreach(ModuleBase_ViewerPrsPtr aPrs, aResult) {
GeomAPI_Edge aUsedEdge(aPrs->shape());
if (aUsedEdge.isEqual(aEdgeShape)) {
isContains = true;
}
}
if (!isContains) {
- std::shared_ptr<ModuleBase_ViewerPrs>
- aPrs(new ModuleBase_ViewerPrs(aResObj, aEdgeShape));
+ ModuleBase_ViewerPrsPtr aPrs(new ModuleBase_ViewerPrs(aResObj, aEdgeShape));
aResult.append(aPrs);
}
}
onShowPanel();
}
return ModuleBase_WidgetValidated::eventFilter(theObj, theEvent);
-}
\ No newline at end of file
+}
+
+void PartSet_WidgetSketchLabel::onShowViewPlane(bool toShow)
+{
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+ if (toShow) {
+ CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
+ aModule->sketchMgr()->previewSketchPlane()->createSketchPlane(aSketch, myWorkshop);
+ }
+ else {
+ aModule->sketchMgr()->previewSketchPlane()->eraseSketchPlane(myWorkshop, false);
+ }
+ myWorkshop->viewer()->update();
+}
#include <ModuleBase_WidgetValidated.h>
#include <ModuleBase_ViewerFilters.h>
+#include <ModuleBase_ViewerPrs.h>
#include <GeomAPI_Dir.h>
/// Returns True if the selected presentation can be used for plane definition
/// \param thePrs a presentation
- static bool canFillSketch(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+ static bool canFillSketch(const ModuleBase_ViewerPrsPtr& thePrs);
/// If widgets has several panels then this method has to show a page which contains information
/// for current feature. By default does nothing
/// Fills the attribute with the value of the selected owner
/// \param thePrs a selected owner
- virtual bool setSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+ virtual bool setSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs);
/// Saves the internal parameters to the given feature
/// \return True in success
/// It is redefined to do nothing if the plane of the sketch has been already set.
/// \param theValues the wrapped selection values
/// \param theToValidate a validation flag
- bool setSelectionInternal(const QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues,
+ bool setSelectionInternal(const QList<ModuleBase_ViewerPrsPtr>& theValues,
const bool theToValidate);
/// Erase preview planes, disconnect widget, change the view projection
/// \param thePrs a selected presentation
- void updateByPlaneSelected(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+ void updateByPlaneSelected(const ModuleBase_ViewerPrsPtr& thePrs);
/// Set sketch plane from selected object
/// \param theFeature a feature of sketch
/// \param thePrs a presentation
- bool fillSketchPlaneBySelection(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+ bool fillSketchPlaneBySelection(const ModuleBase_ViewerPrsPtr& thePrs);
/// Redefinition of a virtual function
virtual void showEvent(QShowEvent* theEvent);
/// \param theOn a flag show constraints or not
void onShowConstraint(bool theOn);
+ /// A a slot called on "Change sketch plane" check box toggele
void onChangePlane();
+ /// A a slot called on "Show remaining DOFs" check box toggele
void onShowDOF();
+ /// A a slot called on changing the panel visibility
void onShowPanel();
+ /// A slot which is called on "Visible" plane checkbox toggle
+ void onShowViewPlane(bool);
+
private:
/// Set sketch plane by shape
/// \param theShape a planar face
* (circles, arcs) which are in pane of of the given sketch
* \param theSketch - the sketch
*/
- QList<std::shared_ptr<ModuleBase_ViewerPrs>> findCircularEdgesInPlane();
+ QList<ModuleBase_ViewerPrsPtr> findCircularEdgesInPlane();
private:
/// class to show/hide preview planes
PartSet_PreviewPlanes* myPreviewPlanes;
QCheckBox* myViewInverted;
+ QCheckBox* myViewVisible;
QCheckBox* myRemoveExternal;
QCheckBox* myShowPoints;
QCheckBox* myAutoConstraints;
## Create wrapper for a given feature and dump it
def dumpFeature(self, theFeature, theForce):
+ aDumper = None
aFeatureKind = theFeature.getKind()
if aFeatureKind in self.myFeatures:
# Dump only feature created by user (in history).
# Also dump Export and RemoveResults features (hard-coded here in order not to change the data model).
# For all other features, just keep their name.
if theForce or theFeature.isInHistory() or aFeatureKind=="Export" or aFeatureKind=="RemoveResults":
- self.myFeatures[aFeatureKind](theFeature).dump(self)
+ aDumper = self.myFeatures[aFeatureKind](theFeature)
+ # Dump comment for the operation before the dumping of the feature to improve the readability of a script.
+ if self.dumpCommentBeforeFeature(theFeature):
+ self.__print__("\n### Create " + theFeature.getKind())
+ self.newline()
else:
self.name(theFeature)
self.clearNotDumped()
else:
# Probably the feature is a constraint, try to dump it with SketchAPI_Constraint.
# In case of theFeature is not a constraint, it will not be dumped.
- self.myFeatures[SketchAPI.SketchAPI_Constraint.ID()](theFeature).dump(self)
+ self.name(theFeature, False, True, True)
+ aDumper = self.myFeatures[SketchAPI.SketchAPI_Constraint.ID()](theFeature)
+ if aDumper is not None:
+ aDumper.dump(self)
## Create wrapper for a folder and dump it
def dumpFolder(self, theFolder):
SketchAPI_MacroEllipse.h
SketchAPI_MacroEllipticArc.h
SketchAPI_Mirror.h
+ SketchAPI_Offset.h
SketchAPI_Point.h
SketchAPI_Projection.h
SketchAPI_Rectangle.h
SketchAPI_MacroEllipse.cpp
SketchAPI_MacroEllipticArc.cpp
SketchAPI_Mirror.cpp
+ SketchAPI_Offset.cpp
SketchAPI_Point.cpp
SketchAPI_Projection.cpp
SketchAPI_Rectangle.cpp
%feature("kwargs") SketchAPI_BSpline::controlPolygon;
%feature("kwargs") SketchAPI_Ellipse::construction;
%feature("kwargs") SketchAPI_EllipticArc::construction;
+%feature("kwargs") SketchAPI_Sketch::addApproximation;
+%feature("kwargs") SketchAPI_Sketch::addInterpolation;
+%feature("kwargs") SketchAPI_Sketch::addProjection;
%feature("kwargs") SketchAPI_Sketch::addSpline;
%feature("kwargs") SketchAPI_Sketch::setAngle;
%shared_ptr(SketchAPI_IntersectionPoint)
%shared_ptr(SketchAPI_Line)
%shared_ptr(SketchAPI_Mirror)
+%shared_ptr(SketchAPI_Offset)
%shared_ptr(SketchAPI_Sketch)
%shared_ptr(SketchAPI_SketchEntity)
%shared_ptr(SketchAPI_Point)
%include "SketchAPI_BSpline.h"
%include "SketchAPI_Projection.h"
%include "SketchAPI_Mirror.h"
+%include "SketchAPI_Offset.h"
%include "SketchAPI_Translation.h"
%include "SketchAPI_Rectangle.h"
%include "SketchAPI_Rotation.h"
return;
const std::string& aSketchName = theDumper.parentName(aBase);
- theDumper << aBase << " = " << aSketchName << "." << aSetter << "(";
+ theDumper << aSketchName << "." << aSetter << "(";
bool isFirstAttr = true;
for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
FeaturePtr aBase = feature();
const std::string& aSketchName = theDumper.parentName(aBase);
- theDumper << aBase << " = " << aSketchName << "." << "setAngle(";
+ theDumper.name(aBase, false, true, true); // mark constraint as dumped
+ theDumper << aSketchName << "." << "setAngle(";
bool isFirstAttr = true;
for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
--- /dev/null
+// Copyright (C) 2014-2019 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 "SketchAPI_Offset.h"
+#include <SketchAPI_SketchEntity.h>
+//--------------------------------------------------------------------------------------
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+//--------------------------------------------------------------------------------------
+SketchAPI_Offset::SketchAPI_Offset (const std::shared_ptr<ModelAPI_Feature> & theFeature)
+ : ModelHighAPI_Interface(theFeature)
+{
+ initialize();
+}
+
+SketchAPI_Offset::SketchAPI_Offset (const std::shared_ptr<ModelAPI_Feature> & theFeature,
+ const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
+ const ModelHighAPI_Double & theOffsetValue,
+ bool theIsReversed)
+ : ModelHighAPI_Interface(theFeature)
+{
+ if (initialize()) {
+ fillAttribute(theObjects, edgesList());
+ fillAttribute(theOffsetValue, value());
+ fillAttribute(theIsReversed, reversed());
+
+ execute();
+ }
+}
+
+SketchAPI_Offset::~SketchAPI_Offset()
+{
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Offset::offset() const
+{
+ std::list<ObjectPtr> aList = feature()->reflist(SketchPlugin_Constraint::ENTITY_B())->list();
+ std::list<FeaturePtr> anIntermediate;
+ std::list<ObjectPtr>::const_iterator anIt = aList.begin();
+ for (; anIt != aList.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ anIntermediate.push_back(aFeature);
+ }
+ return SketchAPI_SketchEntity::wrap(anIntermediate);
+}
+
+//--------------------------------------------------------------------------------------
+
+void SketchAPI_Offset::dump (ModelHighAPI_Dumper& theDumper) const
+{
+ FeaturePtr aBase = feature();
+ const std::string& aSketchName = theDumper.parentName(aBase);
+
+ AttributeRefListPtr aOffsetObjects = edgesList();
+ AttributeDoublePtr aValue = value();
+ AttributeBooleanPtr aReversed = reversed();
+
+ // Check all attributes are already dumped. If not, store the feature as postponed.
+ if (!theDumper.isDumped(aOffsetObjects)) {
+ theDumper.postpone(aBase);
+ return;
+ }
+
+ theDumper << aBase << " = " << aSketchName << ".addOffset(" << aOffsetObjects << ", "
+ << aValue << ", " << aReversed << ")" << std::endl;
+
+ // Dump variables for a list of created features
+ theDumper << "[";
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > aList = offset();
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> >::const_iterator anIt = aList.begin();
+ for (; anIt != aList.end(); ++anIt) {
+ if (anIt != aList.begin())
+ theDumper << ", ";
+ theDumper << (*anIt)->feature();
+ }
+ theDumper << "] = " << theDumper.name(aBase) << ".offset()" << std::endl;
+
+//// // Set necessary "auxiliary" flag for created features
+//// // (flag is set if it differs to anAux)
+//// for (anIt = aList.begin(); anIt != aList.end(); ++anIt) {
+//// FeaturePtr aFeature = (*anIt)->feature();
+//// bool aFeatAux = aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value();
+//// if (aFeatAux != anAux->value())
+//// theDumper << theDumper.name((*anIt)->feature(), false)
+//// << ".setAuxiliary(" << aFeatAux << ")" <<std::endl;
+//// }
+}
--- /dev/null
+// Copyright (C) 2014-2019 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 SRC_SKETCHAPI_SKETCHAPI_OFFSET_H_
+#define SRC_SKETCHAPI_SKETCHAPI_OFFSET_H_
+
+//--------------------------------------------------------------------------------------
+#include "SketchAPI.h"
+#include "SketchAPI_SketchEntity.h"
+
+#include <list>
+
+#include <SketchPlugin_Offset.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+//--------------------------------------------------------------------------------------
+class ModelAPI_Object;
+class ModelHighAPI_RefAttr;
+class ModelHighAPI_Double;
+//--------------------------------------------------------------------------------------
+/**\class SketchAPI_Offset
+ * \ingroup CPPHighAPI
+ * \brief Interface for Offset feature
+ */
+class SketchAPI_Offset : public ModelHighAPI_Interface
+{
+public:
+ /// Constructor without values
+ SKETCHAPI_EXPORT
+ explicit SketchAPI_Offset(const std::shared_ptr<ModelAPI_Feature> & theFeature);
+ /// Constructor with values
+ SKETCHAPI_EXPORT
+ SketchAPI_Offset(const std::shared_ptr<ModelAPI_Feature> & theFeature,
+ const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
+ const ModelHighAPI_Double & theOffsetValue,
+ bool theIsReversed);
+ /// Destructor
+ SKETCHAPI_EXPORT
+ virtual ~SketchAPI_Offset();
+
+ INTERFACE_3(SketchPlugin_Offset::ID(),
+
+ edgesList, SketchPlugin_Offset::EDGES_ID(),
+ ModelAPI_AttributeRefList, /** Offset edges list */,
+
+ value, SketchPlugin_Offset::VALUE_ID(),
+ ModelAPI_AttributeDouble, /** Value */,
+
+ reversed, SketchPlugin_Offset::REVERSED_ID(),
+ ModelAPI_AttributeBoolean, /** Negative value */
+ )
+
+ /// List of created objects
+ SKETCHAPI_EXPORT
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > offset() const;
+
+ /// Dump wrapped feature
+ virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+//! Pointer on Offset object
+typedef std::shared_ptr<SketchAPI_Offset> OffsetPtr;
+
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+#endif /* SRC_SKETCHAPI_SKETCHAPI_OFFSET_H_ */
}
}
-SketchAPI_Projection::SketchAPI_Projection(
- const std::shared_ptr<ModelAPI_Feature> & theFeature,
- const std::string & theExternalName)
-: SketchAPI_SketchEntity(theFeature)
-{
- if (initialize()) {
- setByExternalName(theExternalName);
- }
-}
-
SketchAPI_Projection::~SketchAPI_Projection()
{
execute(true);
}
-void SketchAPI_Projection::setByExternalName(const std::string& theExternalName)
+void SketchAPI_Projection::setIncludeToResult(bool theKeepResult)
{
- setExternalFeature(ModelHighAPI_Selection("EDGE", theExternalName));
+ fillAttribute(theKeepResult, includeToResult());
+ execute(true);
}
-void SketchAPI_Projection::setIncludeToResult(bool theKeepResult)
+void SketchAPI_Projection::setKeepReferenceToOriginal(bool theKeepRefToOriginal)
{
- fillAttribute(theKeepResult, includeToResult());
+ // the Fixed constraint should be assigned explicitly
+ fillAttribute(false, feature()->boolean(SketchPlugin_Projection::MAKE_FIXED()));
+ fillAttribute(theKeepRefToOriginal ? "true" : "false",
+ feature()->string(SketchPlugin_Projection::KEEP_REFERENCE_ID()));
execute(true);
}
SKETCHAPI_EXPORT
SketchAPI_Projection(const std::shared_ptr<ModelAPI_Feature> & theFeature,
const ModelHighAPI_Selection & theExternalFeature);
- /// Constructor with values
- SKETCHAPI_EXPORT
- SketchAPI_Projection(const std::shared_ptr<ModelAPI_Feature> & theFeature,
- const std::string & theExternalName);
/// Destructor
SKETCHAPI_EXPORT
virtual ~SketchAPI_Projection();
SKETCHAPI_EXPORT
void setExternalFeature(const ModelHighAPI_Selection & theExternalLine);
- /// Set by external name
- SKETCHAPI_EXPORT
- void setByExternalName(const std::string & theExternalName);
-
/// Set flag to include projection to result or not
SKETCHAPI_EXPORT
void setIncludeToResult(bool theKeepResult);
+ /// Set flag to keep the reference to the original shape
+ SKETCHAPI_EXPORT
+ void setKeepReferenceToOriginal(bool theKeepRefToOriginal);
+
/// Returns created feature
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_SketchEntity> createdFeature() const;
#include <SketchPlugin_ConstraintPerpendicular.h>
#include <SketchPlugin_ConstraintRadius.h>
#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_CurveFitting.h>
#include <SketchPlugin_Trim.h>
#include <SketchPlugin_Split.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
#include <SketchPlugin_MacroBSpline.h>
#include <SketchPlugin_SketchCopy.h>
+#include <SketchPlugin_Offset.h>
#include <SketcherPrs_Tools.h>
//--------------------------------------------------------------------------------------
#include <ModelAPI_Events.h>
#include "SketchAPI_MacroEllipse.h"
#include "SketchAPI_MacroEllipticArc.h"
#include "SketchAPI_Mirror.h"
+#include "SketchAPI_Offset.h"
#include "SketchAPI_Point.h"
#include "SketchAPI_Projection.h"
#include "SketchAPI_Rectangle.h"
}
//--------------------------------------------------------------------------------------
-std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
- const ModelHighAPI_Selection & theExternalFeature,
- bool theKeepResult)
+static std::shared_ptr<SketchAPI_BSpline> buildInterpolation(
+ const CompositeFeaturePtr& theSketch,
+ const FeaturePtr& theCurveFittingFeature,
+ const std::list<ModelHighAPI_RefAttr>& points,
+ const bool periodic,
+ const bool closed)
+{
+ AttributeBooleanPtr aPeriodicAttr =
+ theCurveFittingFeature->boolean(SketchPlugin_CurveFitting::PERIODIC_ID());
+ fillAttribute(periodic, aPeriodicAttr);
+ AttributeBooleanPtr aClosedAttr =
+ theCurveFittingFeature->boolean(SketchPlugin_CurveFitting::CLOSED_ID());
+ fillAttribute(closed, aClosedAttr);
+ AttributeRefAttrListPtr aPointsAttr =
+ theCurveFittingFeature->refattrlist(SketchPlugin_CurveFitting::POINTS_ID());
+ fillAttribute(points, aPointsAttr);
+ apply(); // to execute and kill the macro-feature
+
+ // find created B-spline feature
+ BSplinePtr aBSpline;
+ const std::string& aKindToFind =
+ periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID();
+ int aNbSubs = theSketch->numberOfSubs();
+ for (int anIndex = aNbSubs - 1; anIndex >= 0; --anIndex) {
+ FeaturePtr aFeature = theSketch->subFeature(anIndex);
+ if (aFeature->getKind() == aKindToFind) {
+ aBSpline.reset(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
+ : new SketchAPI_BSpline(aFeature));
+ aBSpline->execute();
+ break;
+ }
+ }
+ return aBSpline;
+}
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addInterpolation(
+ const std::list<ModelHighAPI_RefAttr>& points,
+ const bool periodic,
+ const bool closed)
{
- std::shared_ptr<ModelAPI_Feature> aFeature =
- compositeFeature()->addFeature(SketchPlugin_Projection::ID());
- ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalFeature));
- aProjection->setIncludeToResult(theKeepResult);
- return aProjection;
+ CompositeFeaturePtr aSketch = compositeFeature();
+ FeaturePtr anInterpFeature = aSketch->addFeature(SketchPlugin_CurveFitting::ID());
+ anInterpFeature->string(SketchPlugin_CurveFitting::TYPE_ID())
+ ->setValue(SketchPlugin_CurveFitting::TYPE_INTERPOLATION_ID());
+ return buildInterpolation(aSketch, anInterpFeature, points, periodic, closed);
+}
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addApproximation(
+ const std::list<ModelHighAPI_RefAttr>& points,
+ const ModelHighAPI_Double& precision,
+ const bool periodic,
+ const bool closed)
+{
+ CompositeFeaturePtr aSketch = compositeFeature();
+ FeaturePtr anInterpFeature = aSketch->addFeature(SketchPlugin_CurveFitting::ID());
+ anInterpFeature->string(SketchPlugin_CurveFitting::TYPE_ID())
+ ->setValue(SketchPlugin_CurveFitting::TYPE_APPROXIMATION_ID());
+ fillAttribute(precision, anInterpFeature->real(SketchPlugin_CurveFitting::PRECISION_ID()));
+ return buildInterpolation(aSketch, anInterpFeature, points, periodic, closed);
}
+//--------------------------------------------------------------------------------------
std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
- const std::string & theExternalName,
- bool theKeepResult)
+ const ModelHighAPI_Selection & theExternalFeature,
+ bool keepResult,
+ bool keepRefToOriginal)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_Projection::ID());
- ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalName));
- aProjection->setIncludeToResult(theKeepResult);
+ ProjectionPtr aProjection(new SketchAPI_Projection(aFeature));
+ aProjection->setIncludeToResult(keepResult);
+ aProjection->setKeepReferenceToOriginal(keepRefToOriginal);
+ aProjection->setExternalFeature(theExternalFeature);
return aProjection;
}
return MirrorPtr(new SketchAPI_Mirror(aFeature, theMirrorLine, theObjects));
}
+//--------------------------------------------------------------------------------------
+std::shared_ptr<SketchAPI_Offset> SketchAPI_Sketch::addOffset(
+ const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
+ const ModelHighAPI_Double & theValue,
+ const bool theReversed)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature =
+ compositeFeature()->addFeature(SketchPlugin_Offset::ID());
+ return OffsetPtr(new SketchAPI_Offset(aFeature, theObjects, theValue, theReversed));
+}
+
//--------------------------------------------------------------------------------------
std::shared_ptr<SketchAPI_Translation> SketchAPI_Sketch::addTranslation(
const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
#include <SketchPlugin_Sketch.h>
#include <SketchPlugin_SketchEntity.h>
+#include <ModelHighAPI_Double.h>
#include <ModelHighAPI_Interface.h>
#include <ModelHighAPI_Macro.h>
#include <ModelHighAPI_Selection.h>
//--------------------------------------------------------------------------------------
class ModelAPI_CompositeFeature;
class ModelAPI_Object;
-class ModelHighAPI_Double;
class ModelHighAPI_Integer;
class ModelHighAPI_RefAttr;
class ModelHighAPI_Reference;
class SketchAPI_IntersectionPoint;
class SketchAPI_Line;
class SketchAPI_Mirror;
+class SketchAPI_Offset;
class SketchAPI_Point;
class SketchAPI_Projection;
class SketchAPI_Rectangle;
const std::list<ModelHighAPI_Integer>& multiplicities = std::list<ModelHighAPI_Integer>(),
const bool periodic = false);
- /// Add projection
+ /// Add interpolation feature
SKETCHAPI_EXPORT
- std::shared_ptr<SketchAPI_Projection> addProjection(
- const ModelHighAPI_Selection & theExternalFeature,
- bool theKeepResult = false);
+ std::shared_ptr<SketchAPI_BSpline> addInterpolation(
+ const std::list<ModelHighAPI_RefAttr>& points,
+ const bool periodic = false,
+ const bool closed = false);
+
+ /// Add approximation feature
+ SKETCHAPI_EXPORT
+ std::shared_ptr<SketchAPI_BSpline> addApproximation(
+ const std::list<ModelHighAPI_RefAttr>& points,
+ const ModelHighAPI_Double& precision = ModelHighAPI_Double(1.e-3),
+ const bool periodic = false,
+ const bool closed = false);
/// Add projection
SKETCHAPI_EXPORT
- std::shared_ptr<SketchAPI_Projection> addProjection(const std::string & theExternalName,
- bool theKeepResult = false);
+ std::shared_ptr<SketchAPI_Projection> addProjection(
+ const ModelHighAPI_Selection & theExternalFeature,
+ bool keepResult = false,
+ bool keepRefToOriginal = true);
/// Add mirror
SKETCHAPI_EXPORT
const ModelHighAPI_RefAttr & theMirrorLine,
const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects);
+ /// Add offset
+ SKETCHAPI_EXPORT
+ std::shared_ptr<SketchAPI_Offset> addOffset(
+ const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
+ const ModelHighAPI_Double & theValue,
+ const bool theReversed);
+
/// Add translation
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_Translation> addTranslation(
#include "SketchAPI_IntersectionPoint.h"
#include "SketchAPI_Line.h"
#include "SketchAPI_Mirror.h"
+ #include "SketchAPI_Offset.h"
#include "SketchAPI_Sketch.h"
#include "SketchAPI_SketchEntity.h"
#include "SketchAPI_Point.h"
def test_arc_by_projection(self):
""" Test 10. Create arc by projection of external feature
"""
- self.sketch.addProjection("[Cylinder_2_1/Face_1][Cylinder_2_1/Face_3]")
+ self.sketch.addProjection(model.selection("EDGE", "[Cylinder_2_1/Face_1][Cylinder_2_1/Face_3]"))
model.do()
anArc = SketchAPI.SketchAPI_Arc(model.lastSubFeature(self.sketch, "SketchArc"))
SketchPlugin_ConstraintRigid.h
SketchPlugin_ConstraintTangent.h
SketchPlugin_ConstraintVertical.h
+ SketchPlugin_CurveFitting.h
SketchPlugin_Ellipse.h
SketchPlugin_EllipticArc.h
SketchPlugin_ExternalValidator.h
SketchPlugin_MacroEllipticArc.h
SketchPlugin_MultiRotation.h
SketchPlugin_MultiTranslation.h
+ SketchPlugin_Offset.h
SketchPlugin_Plugin.h
SketchPlugin_Point.h
SketchPlugin_Projection.h
SketchPlugin_ConstraintRigid.cpp
SketchPlugin_ConstraintTangent.cpp
SketchPlugin_ConstraintVertical.cpp
+ SketchPlugin_CurveFitting.cpp
SketchPlugin_Ellipse.cpp
SketchPlugin_EllipticArc.cpp
SketchPlugin_ExternalValidator.cpp
SketchPlugin_MacroEllipticArc.cpp
SketchPlugin_MultiRotation.cpp
SketchPlugin_MultiTranslation.cpp
+ SketchPlugin_Offset.cpp
SketchPlugin_Plugin.cpp
SketchPlugin_Point.cpp
SketchPlugin_Projection.cpp
TestCreateEllipticArc.py
TestCreateEllipticArcByExternal.py
TestCreateMacroBSpline.py
+ TestCurveFitting1.py
+ TestCurveFitting2.py
+ TestCurveFitting3.py
+ TestCurveFitting4.py
TestDegeneratedGeometry.py
TestDistanceDump.py
TestDistanceSignedVsUnsigned01.py
TestMultiRotation05.py
TestMultiRotationWithParameter.py
TestMultiTranslation.py
+ TestOffset1.py
+ TestOffset2.py
TestPresentation.py
TestProjection.py
TestProjectionBSpline.py
TestProjectionEllipticArc.py
TestProjectionIntoResult.py
TestProjectionUpdate.py
+ TestProjectionWithoutReference.py
TestRectangle.py
TestRemainingDoF.py
TestRemoveBSpline.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 <SketchPlugin_CurveFitting.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_MacroBSpline.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <Events_InfoMessage.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAlgoAPI_CurveBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_BSpline.h>
+
+static void convertTo3D(SketchPlugin_Sketch* theSketch,
+ const AttributeRefAttrListPtr& theAttribute,
+ bool theClosedButNotPeriodic,
+ std::list<GeomPointPtr>& thePoints);
+
+static GeomEdgePtr buildInterpolationCurve(SketchPlugin_Sketch* theSketch,
+ AttributeRefAttrListPtr thePoints,
+ bool thePeriodic,
+ bool theClosed);
+static GeomEdgePtr buildApproximationCurve(SketchPlugin_Sketch* theSketch,
+ AttributeRefAttrListPtr thePoints,
+ double thePrecision,
+ bool thePeriodic,
+ bool theClosed);
+
+
+SketchPlugin_CurveFitting::SketchPlugin_CurveFitting()
+ : SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_CurveFitting::initDerivedClassAttributes()
+{
+ data()->addAttribute(POINTS_ID(), ModelAPI_AttributeRefAttrList::typeId());
+
+ data()->addAttribute(TYPE_ID(), ModelAPI_AttributeString::typeId());
+
+ data()->addAttribute(PRECISION_ID(), ModelAPI_AttributeDouble::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PRECISION_ID());
+
+ data()->addAttribute(NEED_CONTROL_POLYGON_ID(), ModelAPI_AttributeBoolean::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(),
+ NEED_CONTROL_POLYGON_ID());
+
+ data()->addAttribute(PERIODIC_ID(), ModelAPI_AttributeBoolean::typeId());
+ data()->addAttribute(CLOSED_ID(), ModelAPI_AttributeBoolean::typeId());
+}
+
+void SketchPlugin_CurveFitting::execute()
+{
+ FeaturePtr aBSpline = createBSplineFeature();
+ // create control polygon
+ AttributeBooleanPtr aNeedControlPoly = boolean(NEED_CONTROL_POLYGON_ID());
+ if (aNeedControlPoly && aNeedControlPoly->isInitialized() && aNeedControlPoly->value()) {
+ bool isPeriodic = boolean(PERIODIC_ID())->value();
+ std::list<FeaturePtr> aControlPoles;
+ SketchPlugin_MacroBSpline::createControlPolygon(aBSpline, isPeriodic, aControlPoles);
+ }
+ // constraints for the selected points
+ createConstraints(aBSpline);
+}
+
+FeaturePtr SketchPlugin_CurveFitting::createBSplineFeature()
+{
+ // create transient curve if not created yet
+ if (!myTransientResult) {
+ getAISObject(AISObjectPtr());
+ if (!myTransientResult)
+ return FeaturePtr();
+ }
+
+ SketchPlugin_Sketch* aSketch = sketch();
+ if (!aSketch)
+ return FeaturePtr();
+
+ bool isPeriodic = boolean(PERIODIC_ID())->value();
+
+ FeaturePtr aBSplineFeature = aSketch->addFeature(
+ isPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ // Convert transient edge to B-spline curve.
+ GeomCurvePtr aCurve = std::make_shared<GeomAPI_Curve>(myTransientResult);
+ std::shared_ptr<GeomAPI_BSpline> aBSpline = std::make_shared<GeomAPI_BSpline>(aCurve);
+
+ // Fill attributes of B-spline feature:
+ bool aWasBlocked = aBSplineFeature->data()->blockSendAttributeUpdated(true, false);
+ // 1. Degree
+ aBSplineFeature->integer(SketchPlugin_BSplineBase::DEGREE_ID())->setValue(aBSpline->degree());
+ // 2. Poles
+ std::list<GeomPointPtr> aPoles = aBSpline->poles();
+ AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aBSplineFeature->attribute(SketchPlugin_BSplineBase::POLES_ID()));
+ aPolesAttr->setSize((int)aPoles.size());
+ int anIndex = 0;
+ for (auto it = aPoles.begin(); it != aPoles.end(); ++it, ++anIndex)
+ aPolesAttr->setPnt(anIndex, aSketch->to2D(*it));
+ // 3. Weights
+ std::list<double> aWeights = aBSpline->weights();
+ AttributeDoubleArrayPtr aWeightsAttr =
+ aBSplineFeature->data()->realArray(SketchPlugin_BSplineBase::WEIGHTS_ID());
+ if (aWeights.empty()) {
+ aWeightsAttr->setSize((int)aPoles.size());
+ for (anIndex = 0; anIndex < (int)aPoles.size(); ++anIndex)
+ aWeightsAttr->setValue(anIndex, 1.0);
+ }
+ else {
+ aWeightsAttr->setSize((int)aWeights.size());
+ anIndex = 0;
+ for (auto it = aWeights.begin(); it != aWeights.end(); ++it, ++anIndex)
+ aWeightsAttr->setValue(anIndex, *it);
+ }
+ // 4. Knots (normalized from 0 to 1)
+ std::list<double> aKnots = aBSpline->knots();
+ AttributeDoubleArrayPtr aKnotsAttr =
+ aBSplineFeature->data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ aKnotsAttr->setSize((int)aKnots.size());
+ double aFirstKnot = aKnots.front();
+ double aLastKnot = aKnots.back();
+ anIndex = 0;
+ for (auto it = aKnots.begin(); it != aKnots.end(); ++it, ++anIndex)
+ aKnotsAttr->setValue(anIndex, (*it - aFirstKnot) / (aLastKnot - aFirstKnot));
+ // 5. Multiplicities
+ std::list<int> aMults = aBSpline->mults();
+ AttributeIntArrayPtr aMultsAttr =
+ aBSplineFeature->data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ aMultsAttr->setSize((int)aMults.size());
+ anIndex = 0;
+ for (auto it = aMults.begin(); it != aMults.end(); ++it, ++anIndex)
+ aMultsAttr->setValue(anIndex, *it);
+
+ if (!isPeriodic) {
+ AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSplineFeature->attribute(SketchPlugin_BSpline::START_ID()));
+ aStartPoint->setValue(aPolesAttr->pnt(0));
+
+ AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSplineFeature->attribute(SketchPlugin_BSpline::END_ID()));
+ aEndPoint->setValue(aPolesAttr->pnt(aPolesAttr->size() - 1));
+ }
+
+ aBSplineFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+ boolean(AUXILIARY_ID())->value());
+
+ aBSplineFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+
+ aBSplineFeature->execute();
+
+ return aBSplineFeature;
+}
+
+void SketchPlugin_CurveFitting::createConstraints(FeaturePtr theProducedFeature)
+{
+ if (!theProducedFeature)
+ return;
+
+ SketchPlugin_Sketch* aSketch = sketch();
+ ResultPtr aResult = theProducedFeature->lastResult();
+ bool isPeriodic = boolean(PERIODIC_ID())->value();
+ bool isClosed = boolean(CLOSED_ID())->value();
+ bool isApproximation = string(TYPE_ID())->value() == TYPE_APPROXIMATION_ID();
+
+ AttributeRefAttrListPtr aPointsAttr = refattrlist(POINTS_ID());
+ std::list<std::pair<ObjectPtr, AttributePtr> > aPointsList = aPointsAttr->list();
+ std::list<std::pair<ObjectPtr, AttributePtr> >::iterator aLastIt = --aPointsList.end();
+ for (auto it = aPointsList.begin(); it != aPointsList.end(); ++it) {
+ AttributePtr anAttr = it->second;
+ if (!anAttr) {
+ // maybe the SketchPoint is selected
+ FeaturePtr aFeature = ModelAPI_Feature::feature(it->first);
+ if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
+ anAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
+ else
+ continue;
+ }
+
+ if (!isPeriodic && it == aPointsList.begin()) {
+ SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ anAttr, theProducedFeature->attribute(SketchPlugin_BSpline::START_ID()));
+ if (isClosed) {
+ // end of B-spline curve should be coincident with the first selected point
+ SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ anAttr, theProducedFeature->attribute(SketchPlugin_BSpline::END_ID()));
+ }
+ }
+ else if (!isPeriodic && !isClosed && it == aLastIt) {
+ SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ anAttr, theProducedFeature->attribute(SketchPlugin_BSpline::END_ID()));
+ }
+ else if (!isApproximation) {
+ SketchPlugin_Tools::createConstraintAttrObject(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ anAttr, aResult);
+ }
+ }
+}
+
+bool SketchPlugin_CurveFitting::customAction(const std::string& theActionId)
+{
+ bool isOk = true;
+ if (theActionId == REORDER_POINTS_ACTION_ID()) {
+ reorderPoints();
+ } else {
+ static const std::string MESSAGE("Error: Feature \"%1\" does not support action \"%2\".");
+ Events_InfoMessage("SketchPlugin_CurveFitting", MESSAGE)
+ .arg(getKind()).arg(theActionId).send();
+ isOk = false;
+ }
+ return isOk;
+}
+
+
+void SketchPlugin_CurveFitting::reorderPoints()
+{
+ AttributeRefAttrListPtr aPointsAttr = refattrlist(POINTS_ID());
+ bool isPeriodic = boolean(PERIODIC_ID())->value();
+ bool isClosed = boolean(CLOSED_ID())->value();
+
+ std::list<GeomPointPtr> aCoordinates;
+ convertTo3D(sketch(), aPointsAttr, !isPeriodic && isClosed, aCoordinates);
+
+ // to keep mapping between points and attributes
+ std::map<GeomPointPtr, std::pair<ObjectPtr, AttributePtr> > aMap;
+ std::list<std::pair<ObjectPtr, AttributePtr> > aPointsList = aPointsAttr->list();
+ bool isPointAdded = aCoordinates.size() != aPointsList.size();
+ std::list<GeomPointPtr>::iterator aCoordIt = aCoordinates.begin();
+ std::list<std::pair<ObjectPtr, AttributePtr> >::iterator anAttrIt = aPointsList.begin();
+ for (; aCoordIt != aCoordinates.end() && anAttrIt != aPointsList.end(); ++aCoordIt, ++anAttrIt)
+ aMap[*aCoordIt] = *anAttrIt;
+
+ // reorder points
+ GeomAlgoAPI_CurveBuilder::reorderPoints(aCoordinates);
+
+ // re-compose the attribute
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+ aPointsAttr->clear();
+ for (aCoordIt = aCoordinates.begin(); aCoordIt != aCoordinates.end(); ++aCoordIt) {
+ const std::pair<ObjectPtr, AttributePtr>& aValue = aMap.at(*aCoordIt);
+ if (aValue.second)
+ aPointsAttr->append(aValue.second);
+ else
+ aPointsAttr->append(aValue.first);
+ }
+ data()->blockSendAttributeUpdated(aWasBlocked);
+}
+
+AISObjectPtr SketchPlugin_CurveFitting::getAISObject(AISObjectPtr thePrevious)
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if (!aSketch)
+ return AISObjectPtr();
+
+ std::string aType = string(TYPE_ID())->value();
+ if (aType == TYPE_INTERPOLATION_ID()) {
+ myTransientResult = buildInterpolationCurve(aSketch,
+ refattrlist(POINTS_ID()),
+ boolean(PERIODIC_ID())->value(),
+ boolean(CLOSED_ID())->value());
+ }
+ else if (aType == TYPE_APPROXIMATION_ID()) {
+ myTransientResult = buildApproximationCurve(aSketch,
+ refattrlist(POINTS_ID()),
+ real(PRECISION_ID())->value(),
+ boolean(PERIODIC_ID())->value(),
+ boolean(CLOSED_ID())->value());
+ }
+ if (!myTransientResult)
+ return AISObjectPtr();
+
+ AISObjectPtr anAIS = thePrevious;
+ if (!anAIS)
+ anAIS.reset(new GeomAPI_AISObject());
+ anAIS->createShape(myTransientResult);
+
+ // Modify attributes
+ SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
+ return anAIS;
+}
+
+
+// =============================== Auxiliary functions ====================================
+
+void convertTo3D(SketchPlugin_Sketch* theSketch,
+ const AttributeRefAttrListPtr& theAttribute,
+ bool theClosedButNotPeriodic,
+ std::list<GeomPointPtr>& thePoints)
+{
+ std::list<std::pair<ObjectPtr, AttributePtr> > aPointsList = theAttribute->list();
+ for (auto it = aPointsList.begin(); it != aPointsList.end(); ++it) {
+ AttributePtr anAttr = it->second;
+ if (!anAttr) {
+ // maybe the SketchPoint is selected
+ FeaturePtr aFeature = ModelAPI_Feature::feature(it->first);
+ if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
+ anAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
+ else {
+ thePoints.clear();
+ break;
+ }
+ }
+
+ AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+ if (aPoint) {
+ GeomPointPtr aPnt3D = theSketch->to3D(aPoint->x(), aPoint->y());
+ thePoints.push_back(aPnt3D);
+ }
+ }
+
+ if (theClosedButNotPeriodic && !thePoints.empty() &&
+ thePoints.front()->distance(thePoints.back()) > 1.e-7)
+ thePoints.push_back(thePoints.front()); // close the curve
+}
+
+GeomEdgePtr buildInterpolationCurve(SketchPlugin_Sketch* theSketch,
+ AttributeRefAttrListPtr thePoints,
+ bool thePeriodic,
+ bool theClosed)
+{
+ std::list<GeomPointPtr> aCoordinates;
+ convertTo3D(theSketch, thePoints, !thePeriodic && theClosed, aCoordinates);
+
+ GeomEdgePtr aResult;
+ if (aCoordinates.size() > 1) {
+ static const bool isReorder = false;
+ static GeomDirPtr aStartEndDir;
+ aResult = GeomAlgoAPI_CurveBuilder::edge(aCoordinates, thePeriodic,
+ isReorder, aStartEndDir, aStartEndDir);
+ }
+ return aResult;
+}
+
+GeomEdgePtr buildApproximationCurve(SketchPlugin_Sketch* theSketch,
+ AttributeRefAttrListPtr thePoints,
+ double thePrecision,
+ bool thePeriodic,
+ bool theClosed)
+{
+ std::list<GeomPointPtr> aCoordinates;
+ convertTo3D(theSketch, thePoints, !thePeriodic && theClosed, aCoordinates);
+
+ GeomEdgePtr aResult;
+ if (aCoordinates.size() > 1)
+ aResult = GeomAlgoAPI_CurveBuilder::approximate(aCoordinates, thePeriodic, thePrecision);
+ return aResult;
+}
--- /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 SketchPlugin_CurveFitting_H_
+#define SketchPlugin_CurveFitting_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Edge;
+
+/**\class SketchPlugin_CurveFitting
+ * \ingroup Plugins
+ * \brief Feature for creation of the new B-spline curve in sketch
+ * as an interpolation or an approximation of a list of points.
+ */
+class SketchPlugin_CurveFitting : public SketchPlugin_SketchEntity,
+ public GeomAPI_IPresentable
+{
+public:
+ /// Interpolation macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchCurveFitting");
+ return ID;
+ }
+
+ /// list of selected points
+ inline static const std::string& POINTS_ID()
+ {
+ static const std::string ID("points");
+ return ID;
+ }
+
+ /// attribute for the periodic flag
+ inline static const std::string& PERIODIC_ID()
+ {
+ static const std::string ID("periodic");
+ return ID;
+ }
+
+ /// attribute for the closed flag
+ inline static const std::string& CLOSED_ID()
+ {
+ static const std::string ID("closed");
+ return ID;
+ }
+
+ /// attribute for the flag of creation a control polygon
+ inline static const std::string& NEED_CONTROL_POLYGON_ID()
+ {
+ static const std::string ID("need_control_poly");
+ return ID;
+ }
+
+ /// attribute for the type of the operation
+ inline static const std::string& TYPE_ID()
+ {
+ static const std::string ID("type");
+ return ID;
+ }
+
+ /// value for the type of operation
+ inline static const std::string& TYPE_INTERPOLATION_ID()
+ {
+ static const std::string ID("interpolation_type");
+ return ID;
+ }
+
+ /// value for the type of operation
+ inline static const std::string& TYPE_APPROXIMATION_ID()
+ {
+ static const std::string ID("approximation_type");
+ return ID;
+ }
+
+ /// attribute for the precision of the approximation
+ inline static const std::string& PRECISION_ID()
+ {
+ static const std::string ID("precision");
+ return ID;
+ }
+
+ /// attribute for the closed flag
+ inline static const std::string& REORDER_POINTS_ACTION_ID()
+ {
+ static const std::string ID("reorder_points");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_CurveFitting::ID();
+ return MY_KIND;
+ }
+
+ /// Returns the AIS preview
+ virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+ /// Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ /// Reimplemented from ModelAPI_Feature::isMacro().
+ /// \returns true
+ SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+
+ SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+
+ /// Performs some functionality by action id.
+ /// \param[in] theAttributeId action key id.
+ /// \return false in case if action not performed.
+ SKETCHPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId);
+
+ /// Use plugin manager for features creation
+ SketchPlugin_CurveFitting();
+
+protected:
+ /// \brief Initializes attributes of derived class.
+ virtual void initDerivedClassAttributes();
+
+private:
+ /// \brief Create a feature, which passes through the selected points
+ FeaturePtr createBSplineFeature();
+
+ /// \brief Create coincidence constraints between selected points and the produced curve.
+ void createConstraints(FeaturePtr theProducedFeature);
+
+ /// \brief Reorder point to compose the polyline of the minimal length
+ void reorderPoints();
+
+private:
+ std::shared_ptr<GeomAPI_Edge> myTransientResult; ///< Interpolation curve
+};
+
+#endif
return false;
}
- data()->blockSendAttributeUpdated(true);
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(),
AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
double aFocalDist = aCenter2d->distance(aFocus2d);
double aMajorRadius = sqrt(aFocalDist * aFocalDist + aMinorRadius * aMinorRadius);
- aMajorRadiusAttr->setValue(aMajorRadius);
+ if (!aMajorRadiusAttr->isInitialized() ||
+ fabs(aMajorRadiusAttr->value() - aMajorRadius) > tolerance)
+ aMajorRadiusAttr->setValue(aMajorRadius);
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_FOCUS_ID()))
->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
- data()->blockSendAttributeUpdated(false);
+ data()->blockSendAttributeUpdated(aWasBlocked);
return true;
}
if (boolean(CONTROL_POLYGON_ID())->value()) {
std::list<FeaturePtr> aControlPoles;
- createControlPolygon(aBSpline, aControlPoles);
+ createControlPolygon(aBSpline, myIsPeriodic, aControlPoles);
constraintsForPoles(aControlPoles);
}
}
}
void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
+ bool thePeriodic,
std::list<FeaturePtr>& thePoles)
{
AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
// segments
for (int index = 1; index < aSize; ++index)
createAuxiliarySegment(aPoles, index - 1, index);
- if (myIsPeriodic) {
+ if (thePeriodic) {
// additional segment to close the control polygon
createAuxiliarySegment(aPoles, aSize - 1, 0);
}
private:
FeaturePtr createBSplineFeature();
- void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
+ /// Create control polygon for the B-spline and returns the list of its poles
+ static void createControlPolygon(FeaturePtr theBSpline,
+ bool thePeriodic,
+ std::list<FeaturePtr>& thePoles);
+
+ /// Create additional coincidences if other features were selected while creating the B-spline
void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
/// Create Point feature coincident with the B-spline pole
const int thePoleIndex1,
const int thePoleIndex2 = -1);
friend class SketchPlugin_BSplineBase;
+ friend class SketchPlugin_CurveFitting;
private:
std::list<double> myKnots;
};
-/**\class SketchPlugin_MacroBSpline
+/**\class SketchPlugin_MacroBSplinePeriodic
* \ingroup Plugins
-* \brief Feature for creation of the new B-spline in Sketch.
+* \brief Feature for creation of the new periodic B-spline in Sketch.
*/
class SketchPlugin_MacroBSplinePeriodic : public SketchPlugin_MacroBSpline
{
--- /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 <SketchPlugin_Offset.h>
+
+#include <SketchPlugin_Sketch.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+#include <SketchPlugin_Tools.h>
+
+#include <SketcherPrs_Factory.h>
+
+#include <Events_InfoMessage.h>
+
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_Offset.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAlgoAPI_WireBuilder.h>
+
+#include <GeomAPI_BSpline.h>
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_Wire.h>
+#include <GeomAPI_WireExplorer.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+static const double tolerance = 1.e-7;
+
+SketchPlugin_Offset::SketchPlugin_Offset()
+{
+}
+
+void SketchPlugin_Offset::initAttributes()
+{
+ data()->addAttribute(EDGES_ID(), ModelAPI_AttributeRefList::typeId());
+ data()->addAttribute(VALUE_ID(), ModelAPI_AttributeDouble::typeId());
+ data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+
+ // store original entities
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
+ // store offset entities
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
+ // store mapping between original entity and index of the corresponding offset entity
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeIntArray::typeId());
+
+ ModelAPI_Session::get()->validators()->
+ registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_A());
+ ModelAPI_Session::get()->validators()->
+ registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B());
+ ModelAPI_Session::get()->validators()->
+ registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C());
+}
+
+void SketchPlugin_Offset::execute()
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if (!aSketch) return;
+
+ // 1. Sketch plane
+ std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
+
+ // 2. Offset value
+ AttributeDoublePtr aValueAttr = real(VALUE_ID());
+ if (!aValueAttr->isInitialized()) return;
+ double aValue = aValueAttr->value();
+ if (aValue < tolerance) return;
+
+ // 2.a. Reversed?
+ AttributeBooleanPtr aReversedAttr = boolean(REVERSED_ID());
+ if (!aReversedAttr->isInitialized()) return;
+ if (aReversedAttr->value()) aValue = -aValue; // reverse offset direction
+
+ // 3. List of all selected edges
+ AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID());
+ std::list<ObjectPtr> anEdgesList = aSelectedEdges->list();
+
+ // 4. Put all selected edges in a set to pass them into findWireOneWay() below
+ std::set<FeaturePtr> anEdgesSet;
+ std::list<ObjectPtr>::const_iterator anEdgesIt = anEdgesList.begin();
+ for (; anEdgesIt != anEdgesList.end(); anEdgesIt++) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
+ if (aFeature) {
+ anEdgesSet.insert(aFeature);
+ }
+ }
+
+ // Wait all objects being created, then send update events
+ static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+ if (isUpdateFlushed)
+ Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+
+ // 5. Gather wires and make offset for each wire
+ ListOfMakeShape anOffsetAlgos;
+ std::set<FeaturePtr> aProcessedEdgesSet;
+ for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
+ if (aFeature.get()) {
+ if (aProcessedEdgesSet.find(aFeature) != aProcessedEdgesSet.end())
+ continue;
+
+ // 5.a. End points (if any)
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, anEndPoint;
+ SketchPlugin_SegmentationTools::getFeaturePoints(aFeature, aStartPoint, anEndPoint);
+
+ // 5.b. Find a chain of edges
+ std::list<FeaturePtr> aChain;
+ aChain.push_back(aFeature);
+ bool isClosed = !(aStartPoint && anEndPoint); // not closed edge
+ if (!isClosed) {
+ isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet,
+ aProcessedEdgesSet, aChain, true);
+ if (!isClosed) {
+ isClosed = findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet,
+ aProcessedEdgesSet, aChain, false);
+ }
+ }
+ aProcessedEdgesSet.insert(aFeature);
+
+ // 5.c. Make wire
+ ListOfShape aTopoChain;
+ std::list<FeaturePtr>::iterator aChainIt = aChain.begin();
+ for (; aChainIt != aChain.end(); ++aChainIt) {
+ FeaturePtr aChainFeature = (*aChainIt);
+ GeomShapePtr aTopoEdge = aChainFeature->lastResult()->shape();
+ if (aTopoEdge->shapeType() == GeomAPI_Shape::EDGE) {
+ aTopoChain.push_back(aTopoEdge);
+ }
+ }
+ std::shared_ptr<GeomAlgoAPI_WireBuilder> aWireBuilder(
+ new GeomAlgoAPI_WireBuilder(aTopoChain, !isClosed));
+
+ GeomShapePtr aWireShape = aWireBuilder->shape();
+ GeomWirePtr aWire (new GeomAPI_Wire (aWireShape));
+
+ // Fix for a problem of offset side change with selection change.
+ // Wire direction is defined by the first selected edge of this wire.
+ double aSign = 1.;
+ if (!aWire->isClosed()) {
+ ListOfShape aModified;
+ // First selected edge of current chain
+ GeomShapePtr aFirstSel = aFeature->lastResult()->shape();
+ aWireBuilder->modified(aFirstSel, aModified);
+ GeomShapePtr aModFS = aModified.front();
+ if (aModFS->orientation() != aFirstSel->orientation())
+ aSign = -1.;
+ }
+
+ // 5.d. Make offset for the wire
+ std::shared_ptr<GeomAlgoAPI_Offset> anOffsetShape(
+ new GeomAlgoAPI_Offset(aPlane, aWireShape, aValue*aSign));
+
+ std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeList(new GeomAlgoAPI_MakeShapeList);
+ aMakeList->appendAlgo(aWireBuilder);
+ aMakeList->appendAlgo(anOffsetShape);
+ anOffsetAlgos.push_back(aMakeList);
+ }
+ }
+
+ // 6. Store offset results.
+ // Create sketch feature for each edge of anOffsetShape, and also store
+ // created features in CREATED_ID() to remove them on next execute()
+ addToSketch(anOffsetAlgos);
+
+ // send events to update the sub-features by the solver
+ if (isUpdateFlushed)
+ Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+}
+
+bool SketchPlugin_Offset::findWireOneWay (const FeaturePtr& theFirstEdge,
+ const FeaturePtr& theEdge,
+ const std::shared_ptr<GeomDataAPI_Point2D>& theEndPoint,
+ std::set<FeaturePtr>& theEdgesSet,
+ std::set<FeaturePtr>& theProcessedEdgesSet,
+ std::list<FeaturePtr>& theChain,
+ const bool isPrepend)
+{
+ // 1. Find a single edge, coincident to theEndPoint by one of its ends
+ if (!theEndPoint) return false;
+
+ FeaturePtr aNextEdgeFeature;
+ int nbFound = 0;
+
+ std::set<AttributePoint2DPtr> aCoincPoints =
+ SketchPlugin_Tools::findPointsCoincidentToPoint(theEndPoint);
+
+ std::set<AttributePoint2DPtr>::iterator aPointsIt = aCoincPoints.begin();
+ for (; aPointsIt != aCoincPoints.end(); aPointsIt++) {
+ AttributePoint2DPtr aP = (*aPointsIt);
+ FeaturePtr aCoincFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aP->owner());
+ bool isInSet = (theEdgesSet.find(aCoincFeature) != theEdgesSet.end());
+
+ // Condition 0: not auxiliary
+ if (!isInSet && aCoincFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value())
+ continue;
+
+ // Condition 1: not a point feature
+ if (aCoincFeature->getKind() != SketchPlugin_Point::ID()) {
+ // Condition 2: it is not the current edge
+ if (aCoincFeature != theEdge) {
+ // Condition 3: it is in the set of interest.
+ // Empty set means all sketch edges.
+ if (isInSet || theEdgesSet.empty()) {
+ // Condition 4: consider only features with two end points
+ std::shared_ptr<GeomDataAPI_Point2D> aP1, aP2;
+ SketchPlugin_SegmentationTools::getFeaturePoints(aCoincFeature, aP1, aP2);
+ if (aP1 && aP2) {
+ // Condition 5: consider only features, that have aP as one of they ends.
+ // For example, we do not need an arc, coincident to aP by its center.
+ if (theEndPoint->pnt()->isEqual(aP1->pnt()) ||
+ theEndPoint->pnt()->isEqual(aP2->pnt())) {
+ // Condition 6: only one edge can prolongate the chain. If several, we stop here.
+ nbFound++;
+ if (nbFound > 1)
+ return false;
+
+ // One found
+ aNextEdgeFeature = aCoincFeature;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Only one edge can prolongate the chain. If several or none, we stop here.
+ if (nbFound != 1)
+ return false;
+
+ // 2. So, we have the single edge, that prolongate the chain
+
+ // Condition 7: if we reached the very first edge of the chain
+ if (aNextEdgeFeature == theFirstEdge)
+ // Closed chain found
+ return true;
+
+ // 3. Add the found edge to the chain
+ if (isPrepend)
+ theChain.push_front(aNextEdgeFeature);
+ else
+ theChain.push_back(aNextEdgeFeature);
+ theProcessedEdgesSet.insert(aNextEdgeFeature);
+
+ // 4. Which end of aNextEdgeFeature we need to proceed
+ std::shared_ptr<GeomDataAPI_Point2D> aP1, aP2;
+ SketchPlugin_SegmentationTools::getFeaturePoints(aNextEdgeFeature, aP1, aP2);
+ if (aP2->pnt()->isEqual(theEndPoint->pnt())) {
+ // reversed
+ aP2 = aP1;
+ }
+
+ // 5. Continue gathering the chain (recursive)
+ return findWireOneWay (theFirstEdge, aNextEdgeFeature, aP2, theEdgesSet,
+ theProcessedEdgesSet, theChain, isPrepend);
+}
+
+static void setRefListValue(AttributeRefListPtr theList, int theListSize,
+ ObjectPtr theValue, int theIndex)
+{
+ if (theIndex < theListSize) {
+ ObjectPtr aCur = theList->object(theIndex);
+ if (aCur != theValue)
+ theList->substitute(aCur, theValue);
+ }
+ else
+ theList->append(theValue);
+}
+
+// Reorder shapes according to the wire's order
+static void reorderShapes(ListOfShape& theShapes, GeomShapePtr theWire)
+{
+ std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aShapes;
+ aShapes.insert(theShapes.begin(), theShapes.end());
+ theShapes.clear();
+
+ GeomWirePtr aWire(new GeomAPI_Wire(theWire));
+ GeomAPI_WireExplorer anExp(aWire);
+ for (; anExp.more(); anExp.next()) {
+ GeomShapePtr aCurEdge = anExp.current();
+ auto aFound = aShapes.find(aCurEdge);
+ if (aFound != aShapes.end()) {
+ theShapes.push_back(aCurEdge);
+ aShapes.erase(aFound);
+ }
+ }
+}
+
+static void removeLastFromIndex(AttributeRefListPtr theList, int theListSize, int& theLastIndex)
+{
+ if (theLastIndex < theListSize) {
+ std::set<int> anIndicesToRemove;
+ for (; theLastIndex < theListSize; ++theLastIndex)
+ anIndicesToRemove.insert(theLastIndex);
+ theList->remove(anIndicesToRemove);
+ }
+}
+
+void SketchPlugin_Offset::addToSketch(const ListOfMakeShape& theOffsetAlgos)
+{
+ AttributeRefListPtr aSelectedRefList = reflist(EDGES_ID());
+ AttributeRefListPtr aBaseRefList = reflist(ENTITY_A());
+ AttributeRefListPtr anOffsetRefList = reflist(ENTITY_B());
+ AttributeIntArrayPtr anOffsetToBaseMap = intArray(ENTITY_C());
+
+ // compare the list of selected edges and the previously stored,
+ // and store maping between them
+ std::map<ObjectPtr, std::list<ObjectPtr> > aMapExistent;
+ std::list<ObjectPtr> anObjectsToRemove;
+ std::list<ObjectPtr> aSelectedList = aSelectedRefList->list();
+ for (std::list<ObjectPtr>::iterator aSIt = aSelectedList.begin();
+ aSIt != aSelectedList.end(); ++aSIt) {
+ aMapExistent[*aSIt] = std::list<ObjectPtr>();
+ }
+ for (int anIndex = 0, aSize = anOffsetRefList->size(); anIndex < aSize; ++anIndex) {
+ ObjectPtr aCurrent = anOffsetRefList->object(anIndex);
+ int aBaseIndex = anOffsetToBaseMap->value(anIndex);
+ if (aBaseIndex >= 0) {
+ ObjectPtr aBaseObj = aBaseRefList->object(aBaseIndex);
+ std::map<ObjectPtr, std::list<ObjectPtr> >::iterator aFound = aMapExistent.find(aBaseObj);
+ if (aFound != aMapExistent.end())
+ aFound->second.push_back(aCurrent);
+ else
+ anObjectsToRemove.push_back(aCurrent);
+ }
+ else
+ anObjectsToRemove.push_back(aCurrent);
+ }
+
+ // update lists of base shapes and of offset shapes
+ int aBaseListSize = aBaseRefList->size();
+ int anOffsetListSize = anOffsetRefList->size();
+ int aBaseListIndex = 0, anOffsetListIndex = 0;
+ std::list<int> anOffsetBaseBackRefs;
+ std::set<GeomShapePtr, GeomAPI_Shape::ComparatorWithOri> aProcessedOffsets;
+ for (std::list<ObjectPtr>::iterator aSIt = aSelectedList.begin();
+ aSIt != aSelectedList.end(); ++aSIt) {
+ // find an offseted edge
+ FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*aSIt);
+ GeomShapePtr aBaseShape = aBaseFeature->lastResult()->shape();
+ ListOfShape aNewShapes;
+ for (ListOfMakeShape::const_iterator anAlgoIt = theOffsetAlgos.begin();
+ anAlgoIt != theOffsetAlgos.end(); ++anAlgoIt) {
+ (*anAlgoIt)->generated(aBaseShape, aNewShapes);
+ if (!aNewShapes.empty()) {
+ reorderShapes(aNewShapes, (*anAlgoIt)->shape());
+ break;
+ }
+ }
+
+ // store base feature
+ setRefListValue(aBaseRefList, aBaseListSize, *aSIt, aBaseListIndex);
+
+ // create or update an offseted feature
+ const std::list<ObjectPtr>& anImages = aMapExistent[*aSIt];
+ std::list<ObjectPtr>::const_iterator anImgIt = anImages.begin();
+ for (ListOfShape::iterator aNewIt = aNewShapes.begin(); aNewIt != aNewShapes.end(); ++aNewIt) {
+ FeaturePtr aNewFeature;
+ if (anImgIt != anImages.end())
+ aNewFeature = ModelAPI_Feature::feature(*anImgIt++);
+ updateExistentOrCreateNew(*aNewIt, aNewFeature, anObjectsToRemove);
+ aProcessedOffsets.insert(*aNewIt);
+
+ // store an offseted feature
+ setRefListValue(anOffsetRefList, anOffsetListSize, aNewFeature, anOffsetListIndex);
+
+ anOffsetBaseBackRefs.push_back(aBaseListIndex);
+ ++anOffsetListIndex;
+ }
+ ++aBaseListIndex;
+ anObjectsToRemove.insert(anObjectsToRemove.end(), anImgIt, anImages.end());
+ }
+ // create arcs generated from vertices
+ for (ListOfMakeShape::const_iterator anAlgoIt = theOffsetAlgos.begin();
+ anAlgoIt != theOffsetAlgos.end(); ++anAlgoIt) {
+ GeomShapePtr aCurWire = (*anAlgoIt)->shape();
+ GeomAPI_ShapeExplorer anExp(aCurWire, GeomAPI_Shape::EDGE);
+ for (; anExp.more(); anExp.next()) {
+ GeomShapePtr aCurEdge = anExp.current();
+ if (aProcessedOffsets.find(aCurEdge) == aProcessedOffsets.end()) {
+ FeaturePtr aNewFeature;
+ updateExistentOrCreateNew(aCurEdge, aNewFeature, anObjectsToRemove);
+ aProcessedOffsets.insert(aCurEdge);
+
+ // store an offseted feature
+ setRefListValue(anOffsetRefList, anOffsetListSize, aNewFeature, anOffsetListIndex);
+
+ anOffsetBaseBackRefs.push_back(-1);
+ ++anOffsetListIndex;
+ }
+ }
+ }
+
+ removeLastFromIndex(aBaseRefList, aBaseListSize, aBaseListIndex);
+ removeLastFromIndex(anOffsetRefList, anOffsetListSize, anOffsetListIndex);
+
+ anOffsetToBaseMap->setSize((int)anOffsetBaseBackRefs.size(), false);
+ int anIndex = 0;
+ for (std::list<int>::iterator anIt = anOffsetBaseBackRefs.begin();
+ anIt != anOffsetBaseBackRefs.end(); ++anIt) {
+ anOffsetToBaseMap->setValue(anIndex++, *anIt, false);
+ }
+
+ // remove unused objects
+ std::set<FeaturePtr> aSet;
+ for (std::list<ObjectPtr>::iterator anIt = anObjectsToRemove.begin();
+ anIt != anObjectsToRemove.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature)
+ aSet.insert(aFeature);
+ }
+ ModelAPI_Tools::removeFeaturesAndReferences(aSet);
+}
+
+static void findOrCreateFeatureByKind(SketchPlugin_Sketch* theSketch,
+ const std::string& theFeatureKind,
+ FeaturePtr& theFeature,
+ std::list<ObjectPtr>& thePoolOfFeatures)
+{
+ if (theFeature) {
+ // check the feature type is the same as required
+ if (theFeature->getKind() != theFeatureKind) {
+ // return feature to the pool and try to find the most appropriate
+ thePoolOfFeatures.push_back(theFeature);
+ theFeature = FeaturePtr();
+ }
+ }
+ if (!theFeature) {
+ // try to find appropriate feature in the pool
+ for (std::list<ObjectPtr>::iterator it = thePoolOfFeatures.begin();
+ it != thePoolOfFeatures.end(); ++it) {
+ FeaturePtr aCurFeature = ModelAPI_Feature::feature(*it);
+ if (aCurFeature->getKind() == theFeatureKind) {
+ theFeature = aCurFeature;
+ thePoolOfFeatures.erase(it);
+ break;
+ }
+ }
+ // feature not found, create new
+ if (!theFeature)
+ theFeature = theSketch->addFeature(theFeatureKind);
+ }
+}
+
+void SketchPlugin_Offset::updateExistentOrCreateNew(const GeomShapePtr& theShape,
+ FeaturePtr& theFeature,
+ std::list<ObjectPtr>& thePoolOfFeatures)
+{
+ if (theShape->shapeType() != GeomAPI_Shape::EDGE)
+ return;
+
+ std::shared_ptr<GeomAPI_Edge> aResEdge(new GeomAPI_Edge(theShape));
+
+ std::shared_ptr<GeomAPI_Pnt2d> aFP, aLP;
+ std::shared_ptr<GeomAPI_Pnt> aFP3d = aResEdge->firstPoint();
+ std::shared_ptr<GeomAPI_Pnt> aLP3d = aResEdge->lastPoint();
+ if (aFP3d && aLP3d) {
+ aFP = sketch()->to2D(aFP3d);
+ aLP = sketch()->to2D(aLP3d);
+ }
+
+ if (aResEdge->isLine()) {
+ findOrCreateFeatureByKind(sketch(), SketchPlugin_Line::ID(), theFeature, thePoolOfFeatures);
+
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Line::START_ID()))->setValue(aFP);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Line::END_ID()))->setValue(aLP);
+ }
+ else if (aResEdge->isArc()) {
+ std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
+ std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
+ std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
+
+ findOrCreateFeatureByKind(sketch(), SketchPlugin_Arc::ID(), theFeature, thePoolOfFeatures);
+
+ GeomDirPtr aCircNormal = aCircEdge->normal();
+ GeomDirPtr aSketchNormal = sketch()->coordinatePlane()->normal();
+ if (aSketchNormal->dot(aCircNormal) < -tolerance)
+ std::swap(aFP, aLP);
+
+ bool aWasBlocked = theFeature->data()->blockSendAttributeUpdated(true);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(aLP);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(aFP);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCP);
+ theFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+ }
+ else if (aResEdge->isCircle()) {
+ std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
+ std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
+ std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
+
+ findOrCreateFeatureByKind(sketch(), SketchPlugin_Circle::ID(), theFeature, thePoolOfFeatures);
+
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCP);
+ theFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircEdge->radius());
+ }
+ else if (aResEdge->isEllipse()) {
+ std::shared_ptr<GeomAPI_Ellipse> anEllipseEdge = aResEdge->ellipse();
+
+ GeomPointPtr aCP3d = anEllipseEdge->center();
+ GeomPnt2dPtr aCP = sketch()->to2D(aCP3d);
+
+ GeomPointPtr aFocus3d = anEllipseEdge->firstFocus();
+ GeomPnt2dPtr aFocus = sketch()->to2D(aFocus3d);
+
+ if (aFP3d && aLP3d) {
+ // Elliptic arc
+ findOrCreateFeatureByKind(sketch(), SketchPlugin_EllipticArc::ID(),
+ theFeature, thePoolOfFeatures);
+
+ bool aWasBlocked = theFeature->data()->blockSendAttributeUpdated(true);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()))->setValue(aCP);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()))->setValue(aFocus);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))->setValue(aFP);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))->setValue(aLP);
+ theFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+ }
+ else {
+ // Ellipse
+ findOrCreateFeatureByKind(sketch(), SketchPlugin_Ellipse::ID(),
+ theFeature, thePoolOfFeatures);
+
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()))->setValue(aCP);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+ (theFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()))->setValue(aFocus);
+ theFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(
+ anEllipseEdge->minorRadius());
+ }
+ }
+ else {
+ // convert to b-spline
+ mkBSpline(theFeature, aResEdge, thePoolOfFeatures);
+ }
+
+ if (theFeature.get()) {
+ theFeature->boolean(SketchPlugin_SketchEntity::COPY_ID())->setValue(true);
+ theFeature->execute();
+
+ static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ ModelAPI_EventCreator::get()->sendUpdated(theFeature, aRedisplayEvent);
+ const std::list<ResultPtr>& aResults = theFeature->results();
+ for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+ anIt != aResults.end(); ++anIt)
+ ModelAPI_EventCreator::get()->sendUpdated(*anIt, aRedisplayEvent);
+ }
+}
+
+void SketchPlugin_Offset::mkBSpline (FeaturePtr& theResult,
+ const GeomEdgePtr& theEdge,
+ std::list<ObjectPtr>& thePoolOfFeatures)
+{
+ GeomCurvePtr aCurve (new GeomAPI_Curve (theEdge));
+ // Forced conversion to b-spline, if aCurve is not b-spline
+ GeomBSplinePtr aBSpline = GeomAPI_BSpline::convertToBSpline(aCurve);
+
+ const std::string& aBSplineKind = aBSpline->isPeriodic() ? SketchPlugin_BSplinePeriodic::ID()
+ : SketchPlugin_BSpline::ID();
+ findOrCreateFeatureByKind(sketch(), aBSplineKind, theResult, thePoolOfFeatures);
+
+ theResult->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline->degree());
+
+ AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>
+ (theResult->attribute(SketchPlugin_BSpline::POLES_ID()));
+ std::list<GeomPointPtr> aPoles = aBSpline->poles();
+ aPolesAttr->setSize((int)aPoles.size());
+ std::list<GeomPointPtr>::iterator anIt = aPoles.begin();
+ for (int anIndex = 0; anIt != aPoles.end(); ++anIt, ++anIndex) {
+ GeomPnt2dPtr aPoleInSketch = sketch()->to2D(*anIt);
+ aPolesAttr->setPnt(anIndex, aPoleInSketch);
+ }
+
+ AttributeDoubleArrayPtr aWeightsAttr =
+ theResult->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+ std::list<double> aWeights = aBSpline->weights();
+ if (aWeights.empty()) { // rational B-spline
+ int aSize = (int)aPoles.size();
+ aWeightsAttr->setSize(aSize);
+ for (int anIndex = 0; anIndex < aSize; ++anIndex)
+ aWeightsAttr->setValue(anIndex, 1.0);
+ }
+ else { // non-rational B-spline
+ aWeightsAttr->setSize((int)aWeights.size());
+ std::list<double>::iterator anIt = aWeights.begin();
+ for (int anIndex = 0; anIt != aWeights.end(); ++anIt, ++anIndex)
+ aWeightsAttr->setValue(anIndex, *anIt);
+ }
+
+ AttributeDoubleArrayPtr aKnotsAttr =
+ theResult->data()->realArray(SketchPlugin_BSpline::KNOTS_ID());
+ std::list<double> aKnots = aBSpline->knots();
+ int aSize = (int)aKnots.size();
+ aKnotsAttr->setSize(aSize);
+ std::list<double>::iterator aKIt = aKnots.begin();
+ for (int index = 0; index < aSize; ++index, ++aKIt)
+ aKnotsAttr->setValue(index, *aKIt);
+
+ AttributeIntArrayPtr aMultsAttr =
+ theResult->data()->intArray(SketchPlugin_BSpline::MULTS_ID());
+ std::list<int> aMultiplicities = aBSpline->mults();
+ aSize = (int)aMultiplicities.size();
+ aMultsAttr->setSize(aSize);
+ std::list<int>::iterator aMIt = aMultiplicities.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMultsAttr->setValue(index, *aMIt);
+}
+
+void SketchPlugin_Offset::attributeChanged(const std::string& theID)
+{
+ if (theID == EDGES_ID()) {
+ AttributeRefListPtr aSelected = reflist(EDGES_ID());
+ if (aSelected->size() == 0) {
+ // Clear list of objects
+ AttributeRefListPtr anOffsetAttr = reflist(SketchPlugin_Constraint::ENTITY_B());
+ std::list<ObjectPtr> anOffsetList = anOffsetAttr->list();
+ std::set<FeaturePtr> aFeaturesToBeRemoved;
+ for (std::list<ObjectPtr>::iterator anIt = anOffsetList.begin();
+ anIt != anOffsetList.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature)
+ aFeaturesToBeRemoved.insert(aFeature);
+ }
+
+ reflist(SketchPlugin_Constraint::ENTITY_A())->clear();
+ anOffsetAttr->clear();
+ intArray(SketchPlugin_Constraint::ENTITY_C())->setSize(0);
+
+ ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
+ }
+ }
+}
+
+bool SketchPlugin_Offset::customAction(const std::string& theActionId)
+{
+ bool isOk = false;
+ if (theActionId == ADD_WIRE_ACTION_ID()) {
+ isOk = findWires();
+ }
+ else {
+ std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
+ Events_InfoMessage("SketchPlugin_Offset", aMsg).arg(getKind()).arg(theActionId).send();
+ }
+ return isOk;
+}
+
+bool SketchPlugin_Offset::findWires()
+{
+ AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID());
+ std::list<ObjectPtr> anEdgesList = aSelectedEdges->list();
+
+ // Empty set
+ std::set<FeaturePtr> anEdgesSet;
+
+ // Processed set
+ std::set<FeaturePtr> aProcessedEdgesSet;
+
+ // Put all selected edges in a set to avoid adding them in reflist(EDGES_ID())
+ std::set<FeaturePtr> aSelectedSet;
+ std::list<ObjectPtr>::const_iterator anEdgesIt = anEdgesList.begin();
+ for (; anEdgesIt != anEdgesList.end(); anEdgesIt++) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
+ if (aFeature) {
+ aSelectedSet.insert(aFeature);
+ }
+ }
+
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+
+ // Gather chains of edges
+ for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
+ if (aFeature.get()) {
+ if (aProcessedEdgesSet.find(aFeature) != aProcessedEdgesSet.end())
+ continue;
+ aProcessedEdgesSet.insert(aFeature);
+
+ // End points (if any)
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, anEndPoint;
+ SketchPlugin_SegmentationTools::getFeaturePoints(aFeature, aStartPoint, anEndPoint);
+
+ std::list<FeaturePtr> aChain;
+ aChain.push_back(aFeature);
+ bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet,
+ aProcessedEdgesSet, aChain, true);
+ if (!isClosed) {
+ findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet,
+ aProcessedEdgesSet, aChain, false);
+ }
+
+ std::list<FeaturePtr>::iterator aChainIt = aChain.begin();
+ for (; aChainIt != aChain.end(); ++aChainIt) {
+ FeaturePtr aChainFeature = (*aChainIt);
+ if (aSelectedSet.find(aChainFeature) == aSelectedSet.end()) {
+ aSelectedEdges->append(aChainFeature->lastResult());
+ }
+ }
+ }
+ }
+ // TODO: hilight selection in the viewer
+
+ data()->blockSendAttributeUpdated(aWasBlocked);
+ return true;
+}
+
+
+AISObjectPtr SketchPlugin_Offset::getAISObject(AISObjectPtr thePrevious)
+{
+ if (!sketch())
+ return thePrevious;
+
+ AISObjectPtr anAIS = SketcherPrs_Factory::offsetObject(this, sketch(),
+ thePrevious);
+ return anAIS;
+}
--- /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 SketchPlugin_Offset_H_
+#define SketchPlugin_Offset_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_ConstraintBase.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Edge.h>
+
+class GeomAlgoAPI_MakeShape;
+
+/**\class SketchPlugin_Offset
+ * \ingroup Plugins
+ * \brief Builds offset curves in the sketch.
+ */
+class SketchPlugin_Offset : public SketchPlugin_ConstraintBase
+{
+public:
+ /// Offset macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchOffset");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_Offset::ID();
+ return MY_KIND;
+ }
+
+ /// list of offset edges
+ inline static const std::string& EDGES_ID()
+ {
+ static const std::string ID("segments");
+ return ID;
+ }
+
+ /// attribute to store the offset value
+ inline static const std::string& VALUE_ID()
+ {
+ static const std::string ID("offset_value");
+ return ID;
+ }
+
+ /// attribute to store the reversed offset direction
+ inline static const std::string& REVERSED_ID()
+ {
+ static const std::string ID("reversed");
+ return ID;
+ }
+
+ /// name for add wire action
+ inline static const std::string& ADD_WIRE_ACTION_ID()
+ {
+ static const std::string ID("add_wire");
+ return ID;
+ }
+
+ /// Called on change of any argument-attribute of this object
+ SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return true; }
+
+ /// Find edges connected by coincident boundary constraint and composing a wire with
+ /// the already selected segments. It means that not more than 2 edges can be connected
+ /// with the coincident point.
+ /// \param[in] theActionId action key id (in following form: Action#Index)
+ /// \return \c false in case the action not performed.
+ SKETCHPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId);
+
+ /// Returns the AIS preview
+ SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+ /// Use plugin manager for features creation.
+ SketchPlugin_Offset();
+
+protected:
+ /// \brief Initializes attributes of derived class.
+ virtual void initAttributes();
+
+private:
+ /// Find all wires connected with the selected edges
+ bool findWires();
+
+ /// Create sketch feature for each edge of the offset result,
+ /// and store it in ENTITY_B(). Original edges are copied to ENTITY_A() to update
+ /// correctly if original selection is modified.
+ void addToSketch (const std::list< std::shared_ptr<GeomAlgoAPI_MakeShape> >& theOffsetAlgos);
+
+ /// Create BSpline or BSplinePeriodic sketch feature from theEdge
+ void mkBSpline (FeaturePtr& theResult, const GeomEdgePtr& theEdge,
+ std::list<ObjectPtr>& thePoolOfFeatures);
+
+ /// Update existent feature by the parameters of the given edge or create a new feature.
+ /// \param[in] theShape a shape to be converted to sketch feature
+ /// \param[in,out] theFeature sketch feature to be updated or created from scratch
+ /// \param[in,out] thePoolOfFeatures list of features to be removed (may be used as a new feature)
+ void updateExistentOrCreateNew (const GeomShapePtr& theShape, FeaturePtr& theFeature,
+ std::list<ObjectPtr>& thePoolOfFeatures);
+
+ /// Find edges that prolongate theEdgeFeature (in a chain) at theEndPoint
+ /// Recursive method.
+ /// \param[in] theFirstEdge Start edge of wire searching
+ /// \param[in] theEdge Current edge
+ /// \param[in] theEndPoint Point of the Current edge, not belonging to a previous edge
+ /// \param[in/out] theEdgesSet All edges to find among. If empty, all sketch edges assumed.
+ /// \param[in/out] theProcessedEdgesSet Already processed (put in chains) edges.
+ /// \param[in/out] theChain Resulting edges
+ /// \param[in] isPrepend if true, push new found edges to theChain front, else to the back
+ /// \return \c true if the chain is closed
+ bool findWireOneWay (const FeaturePtr& theFirstEdge,
+ const FeaturePtr& theEdge,
+ const std::shared_ptr<GeomDataAPI_Point2D>& theEndPoint,
+ std::set<FeaturePtr>& theEdgesSet,
+ std::set<FeaturePtr>& theProcessedEdgesSet,
+ std::list<FeaturePtr>& theChain,
+ const bool isPrepend = false);
+};
+
+#endif
#include <SketchPlugin_MacroCircle.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
+#include <SketchPlugin_Offset.h>
#include <SketchPlugin_Trim.h>
#include <SketchPlugin_Split.h>
#include <SketchPlugin_Validators.h>
#include <SketchPlugin_MacroEllipticArc.h>
#include <SketchPlugin_SketchDrawer.h>
#include <SketchPlugin_SketchCopy.h>
+#include <SketchPlugin_CurveFitting.h>
#include <SketcherPrs_Tools.h>
new SketchPlugin_MultiRotationAngleValidator);
aFactory->registerValidator("SketchPlugin_BSplineValidator",
new SketchPlugin_BSplineValidator);
+ aFactory->registerValidator("SketchPlugin_CurveFittingValidator",
+ new SketchPlugin_CurveFittingValidator);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new SketchPlugin_EllipticArc);
} else if (theFeatureID == SketchPlugin_MacroEllipticArc::ID()) {
return FeaturePtr(new SketchPlugin_MacroEllipticArc);
+ } else if (theFeatureID == SketchPlugin_CurveFitting::ID()) {
+ return FeaturePtr(new SketchPlugin_CurveFitting);
} else if (theFeatureID == SketchPlugin_SketchDrawer::ID()) {
return FeaturePtr(new SketchPlugin_SketchDrawer);
} else if (theFeatureID == SketchPlugin_SketchCopy::ID()) {
return FeaturePtr(new SketchPlugin_SketchCopy);
+ } else if (theFeatureID == SketchPlugin_Offset::ID()) {
+ return FeaturePtr(new SketchPlugin_Offset);
}
// feature of such kind is not found
return FeaturePtr();
aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_ConstraintDistanceHorizontal::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_CurveFitting::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_Offset::ID(), aHasSketchPlane);
// SketchRectangle is a python feature, so its ID is passed just as a string
aMsg->setState("SketchRectangle", aHasSketchPlane);
}
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeString.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
#include <cmath>
static const double tolerance = 1.e-7;
+static const std::string THE_KEEP_REF("true");
+
+static bool isKeepReference(AttributeStringPtr theAttr)
+{
+ return !theAttr || !theAttr->isInitialized() || theAttr->value() == THE_KEEP_REF;
+}
SketchPlugin_Projection::SketchPlugin_Projection()
{
data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PROJECTED_FEATURE_ID());
data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
}
+void SketchPlugin_Projection::initDerivedClassAttributes2()
+{
+ AttributePtr aKeepRefAttr =
+ data()->addAttribute(KEEP_REFERENCE_ID(), ModelAPI_AttributeString::typeId());
+ if (!aKeepRefAttr->isInitialized()) {
+ std::dynamic_pointer_cast<ModelAPI_AttributeString>(aKeepRefAttr)->setValue(THE_KEEP_REF);
+ }
+
+ data()->addAttribute(MAKE_FIXED(), ModelAPI_AttributeBoolean::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAKE_FIXED());
+
+ data()->addAttribute(FIXED_CONSTRAINT_ID(), ModelAPI_AttributeReference::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIXED_CONSTRAINT_ID());
+ data()->attribute(FIXED_CONSTRAINT_ID())->setIsArgument(false);
+}
+
void SketchPlugin_Projection::execute()
{
AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
return;
FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
- if (!lastResult().get()) {
+ if (isKeepReference(string(KEEP_REFERENCE_ID())) && !lastResult().get()) {
bool hasProjResult = aProjection->lastResult().get() != NULL;
ResultConstructionPtr aConstr = document()->createConstruction(data());
if (hasProjResult)
computeProjection(EXTERNAL_FEATURE_ID());
}
+bool SketchPlugin_Projection::isMacro() const
+{
+ if (!data() || !data()->isValid())
+ return false;
+
+ AttributeStringPtr aKeepRefAttr =
+ const_cast<SketchPlugin_Projection*>(this)->string(KEEP_REFERENCE_ID());
+ return !isKeepReference(aKeepRefAttr);
+}
+
void SketchPlugin_Projection::attributeChanged(const std::string& theID)
{
if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
if (!isProjected)
return; // projection is not computed, stop processing
- aProjection->boolean(COPY_ID())->setValue(true);
+ bool keepBackRef = isKeepReference(string(KEEP_REFERENCE_ID()));
+
+ aProjection->boolean(COPY_ID())->setValue(keepBackRef);
aProjection->execute();
aRefAttr->setObject(aProjection);
restoreCurrentFeature();
- if (theID == EXTERNAL_FEATURE_ID()) {
- selection(EXTERNAL_ID())->selectValue(aExtFeature);
+ AttributeBooleanPtr aMakeFixedAttr = boolean(MAKE_FIXED());
+ bool isMakeFixed = aMakeFixedAttr && aMakeFixedAttr->isInitialized() && aMakeFixedAttr->value();
+
+ AttributeReferencePtr aFixedConstrAttr = reference(FIXED_CONSTRAINT_ID());
+ FeaturePtr aFixedConstraint;
+ if (aFixedConstrAttr && aFixedConstrAttr->isInitialized())
+ aFixedConstraint = ModelAPI_Feature::feature(aFixedConstrAttr->value());
- if (aResult) {
- aResult->setShape(aProjection->lastResult()->shape());
- setResult(aResult);
- GeomShapePtr anEmptyVal;
- aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
+ if (keepBackRef) {
+ if (theID == EXTERNAL_FEATURE_ID()) {
+ selection(EXTERNAL_ID())->selectValue(aExtFeature);
- static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
- ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
+ if (aResult) {
+ aResult->setShape(aProjection->lastResult()->shape());
+ setResult(aResult);
+ GeomShapePtr anEmptyVal;
+ aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
+ }
}
}
+ else if (isMakeFixed) {
+ // fix the projected entity with the Fixed constraint
+ if (!aFixedConstraint)
+ aFixedConstraint = sketch()->addFeature(SketchPlugin_ConstraintRigid::ID());
+ aFixedConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(
+ aProjection->lastResult());
+ }
+
+
+ // remove Fixed constraint in case of redundance
+ if (aFixedConstraint && (keepBackRef || !isMakeFixed)) {
+ document()->removeFeature(aFixedConstraint);
+ aFixedConstraint = FeaturePtr();
+ }
+ aFixedConstrAttr->setValue(aFixedConstraint);
+
+ static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
+ ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
}
bool SketchPlugin_Projection::rebuildProjectedFeature(
return MY_INCLUDE;
}
+ static const std::string& KEEP_REFERENCE_ID()
+ {
+ static std::string ID("keep_reference");
+ return ID;
+ }
+
+ static const std::string& MAKE_FIXED()
+ {
+ static std::string ID("make_fixed");
+ return ID;
+ }
+
+ static const std::string& FIXED_CONSTRAINT_ID()
+ {
+ static std::string ID("fixed_constraint");
+ return ID;
+ }
+
/// Returns true because projected feature is always external
virtual bool isFixed()
{ return true; }
/// Called on change of any argument-attribute of this object: for external point
SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+ /// Returns true if this feature is used as macro: creates other features and then removed.
+ /// This feature may change its macro-state according to selected item.
+ /// \returns false by default
+ SKETCHPLUGIN_EXPORT virtual bool isMacro() const;
+
/// Use plugin manager for features creation
SketchPlugin_Projection();
/// \brief Initializes attributes of derived class.
virtual void initDerivedClassAttributes();
+ /// \brief Initializes attributes of keeping the reference to the original shape.
+ virtual void initDerivedClassAttributes2();
+
private:
/// \brief Find projection of a feature onto sketch plane
void computeProjection(const std::string& theID);
anAttr = data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId());
anAttr->setIsArgument(false);
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID());
+
+ // initialize the rest of attributes
+ initDerivedClassAttributes2();
}
/// \brief Initializes attributes of derived class.
virtual void initDerivedClassAttributes(){};
+ /// \brief Initializes attributes of derived class which were added recently.
+ virtual void initDerivedClassAttributes2(){};
+
};
#endif
#include "SketchPlugin_Tools.h"
#include "SketchPlugin_Arc.h"
+#include "SketchPlugin_BSpline.h"
#include "SketchPlugin_Circle.h"
#include "SketchPlugin_ConstraintCoincidence.h"
#include "SketchPlugin_ConstraintCoincidenceInternal.h"
#include <SketcherPrs_Tools.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
#include <ModelGeomAlgo_Point2D.h>
#include <ModelGeomAlgo_Shape.h>
return aPnt;
}
-std::set<FeaturePtr> findCoincidentConstraints(const FeaturePtr& theFeature)
+std::set<FeaturePtr> findCoincidentConstraints(const ObjectPtr& theObject)
{
std::set<FeaturePtr> aCoincident;
- const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
+ const std::set<AttributePtr>& aRefsList = theObject->data()->refsToMe();
std::set<AttributePtr>::const_iterator aIt;
for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
// Useful to find points coincident to a given point.
class CoincidentPoints
{
+ static const int THE_DEFAULT_INDEX = -1;
+
public:
- void addCoincidence(const AttributePoint2DPtr& thePoint1,
- const AttributePoint2DPtr& thePoint2 = AttributePoint2DPtr())
+ void addCoincidence(const AttributePtr& thePoint1, const int theIndex1,
+ const AttributePtr& thePoint2, const int theIndex2)
{
- std::list< std::set<AttributePoint2DPtr> >::iterator aFound1 = find(thePoint1);
- std::list< std::set<AttributePoint2DPtr> >::iterator aFound2 = find(thePoint2);
+ auto aFound1 = find(thePoint1, theIndex1);
+ auto aFound2 = find(thePoint2, theIndex2);
if (aFound1 == myCoincidentPoints.end()) {
if (aFound2 == myCoincidentPoints.end()) {
- std::set<AttributePoint2DPtr> aNewSet;
- aNewSet.insert(thePoint1);
+ std::map<AttributePtr, std::set<int> > aNewSet;
+ aNewSet[thePoint1].insert(theIndex1);
if (thePoint2)
- aNewSet.insert(thePoint2);
+ aNewSet[thePoint2].insert(theIndex2);
myCoincidentPoints.push_back(aNewSet);
} else
- aFound2->insert(thePoint1);
+ (*aFound2)[thePoint1].insert(theIndex1);
} else if (aFound2 == myCoincidentPoints.end()) {
if (thePoint2)
- aFound1->insert(thePoint2);
+ (*aFound1)[thePoint2].insert(theIndex2);
} else {
- aFound1->insert(aFound2->begin(), aFound2->end());
+ for (auto it = aFound2->begin(); it != aFound2->end(); ++it)
+ (*aFound1)[it->first].insert(it->second.begin(), it->second.end());
myCoincidentPoints.erase(aFound2);
}
}
{
collectCoincidentPoints(thePoint);
- std::list< std::set<AttributePoint2DPtr> >::iterator aFound = find(thePoint);
- if (aFound == myCoincidentPoints.end())
- return std::set<AttributePoint2DPtr>();
- return *aFound;
+ std::set<AttributePoint2DPtr> aCoincPoints;
+ auto aFound = find(thePoint, THE_DEFAULT_INDEX);
+ if (aFound != myCoincidentPoints.end()) {
+ for (auto it = aFound->begin(); it != aFound->end(); ++it) {
+ AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(it->first);
+ if (aPoint)
+ aCoincPoints.insert(aPoint);
+ else {
+ AttributePoint2DArrayPtr aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(it->first);
+ if (aPointArray) {
+ // this is a B-spline feature, the connection is possible
+ // to the first or the last point
+ FeaturePtr anOwner = ModelAPI_Feature::feature(aPointArray->owner());
+ if (it->second.find(0) != it->second.end()) {
+ AttributePoint2DPtr aFirstPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ anOwner->attribute(SketchPlugin_BSpline::START_ID()));
+ aCoincPoints.insert(aFirstPoint);
+ }
+ if (it->second.find(aPointArray->size() - 1) != it->second.end()) {
+ AttributePoint2DPtr aFirstPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ anOwner->attribute(SketchPlugin_BSpline::END_ID()));
+ aCoincPoints.insert(aFirstPoint);
+ }
+ }
+ }
+ }
+ }
+ return aCoincPoints;
}
private:
{
// iterate through coincideces for the given feature
std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(theFeature);
- std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
+ if (theFeature->getKind() == SketchPlugin_Point::ID()) {
+ std::set<FeaturePtr> aCoincToRes =
+ SketchPlugin_Tools::findCoincidentConstraints(theFeature->lastResult());
+ aCoincidences.insert(aCoincToRes.begin(), aCoincToRes.end());
+ }\r std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
for (; aCIt != aCoincidences.end(); ++aCIt)
{
if (theCoincidences.find(*aCIt) != theCoincidences.end())
// iterate on coincident attributes
for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
- if (aRefAttr && !aRefAttr->isObject())
- {
- FeaturePtr anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
- if (anOwner != theFeature)
- coincidences(anOwner, theCoincidences);
+ if (!aRefAttr)
+ continue;
+ FeaturePtr anOwner;
+ if (aRefAttr->isObject()) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ if (aFeature->getKind() == SketchPlugin_Point::ID())
+ anOwner = aFeature;
}
+ else
+ anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
+ if (anOwner && anOwner != theFeature)
+ coincidences(anOwner, theCoincidences);
}
}
}
// (two points may be coincident through the third point)
void collectCoincidentPoints(const AttributePoint2DPtr& thePoint)
{
- AttributePoint2DPtr aPoints[2];
+ AttributePtr aPoints[2];
+ int anIndicesInArray[2];
FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
std::set<FeaturePtr> aCoincidences;
std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
for (; aCIt != aCoincidences.end(); ++aCIt) {
- aPoints[0] = AttributePoint2DPtr();
- aPoints[1] = AttributePoint2DPtr();
+ aPoints[0] = aPoints[1] = AttributePtr();
+ anIndicesInArray[0] = anIndicesInArray[1] = THE_DEFAULT_INDEX;
for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
- if (aRefAttr && !aRefAttr->isObject())
- aPoints[aPtInd++] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
+ if (!aRefAttr)
+ continue;
+ if (aRefAttr->isObject()) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
+ aPoints[aPtInd++] = aFeature->attribute(SketchPlugin_Point::COORD_ID());
+ }
+ else {
+ AttributePoint2DPtr aPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
+ AttributePoint2DArrayPtr aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(aRefAttr->attr());
+ if (aPointAttr)
+ aPoints[aPtInd++] = aPointAttr;
+ else if (aPointArray) {
+ AttributeIntegerPtr anIndexAttr = (*aCIt)->integer(i == 0 ?
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ aPoints[aPtInd] = aPointArray;
+ anIndicesInArray[aPtInd++] = anIndexAttr->value();
+ }
+ }
}
if (aPoints[0] && aPoints[1])
- addCoincidence(aPoints[0], aPoints[1]);
+ addCoincidence(aPoints[0], anIndicesInArray[0], aPoints[1], anIndicesInArray[1]);
}
}
- std::list< std::set<AttributePoint2DPtr> >::iterator find(const AttributePoint2DPtr& thePoint)
+ std::list< std::map<AttributePtr, std::set<int> > >::iterator find(const AttributePtr& thePoint,
+ const int theIndex)
{
- std::list< std::set<AttributePoint2DPtr> >::iterator aSeek = myCoincidentPoints.begin();
- for (; aSeek != myCoincidentPoints.end(); ++aSeek)
- if (aSeek->find(thePoint) != aSeek->end())
+ auto aSeek = myCoincidentPoints.begin();
+ for (; aSeek != myCoincidentPoints.end(); ++aSeek) {
+ auto aFound = aSeek->find(thePoint);
+ if (aFound != aSeek->end() && aFound->second.find(theIndex) != aFound->second.end())
return aSeek;
+ }
+ // nothing is found, but if the point is a B-spline boundary point, lets check it as poles array
+ FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
+ if (anOwner->getKind() == SketchPlugin_BSpline::ID()) {
+ AttributePtr aPointsArray;
+ int anIndex = -1;
+ if (thePoint->id() == SketchPlugin_BSpline::START_ID()) {
+ aPointsArray = anOwner->attribute(SketchPlugin_BSpline::POLES_ID());
+ anIndex = 0;
+ }
+ else if (thePoint->id() == SketchPlugin_BSpline::END_ID()) {
+ aPointsArray = anOwner->attribute(SketchPlugin_BSpline::POLES_ID());
+ anIndex = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(aPointsArray)->size() - 1;
+ }
+ if (aPointsArray)
+ return find(aPointsArray, anIndex);
+ }
return myCoincidentPoints.end();
}
private:
- std::list< std::set<AttributePoint2DPtr> > myCoincidentPoints;
+ std::list< std::map<AttributePtr, std::set<int> > > myCoincidentPoints;
};
std::set<AttributePoint2DPtr> findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint)
return aCoincidentPoints.coincidentPoints(thePoint);
}
+
void resetAttribute(SketchPlugin_Feature* theFeature,
const std::string& theId)
{
aStartAttributeName = SketchPlugin_EllipticArc::START_POINT_ID();
anEndAttributeName = SketchPlugin_EllipticArc::END_POINT_ID();
}
+ else if (aFeatureKind == SketchPlugin_BSpline::ID()) {
+ aStartAttributeName = SketchPlugin_BSpline::START_ID();
+ anEndAttributeName = SketchPlugin_BSpline::END_ID();
+ }
if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
theFeature->attribute(aStartAttributeName));
#include <GeomAPI_Shape.h>
#include <GeomAPI_AISObject.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomAlgoAPI_ShapeTools.h>
#include <list>
std::shared_ptr<GeomAPI_Pnt2d> getCoincidencePoint(const FeaturePtr theStartCoin);
/// Find all Coincident constraints referred to the feature or its attribute
-std::set<FeaturePtr> findCoincidentConstraints(const FeaturePtr& theFeature);
+std::set<FeaturePtr> findCoincidentConstraints(const ObjectPtr& theObject);
/// Finds lines coincident at point
/// \param[in] theStartCoin coincidence feature
#include "SketchPlugin_Ellipse.h"
#include "SketchPlugin_EllipticArc.h"
#include "SketchPlugin_Fillet.h"
+#include "SketchPlugin_CurveFitting.h"
#include "SketchPlugin_Line.h"
#include "SketchPlugin_MacroArc.h"
#include "SketchPlugin_MacroCircle.h"
#include "SketchPlugin_MultiRotation.h"
+#include "SketchPlugin_Offset.h"
#include "SketchPlugin_Point.h"
#include "SketchPlugin_Sketch.h"
#include "SketchPlugin_Trim.h"
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefAttrList.h>
#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_AttributeSelectionList.h>
#include <ModelAPI_AttributeString.h>
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
AttributeRefListPtr aSelAttr =
std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
+ std::set<ObjectPtr> aSelected;
AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
std::list<ObjectPtr>::iterator anObjIter;
for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
ObjectPtr aSelObject = aSelAttr->object(anInd);
+ if (aSelected.find(aSelObject) != aSelected.end()) {
+ theError = "Error: An object selected twice";
+ return false;
+ }
+ aSelected.insert(aSelObject);
+
anObjIter = anInitialObjects.begin();
for (; anObjIter != anInitialObjects.end(); anObjIter++)
if (aSelObject == *anObjIter)
// B-splines are not supported in Copying features
FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
- if (aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
+ if (aFeature->getKind() != SketchPlugin_Offset::ID() &&
+ aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
theError = "Not supported";
return false;
}
anObjIter = aCopiedObjects.begin();
- for (; anObjIter != aCopiedObjects.end(); anObjIter++)
- if (aSelObject == *anObjIter) {
+ for (; anObjIter != aCopiedObjects.end(); anObjIter++) {
+ bool isFound = aSelObject == *anObjIter;
+ if (!isFound) {
+ // check in the results of the feature
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
+ if (aFeature) {
+ const std::list<ResultPtr>& aResults = aFeature->results();
+ for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
+ aResIt != aResults.end() && !isFound; ++aResIt) {
+ isFound = aSelObject == *aResIt;
+ }
+ }
+ }
+ if (isFound) {
std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
theError = "The object %1 is a result of copy";
theError.arg(aName);
return false;
}
+ }
}
return true;
}
std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
double aDot = fabs(aNormal->dot(anEllipseNormal));
- aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
+ aValid = aDot >= tolerance * tolerance;
if (!aValid)
theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
: "Error: Elliptic Arc is orthogonal to the sketch plane.");
return true;
}
+
+bool SketchPlugin_CurveFittingValidator::isValid(const FeaturePtr& theFeature,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ AttributeRefAttrListPtr aRefAttrList =
+ theFeature->refattrlist(SketchPlugin_CurveFitting::POINTS_ID());
+ AttributeBooleanPtr aPeriodicAttr =
+ theFeature->boolean(SketchPlugin_CurveFitting::PERIODIC_ID());
+
+ // check number of selected entities
+ int aMinNbPoints = aPeriodicAttr->value() ? 3 : 2;
+ if (aRefAttrList->size() < aMinNbPoints) {
+ theError = "Not enough points selected. Need at least %1 points.";
+ theError.arg(aMinNbPoints);
+ return false;
+ }
+ return true;
+}
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_CurveFittingValidator
+ * \ingroup Validators
+ * \brief Validator for the selected vertices for the curve fitting feature.
+ */
+class SketchPlugin_CurveFittingValidator : public ModelAPI_FeatureValidator
+{
+public:
+ //! returns true if number of selected points is greater than the minimal value
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute
+ //! \param theError error message
+ virtual bool isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
#endif
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="en_US">
+
+ <context>
+ <name>workshop</name>
+ <message>
+ <source>Curve fitting</source>
+ <translation>Curve fitting</translation>
+ </message>
+ </context>
+
<context>
<name>Sketch:Model_FeatureValidator</name>
<message>
<translation>Edges in selected point has tangent constraint</translation>
</message>
</context>
-
+
+ <context>
+ <name>SketchProjection</name>
+ <message>
+ <source>Project feature onto sketch plane</source>
+ <translation>Project feature onto sketch plane</translation>
+ </message>
+ <message>
+ <source>Projection</source>
+ <translation>Projection</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:ExternalFeature</name>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Select external edge or vertex.</translation>
+ </message>
+ <message>
+ <source>Object</source>
+ <translation>Object</translation>
+ </message>
+ <message>
+ <source>Select external edge or vertex.</source>
+ <translation>Select external edge or vertex.</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:IncludeToResult</name>
+ <message>
+ <source>Include into the sketch result</source>
+ <translation>Include into the sketch result</translation>
+ </message>
+ <message>
+ <source>Include projected feature into the sketch result</source>
+ <translation>Include projected feature into the sketch result</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:keep_reference</name>
+ <message>
+ <source>A sketch entity will be created without connection to the selected shape.</source>
+ <translation>A sketch entity will be created without connection to the selected shape.</translation>
+ </message>
+ <message>
+ <source>The reference to the original curve is stored. So it can be changed later.</source>
+ <translation>The reference to the original curve is stored. So it can be changed later.</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:make_fixed</name>
+ <message>
+ <source>Assign the Fixed constraint to the result of projection</source>
+ <translation>Assign the Fixed constraint to the result of projection</translation>
+ </message>
+ <message>
+ <source>Make projected curve fixed</source>
+ <translation>Make projected curve fixed</translation>
+ </message>
+ </context>
<context>
<name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
<message>
<translation>Error: Selected object is not supported for projection.</translation>
</message>
</context>
+
+ <!-- SketchCurveFitting -->
+ <context>
+ <name>SketchCurveFitting</name>
+ <message>
+ <source>Curve fitting</source>
+ <translation>Curve fitting</translation>
+ </message>
+ <message>
+ <source>Create curve passing through the points</source>
+ <translation>Create curve passing through the points</translation>
+ </message>
+ <message>
+ <source>Error: Feature "%1" does not support action "%2".</source>
+ <translation>Error: Feature "%1" does not support action "%2".</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:SketchPlugin_CurveFittingValidator</name>
+ <message>
+ <source>Not enough points selected. Need at least %1 points.</source>
+ <translation>Not enough points selected. Need at least %1 points.</translation>
+ </message>
+ </context>
<context>
- <name>SketchProjection:Model_FeatureValidator</name>
+ <name>SketchCurveFitting:points</name>
+ <message>
+ <source>Points</source>
+ <translation>Points</translation>
+ </message>
+ <message>
+ <source>Select points for curve fitting</source>
+ <translation>Select points for curve fitting</translation>
+ </message>
<message>
<source>Attribute "%1" is not initialized.</source>
- <translation></translation>
+ <translation>Select points for interpolation</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:periodic</name>
+ <message>
+ <source>Periodic</source>
+ <translation>Periodic</translation>
+ </message>
+ <message>
+ <source>Make curve periodic</source>
+ <translation>Make curve periodic</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:closed</name>
+ <message>
+ <source>Closed</source>
+ <translation>Closed</translation>
+ </message>
+ <message>
+ <source>Make curve closed, but not periodic</source>
+ <translation>Make curve closed, but not periodic</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:type</name>
+ <message>
+ <source>Interpolation</source>
+ <translation>Interpolation</translation>
+ </message>
+ <message>
+ <source>Approximation</source>
+ <translation>Approximation</translation>
</message>
</context>
+ <context>
+ <name>SketchCurveFitting:precision</name>
+ <message>
+ <source>Precision</source>
+ <translation>Precision</translation>
+ </message>
+ <message>
+ <source>Maximal distance from selected points to the curve</source>
+ <translation>Maximal distance from selected points to the curve</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:need_control_poly</name>
+ <message>
+ <source>Create control polygon</source>
+ <translation>Create control polygon</translation>
+ </message>
+ <message>
+ <source>Specify if the control polygon should be created</source>
+ <translation>Specify if the control polygon should be created</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:reorder_points</name>
+ <message>
+ <source>Reorder points</source>
+ <translation>Reorder points</translation>
+ </message>
+ <message>
+ <source>Sort selected points to minimize the distance heighbors</source>
+ <translation>Sort selected points to minimize the distance heighbors</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:Auxiliary</name>
+ <message>
+ <source>Auxiliary</source>
+ <translation>Auxiliary</translation>
+ </message>
+ <message>
+ <source>Construction element</source>
+ <translation>Construction element</translation>
+ </message>
+ </context>
+
</TS>
<source>Horizontal Distance</source>
<translation>Distance horizontale</translation>
</message>
+ <message>
+ <source>Curve fitting</source>
+ <translation>Courbe d'ajustement</translation>
+ </message>
<message>
<source>Length</source>
<translation>Longueur</translation>
</message>
</context>
- <context>
- <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
- <message>
- <source>The attribute with the %1 type is not processed</source>
- <translation>Un argument de type %1 de la fonctionnalité de projection n'est pas pris en charge</translation>
- </message>
- <message>
- <source>The attribute %1 should be an edge</source>
- <translation>L'attribut %1 doit être une arête</translation>
- </message>
- <message>
- <source>There is no sketch referring to the current feature</source>
- <translation>La fonction de projection n'a pas d'esquisse</translation>
- </message>
- <message>
- <source>The attribute %1 should be an edge or vertex</source>
- <translation>L'élément projeté doit être une arête ou un sommet</translation>
- </message>
- <message>
- <source>Unable to project feature from the same sketch</source>
- <translation>Les fonctions de l'esquisse en cours ne peuvent pas être projetées</translation>
- </message>
- <message>
- <source>Error: Line is orthogonal to the sketch plane.</source>
- <translation>Erreur: La ligne est orthogonale au plan d'esquisse.</translation>
- </message>
- <message>
- <source>Error: Circle is orthogonal to the sketch plane.</source>
- <translation>Erreur: Le cercle est orthogonal au plan d'esquisse.</translation>
- </message>
- <message>
- <source>Error: Arc is orthogonal to the sketch plane.</source>
- <translation>Erreur: L'arc est orthogonal au plan d'esquisse.</translation>
- </message>
- <message>
- <source>Error: Ellipse is orthogonal to the sketch plane.</source>
- <translation>Erreur: L'ellipse est orthogonale au plan d'esquisse.</translation>
- </message>
- <message>
- <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
- <translation>Erreur: L'arc d'ellipse est orthogonal au plan d'esquisse.</translation>
- </message>
- <message>
- <source>Error: Periodic B-spline is orthogonal to the sketch plane.</source>
- <translation>Erreur: La B-spline périodique est orthogonale au plan d'esquisse.</translation>
- </message>
- <message>
- <source>Error: Selected object is not supported for projection.</source>
- <translation>Erreur: L'objet sélectionné n'est pas pris en charge pour la projection.</translation>
- </message>
- </context>
- <context>
- <name>SketchProjection:Model_FeatureValidator</name>
- <message>
- <source>Attribute "%1" is not initialized.</source>
- <translation>L'attribut "%1" n'est pas initialisé.</translation>
- </message>
- </context>
- <context>
- <name>SketchProjection:ExternalFeature</name>
- <message>
- <source>Attribute "%1" is not initialized.</source>
- <translation>L'attribut "%1" n'est pas initialisé.</translation>
- </message>
- <message>
- <source>Object</source>
- <translation>Objet</translation>
- </message>
- <message>
- <source>Select external edge or vertex.</source>
- <translation>Sélectionnez une arête externe ou un sommet.</translation>
- </message>
- </context>
-
<context>
<name>Sketch</name>
<message>
<translation>Inclure la fonctionnalité projetée dans le résultat de l'esquisse</translation>
</message>
</context>
+ <context>
+ <name>SketchProjection:keep_reference</name>
+ <message>
+ <source>A sketch entity will be created without connection to the selected shape.</source>
+ <translation>Une entité d'esquisse sera créée sans connexion à la forme sélectionnée.</translation>
+ </message>
+ <message>
+ <source>The reference to the original curve is stored. So it can be changed later.</source>
+ <translation>La référence à la courbe d'origine est stockée. Elle peut donc être modifiée ultérieurement.</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:make_fixed</name>
+ <message>
+ <source>Assign the Fixed constraint to the result of projection</source>
+ <translation>Affectez la contrainte Fixe au résultat de la projection</translation>
+ </message>
+ <message>
+ <source>Make projected curve fixed</source>
+ <translation>Fixer la courbe projetée</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
+ <message>
+ <source>The attribute with the %1 type is not processed</source>
+ <translation>Un argument de type %1 de la fonctionnalité de projection n'est pas pris en charge</translation>
+ </message>
+ <message>
+ <source>The attribute %1 should be an edge</source>
+ <translation>L'attribut %1 doit être une arête</translation>
+ </message>
+ <message>
+ <source>There is no sketch referring to the current feature</source>
+ <translation>La fonction de projection n'a pas d'esquisse</translation>
+ </message>
+ <message>
+ <source>The attribute %1 should be an edge or vertex</source>
+ <translation>L'élément projeté doit être une arête ou un sommet</translation>
+ </message>
+ <message>
+ <source>Unable to project feature from the same sketch</source>
+ <translation>Les fonctions de l'esquisse en cours ne peuvent pas être projetées</translation>
+ </message>
+ <message>
+ <source>Error: Line is orthogonal to the sketch plane.</source>
+ <translation>Erreur: La ligne est orthogonale au plan d'esquisse.</translation>
+ </message>
+ <message>
+ <source>Error: Circle is orthogonal to the sketch plane.</source>
+ <translation>Erreur: Le cercle est orthogonal au plan d'esquisse.</translation>
+ </message>
+ <message>
+ <source>Error: Arc is orthogonal to the sketch plane.</source>
+ <translation>Erreur: L'arc est orthogonal au plan d'esquisse.</translation>
+ </message>
+ <message>
+ <source>Error: Ellipse is orthogonal to the sketch plane.</source>
+ <translation>Erreur: L'ellipse est orthogonale au plan d'esquisse.</translation>
+ </message>
+ <message>
+ <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
+ <translation>Erreur: L'arc d'ellipse est orthogonal au plan d'esquisse.</translation>
+ </message>
+ <message>
+ <source>Error: Selected object is not supported for projection.</source>
+ <translation>Erreur: L'objet sélectionné n'est pas pris en charge pour la projection.</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:Model_FeatureValidator</name>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>L'attribut "%1" n'est pas initialisé.</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchProjection:ExternalFeature</name>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Sélectionnez une arête externe ou un sommet.</translation>
+ </message>
+ <message>
+ <source>Object</source>
+ <translation>Objet</translation>
+ </message>
+ <message>
+ <source>Select external edge or vertex.</source>
+ <translation>Sélectionnez une arête externe ou un sommet.</translation>
+ </message>
+ </context>
<context>
<name>SketchRectangle</name>
</message>
</context>
+ <!-- SketchCurveFitting-->
+ <context>
+ <name>SketchCurveFitting</name>
+ <message>
+ <source>Curve fitting</source>
+ <translation>Courbe d'ajustement</translation>
+ </message>
+ <message>
+ <source>Create curve passing through the points</source>
+ <translation>Créer une courbe passant par les points</translation>
+ </message>
+ <message>
+ <source>Error: Feature "%1" does not support action "%2".</source>
+ <translation>Erreur: la fonctionnalité "% 1" ne prend pas en charge l'action "% 2".</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:SketchPlugin_CurveFittingValidator</name>
+ <message>
+ <source>Not enough points selected. Need at least %1 points.</source>
+ <translation>Pas assez de points sélectionnés. Besoin d'au moins %1 points.</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:points</name>
+ <message>
+ <source>Points</source>
+ <translation>Points</translation>
+ </message>
+ <message>
+ <source>Select points for curve fitting</source>
+ <translation>Sélectionner des points pour l'ajustement de courbe</translation>
+ </message>
+ <message>
+ <source>Attribute "%1" is not initialized.</source>
+ <translation>Sélectionner des points pour l'ajustement de courbe</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:periodic</name>
+ <message>
+ <source>Periodic</source>
+ <translation>Périodique</translation>
+ </message>
+ <message>
+ <source>Make curve periodic</source>
+ <translation>Rendre la courbe périodique</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:closed</name>
+ <message>
+ <source>Closed</source>
+ <translation>Fermé</translation>
+ </message>
+ <message>
+ <source>Make curve closed, but not periodic</source>
+ <translation>Rendre la courbe fermée, mais pas périodique</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:type</name>
+ <message>
+ <source>Interpolation</source>
+ <translation>Interpolation</translation>
+ </message>
+ <message>
+ <source>Approximation</source>
+ <translation>Approximation</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:precision</name>
+ <message>
+ <source>Precision</source>
+ <translation>Précision</translation>
+ </message>
+ <message>
+ <source>Maximal distance from selected points to the curve</source>
+ <translation>Distance maximale entre les points sélectionnés et la courbe</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:need_control_poly</name>
+ <message>
+ <source>Create control polygon</source>
+ <translation>Créer un polygone de contrôle</translation>
+ </message>
+ <message>
+ <source>Specify if the control polygon should be created</source>
+ <translation>Précisez si le polygone de contrôle doit être créé</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:reorder_points</name>
+ <message>
+ <source>Reorder points</source>
+ <translation>Réorganiser les points</translation>
+ </message>
+ <message>
+ <source>Sort selected points to minimize the distance heighbors</source>
+ <translation>Trier les points sélectionnés pour minimiser la distance des voisins</translation>
+ </message>
+ </context>
+ <context>
+ <name>SketchCurveFitting:Auxiliary</name>
+ <message>
+ <source>Auxiliary</source>
+ <translation>Auxiliaire</translation>
+ </message>
+ <message>
+ <source>Construction element</source>
+ <translation>Élément de construction</translation>
+ </message>
+ </context>
+
</TS>
--- /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
+#
+
+"""
+ Test creation of B-spline curve passing through the list of points
+"""
+
+import math
+import unittest
+
+from salome.shaper import model
+
+from GeomAPI import *
+from ModelAPI import *
+from ModelHighAPI import *
+from SketchAPI import *
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools as shapetools
+
+__updated__ = "2020-06-27"
+
+TOLERANCE = 1.e-7
+
+class TestInterpolation(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ coordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ self.myPoints = []
+ self.myPointRefs = []
+ for p in coordinates:
+ self.myPoints.append(self.mySketch.addPoint(p[0], p[1]))
+ self.myPointRefs.append(self.myPoints[-1].coordinates())
+ self.myDOF = 10
+ self.myNbPoints = len(self.myPoints)
+ self.myNbLines = 0
+ self.myNbSplines = 0
+ self.myNbPeriodicSplines = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointsOnCurve(self, theCurve):
+ for p in self.myPoints:
+ shape = p.defaultResult().shape()
+ self.assertTrue(shapetools.minimalDistance(shape, theCurve) < TOLERANCE)
+
+
+ def test_interpolation(self):
+ """ Test 1. Create B-spline curve by set of points
+ """
+ self.mySpline = self.mySketch.addInterpolation(self.myPointRefs)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs) - 2
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 172.237458
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_interpolation_periodic(self):
+ """ Test 2. Create periodic B-spline curve by set of points
+ """
+ self.mySpline = self.mySketch.addInterpolation(self.myPointRefs, periodic = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs)
+ self.myNbPeriodicSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == True)
+ EXPECTED_LEN = 262.60929483
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_interpolation_closed(self):
+ """ Test 3. Create closed but not periodic B-spline curve by set of points
+ """
+ self.mySpline = self.mySketch.addInterpolation(self.myPointRefs, closed = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs) - 3
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ self.assertTrue(curve.poles()[0].distance(curve.poles()[-1]) < TOLERANCE)
+ EXPECTED_LEN = 274.25674928
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_interpolation_reorder(self):
+ """ Test 4. Check reordering of points works properly
+ """
+ model.do()
+ # use low-level API to create feature
+ curveFitting = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchCurveFitting")
+ curveFitting.string("type").setValue("interpolation_type")
+ curveFitting.boolean("periodic").setValue(False)
+ curveFitting.boolean("closed").setValue(False)
+ pointsAttr = curveFitting.refattrlist("points")
+ for ind in [0, 3, 4, 2, 1]:
+ pointsAttr.append(self.myPointRefs[ind])
+ # perform reordering
+ curveFitting.customAction("reorder_points")
+ model.do()
+
+ self.mySpline = SketchAPI_BSpline(model.lastSubFeature(self.mySketch, "SketchBSpline"))
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs) - 2
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 172.237458
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /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
+#
+
+"""
+ Test creation of B-spline curve passing through the list of points
+"""
+
+import math
+import unittest
+
+from salome.shaper import model
+
+from GeomAPI import *
+from ModelAPI import *
+from ModelHighAPI import *
+from SketchAPI import *
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools as shapetools
+
+__updated__ = "2020-06-27"
+
+TOLERANCE = 1.e-7
+POINT_NAMES = []
+
+class TestInterpolationExternal(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoints = []
+ self.myPointRefs = []
+ for name in POINT_NAMES:
+ proj = self.mySketch.addProjection(model.selection("VERTEX", name), False)
+ self.myPoints.append(SketchAPI_Point(proj.createdFeature()))
+ self.myPointRefs.append(self.myPoints[-1].coordinates())
+ self.myDOF = 0
+ self.myNbPoints = len(self.myPoints)
+ self.myNbLines = 0
+ self.myNbSplines = 0
+ self.myNbPeriodicSplines = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointsOnCurve(self, theCurve):
+ for p in self.myPoints:
+ shape = p.defaultResult().shape()
+ self.assertTrue(shapetools.minimalDistance(shape, theCurve) < TOLERANCE)
+
+
+ def test_interpolation(self):
+ """ Test 1. Create B-spline curve by set of points
+ """
+ self.mySpline = self.mySketch.addInterpolation(self.myPointRefs)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs) - 2
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 172.237458
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_interpolation_periodic(self):
+ """ Test 2. Create periodic B-spline curve by set of points
+ """
+ self.mySpline = self.mySketch.addInterpolation(self.myPointRefs, periodic = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs)
+ self.myNbPeriodicSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == True)
+ EXPECTED_LEN = 262.60929483
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_interpolation_closed(self):
+ """ Test 3. Create closed but not periodic B-spline curve by set of points
+ """
+ self.mySpline = self.mySketch.addInterpolation(self.myPointRefs, closed = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs) - 3
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ self.assertTrue(curve.poles()[0].distance(curve.poles()[-1]) < TOLERANCE)
+ EXPECTED_LEN = 274.25674928
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_interpolation_reorder(self):
+ """ Test 4. Check reordering of points works properly
+ """
+ model.do()
+ # use low-level API to create feature
+ curveFitting = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchCurveFitting")
+ curveFitting.string("type").setValue("interpolation_type")
+ curveFitting.boolean("periodic").setValue(False)
+ curveFitting.boolean("closed").setValue(False)
+ pointsAttr = curveFitting.refattrlist("points")
+ for ind in [0, 3, 4, 2, 1]:
+ pointsAttr.append(self.myPointRefs[ind])
+ # perform reordering
+ curveFitting.customAction("reorder_points")
+ model.do()
+
+ self.mySpline = SketchAPI_BSpline(model.lastSubFeature(self.mySketch, "SketchBSpline"))
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - len(self.myPointRefs) - 2
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 172.237458
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+
+if __name__ == "__main__":
+ # Create a sketch with the external points
+ model.begin()
+ document = model.moduleDocument()
+ coordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ for p in coordinates:
+ point3D = model.addPoint(document, p[0], p[1], 0)
+ POINT_NAMES.append(point3D.name())
+ model.end()
+
+ # Run testing
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /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
+#
+
+"""
+ Test creation of B-spline curve passing through the list of points
+"""
+
+import math
+import unittest
+
+from salome.shaper import model
+
+from GeomAPI import *
+from ModelAPI import *
+from ModelHighAPI import *
+from SketchAPI import *
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools as shapetools
+
+__updated__ = "2020-06-28"
+
+TOLERANCE = 1.e-7
+
+class TestApproximation(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ coordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ self.myPoints = []
+ self.myPointRefs = []
+ for p in coordinates:
+ self.myPoints.append(self.mySketch.addPoint(p[0], p[1]))
+ self.myPointRefs.append(self.myPoints[-1].coordinates())
+ self.myDOF = 10
+ self.myNbPoints = len(self.myPoints)
+ self.myNbLines = 0
+ self.myNbSplines = 0
+ self.myNbPeriodicSplines = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointsOnCurve(self, theCurve, theTolerance = 1.e-3):
+ for p in self.myPoints:
+ shape = p.defaultResult().shape()
+ self.assertTrue(shapetools.minimalDistance(shape, theCurve) < theTolerance)
+
+
+ def test_approximation_default(self):
+ """ Test 1. Create B-spline curve approximating a set of points with the default precision
+ """
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 4)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 189.17832318
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_approximation_custom(self):
+ """ Test 2. Create B-spline curve approximating a set of points with the custom precision
+ """
+ PRECISION = 10
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, precision = PRECISION)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 166.97400096
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+ def test_approximation_periodic_default(self):
+ """ Test 3. Create periodic B-spline curve approximating set of points with the default precision
+ """
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, periodic = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2
+ self.myNbPeriodicSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == True)
+ EXPECTED_LEN = 390.98013747
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_approximation_periodic_custom(self):
+ """ Test 4. Create periodic B-spline curve approximating set of points with the custom precision
+ """
+ PRECISION = 10
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, precision = PRECISION, periodic = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2
+ self.myNbPeriodicSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == True)
+ EXPECTED_LEN = 390.98013747
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+ def test_approximation_closed_default(self):
+ """ Test 5. Create closed but not periodic B-spline curve approximating set of points with the default precision
+ """
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, closed = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 5)
+ self.assertTrue(curve.isPeriodic() == False)
+ self.assertTrue(curve.poles()[0].distance(curve.poles()[-1]) < TOLERANCE)
+ EXPECTED_LEN = 413.18489109
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_approximation_closed_custom(self):
+ """ Test 6. Create closed but not periodic B-spline curve approximating set of points with the custom precision
+ """
+ PRECISION = 10
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, precision = PRECISION, closed = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ self.assertTrue(curve.poles()[0].distance(curve.poles()[-1]) < TOLERANCE)
+ EXPECTED_LEN = 276.27724118
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+ def test_approximation_reorder(self):
+ """ Test 7. Check reordering of points works properly
+ """
+ PRECISION = 10
+ model.do()
+ # use low-level API to create feature
+ curveFitting = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchCurveFitting")
+ curveFitting.string("type").setValue("approximation_type")
+ curveFitting.real("precision").setValue(PRECISION)
+ curveFitting.boolean("periodic").setValue(False)
+ curveFitting.boolean("closed").setValue(False)
+ pointsAttr = curveFitting.refattrlist("points")
+ for ind in [0, 3, 4, 2, 1]:
+ pointsAttr.append(self.myPointRefs[ind])
+ # perform reordering
+ curveFitting.customAction("reorder_points")
+ model.do()
+
+ self.mySpline = SketchAPI_BSpline(model.lastSubFeature(self.mySketch, "SketchBSpline"))
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 166.97400096
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /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
+#
+
+"""
+ Test creation of B-spline curve passing through the list of points
+"""
+
+import math
+import unittest
+
+from salome.shaper import model
+
+from GeomAPI import *
+from ModelAPI import *
+from ModelHighAPI import *
+from SketchAPI import *
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools as shapetools
+
+__updated__ = "2020-06-28"
+
+TOLERANCE = 1.e-7
+POINT_NAMES = []
+
+class TestApproximationExternal(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoints = []
+ self.myPointRefs = []
+ for name in POINT_NAMES:
+ proj = self.mySketch.addProjection(model.selection("VERTEX", name), False)
+ self.myPoints.append(SketchAPI_Point(proj.createdFeature()))
+ self.myPointRefs.append(self.myPoints[-1].coordinates())
+ self.myDOF = 0
+ self.myNbPoints = len(self.myPoints)
+ self.myNbLines = 0
+ self.myNbSplines = 0
+ self.myNbPeriodicSplines = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointsOnCurve(self, theCurve, theTolerance = 1.e-3):
+ for p in self.myPoints:
+ shape = p.defaultResult().shape()
+ self.assertTrue(shapetools.minimalDistance(shape, theCurve) < theTolerance)
+
+
+ def test_approximation_default(self):
+ """ Test 1. Create B-spline curve approximating a set of points with the default precision
+ """
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 4)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 189.17832318
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_approximation_custom(self):
+ """ Test 2. Create B-spline curve approximating a set of points with the custom precision
+ """
+ PRECISION = 10
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, precision = PRECISION)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 166.97400096
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+ def test_approximation_periodic_default(self):
+ """ Test 3. Create periodic B-spline curve approximating set of points with the default precision
+ """
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, periodic = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2
+ self.myNbPeriodicSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == True)
+ EXPECTED_LEN = 390.98013747
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_approximation_periodic_custom(self):
+ """ Test 4. Create periodic B-spline curve approximating set of points with the custom precision
+ """
+ PRECISION = 10
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, precision = PRECISION, periodic = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2
+ self.myNbPeriodicSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == True)
+ EXPECTED_LEN = 390.98013747
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+ def test_approximation_closed_default(self):
+ """ Test 5. Create closed but not periodic B-spline curve approximating set of points with the default precision
+ """
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, closed = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 5)
+ self.assertTrue(curve.isPeriodic() == False)
+ self.assertTrue(curve.poles()[0].distance(curve.poles()[-1]) < TOLERANCE)
+ EXPECTED_LEN = 413.18489109
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge)
+
+ def test_approximation_closed_custom(self):
+ """ Test 6. Create closed but not periodic B-spline curve approximating set of points with the custom precision
+ """
+ PRECISION = 10
+ self.mySpline = self.mySketch.addApproximation(self.myPointRefs, precision = PRECISION, closed = True)
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ self.assertTrue(curve.poles()[0].distance(curve.poles()[-1]) < TOLERANCE)
+ EXPECTED_LEN = 276.27724118
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+ def test_approximation_reorder(self):
+ """ Test 7. Check reordering of points works properly
+ """
+ PRECISION = 10
+ model.do()
+ # use low-level API to create feature
+ curveFitting = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchCurveFitting")
+ curveFitting.string("type").setValue("approximation_type")
+ curveFitting.real("precision").setValue(PRECISION)
+ curveFitting.boolean("periodic").setValue(False)
+ curveFitting.boolean("closed").setValue(False)
+ pointsAttr = curveFitting.refattrlist("points")
+ for ind in [0, 3, 4, 2, 1]:
+ pointsAttr.append(self.myPointRefs[ind])
+ # perform reordering
+ curveFitting.customAction("reorder_points")
+ model.do()
+
+ self.mySpline = SketchAPI_BSpline(model.lastSubFeature(self.mySketch, "SketchBSpline"))
+ edge = GeomAPI_Edge(self.mySpline.defaultResult().shape())
+ curve = GeomAPI_BSpline(GeomAPI_Curve(edge))
+ self.myDOF += len(curve.poles()) * 2 - 4
+ self.myNbSplines += 1
+ model.do()
+
+ self.assertTrue(self.mySpline.feature())
+ self.assertTrue(self.mySpline.feature().error() == "")
+ self.assertTrue(self.mySpline.degree().value() == 3)
+ self.assertTrue(curve.isPeriodic() == False)
+ EXPECTED_LEN = 166.97400096
+ self.assertTrue(math.fabs(edge.length() - EXPECTED_LEN) < TOLERANCE, "Curve length: {}; expected: {}".format(edge.length(), EXPECTED_LEN))
+ # check points lying of the created curve
+ self.checkPointsOnCurve(edge, PRECISION)
+
+
+if __name__ == "__main__":
+ # Create a sketch with the external points
+ model.begin()
+ document = model.moduleDocument()
+ coordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ for p in coordinates:
+ point3D = model.addPoint(document, p[0], p[1], 0)
+ POINT_NAMES.append(point3D.name())
+ model.end()
+
+ # Run testing
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /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
+#
+
+"""
+ TestOffset.py
+ Unit test of SketchPlugin_Offset class
+
+ SketchPlugin_Offset
+ static const std::string ID("SketchOffset");
+ data()->addAttribute(EDGES_ID(), ModelAPI_AttributeRefList::typeId());
+ data()->addAttribute(VALUE_ID(), ModelAPI_AttributeDouble::typeId());
+ data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeIntArray::typeId());
+"""
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2020-06-30"
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def normalize(theDir):
+ aLen = math.hypot(theDir[0], theDir[1])
+ if aLen < 1.e-10:
+ aLen = 1.0
+ return [theDir[0] / aLen, theDir[1] / aLen]
+
+def checkOffset(theListIn, theListOut, theOutToIn, theDist, isReversed, nbIn, nbOut):
+ TOL = 6.e-5
+ aNbIn = theListIn.size()
+ aNbOut = theListOut.size()
+
+ #print("**checkOffset**")
+ assert (theListIn.size() == nbIn)
+ assert (theListOut.size() == nbOut)
+ assert (theOutToIn.size() == nbOut)
+
+ for ind in range(0, aNbOut):
+ aFeatureOut = ModelAPI_Feature.feature(theListOut.object(ind))
+ assert(aFeatureOut is not None)
+ anInInd = theOutToIn.value(ind)
+ if (anInInd == -1):
+ assert(aFeatureOut.getKind() == "SketchArc")
+ else:
+ aFeatureIn = ModelAPI_Feature.feature(theListIn.object(anInInd))
+ assert(aFeatureIn is not None)
+
+ #print(aFeatureIn.getKind())
+ if (aFeatureIn.getKind() == "SketchLine"):
+ assert(aFeatureOut.getKind() == aFeatureIn.getKind())
+ # Line and its offset are parallel
+ aP1Out = geomDataAPI_Point2D(aFeatureOut.attribute('StartPoint'))
+ aP2Out = geomDataAPI_Point2D(aFeatureOut.attribute('EndPoint'))
+ aP1In = geomDataAPI_Point2D(aFeatureIn.attribute('StartPoint'))
+ aP2In = geomDataAPI_Point2D(aFeatureIn.attribute('EndPoint'))
+ aDirOut = [aP2Out.x() - aP1Out.x(), aP2Out.y() - aP1Out.y()]
+ aDirIn = [ aP2In.x() - aP1In.x(), aP2In.y() - aP1In.y()]
+ aCross = aDirOut[0] * aDirIn[1] - aDirOut[1] * aDirIn[0]
+ assert math.fabs(aCross) < TOL, "aCross = {0}".format(aCross)
+ elif (aFeatureIn.getKind() == "SketchArc"):
+ assert(aFeatureOut.getKind() == aFeatureIn.getKind())
+ # Arc and its offset have the same center
+ aCPOut = geomDataAPI_Point2D(aFeatureOut.attribute('center_point'))
+ aCPIn = geomDataAPI_Point2D(aFeatureIn.attribute('center_point'))
+ assert (math.fabs(aCPOut.x() - aCPIn.x()) < TOL)
+ assert (math.fabs(aCPOut.y() - aCPIn.y()) < TOL)
+
+
+#=========================================================================
+# Start of test
+#=========================================================================
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Creation of an arc and two lines
+#=========================================================================
+# Arc
+aSession.startOperation()
+aSketchArc1 = aSketchFeature.addFeature("SketchArc")
+anArcCentr = geomDataAPI_Point2D(aSketchArc1.attribute("center_point"))
+anArcCentr.setValue(10., 10.)
+anArcStartPoint = geomDataAPI_Point2D(aSketchArc1.attribute("start_point"))
+anArcStartPoint.setValue(50., 0.)
+anArcEndPoint = geomDataAPI_Point2D(aSketchArc1.attribute("end_point"))
+anArcEndPoint.setValue(0., 50.)
+aSession.finishOperation()
+# Line 1
+aSession.startOperation()
+aSketchLine1 = aSketchFeature.addFeature("SketchLine")
+aLine1StartPoint = geomDataAPI_Point2D(aSketchLine1.attribute("StartPoint"))
+aLine1EndPoint = geomDataAPI_Point2D(aSketchLine1.attribute("EndPoint"))
+aLine1StartPoint.setValue(0., 50.)
+aLine1EndPoint.setValue(-20., 0.)
+aSession.finishOperation()
+# Line 2
+aSession.startOperation()
+aSketchLine2 = aSketchFeature.addFeature("SketchLine")
+aLine2StartPoint = geomDataAPI_Point2D(aSketchLine2.attribute("StartPoint"))
+aLine2EndPoint = geomDataAPI_Point2D(aSketchLine2.attribute("EndPoint"))
+aLine2StartPoint.setValue(50., 0.)
+aLine2EndPoint.setValue(-20., 0.)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 13)
+#=========================================================================
+# Link arc points and lines points by the coincidence constraints
+#=========================================================================
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintCoincidence")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(anArcEndPoint)
+reflistB.setAttr(aLine1StartPoint)
+aConstraint.execute()
+aSession.finishOperation()
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintCoincidence")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(anArcStartPoint)
+reflistB.setAttr(aLine2StartPoint)
+aConstraint.execute()
+aSession.finishOperation()
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintCoincidence")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(aLine1EndPoint)
+reflistB.setAttr(aLine2EndPoint)
+aConstraint.execute()
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 7)
+#=========================================================================
+# Make offset for objects created above
+#=========================================================================
+VALUE = 13
+IS_REVERSED = False
+aSession.startOperation()
+anOffset = aSketchFeature.addFeature("SketchOffset")
+aRefListInitial = anOffset.reflist("segments")
+aRefListInitial.append(aSketchLine1.lastResult())
+aRefListInitial.append(aSketchArc1.lastResult())
+aRefListInitial.append(aSketchLine2.lastResult())
+anOffset.real("offset_value").setValue(VALUE)
+anOffset.boolean("reversed").setValue(IS_REVERSED)
+anOffset.execute()
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 7)
+#=========================================================================
+# Verify all offset objects
+#=========================================================================
+aRefListA = anOffset.reflist("ConstraintEntityA")
+aRefListB = anOffset.reflist("ConstraintEntityB")
+anOffsetToBaseMap = anOffset.intArray("ConstraintEntityC")
+checkOffset(aRefListA, aRefListB, anOffsetToBaseMap, VALUE, IS_REVERSED, 3, 6)
+assert (model.dof(aSketchFeature) == 7)
+
+#=========================================================================
+# Remove object from offset
+#=========================================================================
+aSession.startOperation()
+aRefListInitial.remove(aSketchLine2.lastResult())
+aSession.finishOperation()
+checkOffset(aRefListA, aRefListB, anOffsetToBaseMap, VALUE, IS_REVERSED, 2, 4)
+assert (model.dof(aSketchFeature) == 7)
+
+#=========================================================================
+# Clear list of objects
+#=========================================================================
+aSession.startOperation()
+aRefListInitial.clear()
+#TODO: uncomment next line
+#checkOffset(aRefListA, aRefListB, anOffsetToBaseMap, VALUE, IS_REVERSED, 0, 0)
+# add arc once again
+aRefListInitial.append(aSketchArc1.lastResult())
+aSession.finishOperation()
+checkOffset(aRefListA, aRefListB, anOffsetToBaseMap, VALUE, IS_REVERSED, 1, 1)
+assert (model.dof(aSketchFeature) == 7)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /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
+
+SKETCH_DOF = 9
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Sketch
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(10, 10, 50, 0, 0, 50, False)
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(0, 50, -20, 0)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(50, 0, -20, 0)
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_2.startPoint())
+model.do()
+
+assert(model.dof(Sketch_1) == SKETCH_DOF)
+
+### Create SketchOffset
+SketchOffset_1_objects = [SketchLine_1.result(), SketchArc_1.results()[1], SketchLine_2.result()]
+SketchOffset_1 = Sketch_1.addOffset(SketchOffset_1_objects, 13, False)
+model.do()
+
+# DoF should not change
+assert(model.dof(Sketch_1) == SKETCH_DOF)
+# check number of features
+assert(len(SketchOffset_1.offset()) == 5)
+model.testNbSubFeatures(Sketch_1, "SketchPoint", 0)
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchArc", 4)
+model.testNbSubFeatures(Sketch_1, "SketchBSpline", 0)
+model.testNbSubFeatures(Sketch_1, "SketchBSplinePeriodic", 0)
+
+model.end()
+
+assert(model.checkPythonDump())
from GeomAPI import *
+circle = SketchCircle_2.results()[-1].resultSubShapePair()[0].shape()
+assert(circle.isEdge() and circle.edge().isCircle())
ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape()
assert(ellipse1.isEdge() and ellipse1.edge().isEllipse())
ellipse2 = SketchEllipse_2.results()[-1].resultSubShapePair()[0].shape()
assert(ellipse2.isEdge() and ellipse2.edge().isEllipse())
-# TODO [limitation]: projection of an ellipse to non-parallel plane is forbiden (OCCT issue #31016)
-assert(Sketch_2.feature().error() != "")
-
assert(model.checkPythonDump())
--- /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
+#
+
+"""
+ Test projection without the reference to the source geometry.
+"""
+
+import unittest
+
+from salome.shaper import model
+from GeomAPI import *
+from ModelAPI import *
+
+__updated__ = "2020-07-07"
+
+CURVES = []
+PLANE = None
+
+class TestProjectionWithoutRef(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(partSet, model.selection("FACE", PLANE.name()))
+ self.myDOF = 0
+ self.myNbPoints = 1
+ self.myNbLines = 1
+ self.myNbCircles = 0
+ self.myNbArcs = 0
+ self.myNbEllipses = 2
+ self.myNbEllipticArcs = 2
+ self.myNbSplines = 1
+ self.myNbPeriodicSplines = 1
+ self.myNbProjections = 0
+ self.myNbFixedConstraints = 0
+ self.myNbEdgesInSketch = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+ model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", self.myNbEllipticArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchProjection", self.myNbProjections)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintRigid", self.myNbFixedConstraints)
+ nbEdges = 0
+ exp = GeomAPI_ShapeExplorer(self.mySketch.defaultResult().shape(), GeomAPI_Shape.EDGE)
+ while exp.more(): nbEdges += 1; exp.next()
+ self.assertEqual(self.myNbEdgesInSketch, nbEdges)
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+ def test_projection_withref_includeintoresult(self):
+ """ Test 1. Projection with the reference to the original shapes. Projected curves are composed into the sketch result.
+ """
+ for c in CURVES:
+ self.mySketch.addProjection(c, keepResult = True)
+ self.myNbProjections = len(CURVES)
+ self.myNbEdgesInSketch = len(CURVES) - 1
+
+ def test_projection_withref_notincludeintoresult(self):
+ """ Test 2. Projection with the reference to the original shapes. Projected curves are NOT included into the sketch result.
+ """
+ for c in CURVES:
+ self.mySketch.addProjection(c, keepResult = False)
+ self.myNbProjections = len(CURVES)
+
+ def test_projection_withoutref_noconstraints(self):
+ """ Test 3. Projection without the reference to the original shapes. No additional constraints applied.
+ """
+ for c in CURVES:
+ self.mySketch.addProjection(c, keepRefToOriginal = False)
+ model.do()
+ self.myNbEdgesInSketch = len(CURVES) - 1
+ self.myDOF += 2 + 4 + 5 + 7 + 5 + 7 + 6 * 2 + 6 * 2
+
+ def test_projection_withoutref_fixed(self):
+ """ Test 4. Projection without the reference to the original shapes. Additionally, Fixed constraints applied.
+ """
+ model.end()
+ # use the low-level API to access the necessary attributes
+ session = ModelAPI_Session.get()
+ for c in CURVES:
+ session.startOperation()
+ proj = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchProjection")
+ proj.boolean("IncludeToResult").setValue(False)
+ proj.string("keep_reference").setValue("False")
+ proj.boolean("make_fixed").setValue(True)
+ c.fillAttribute(proj.selection("ExternalFeature"))
+ session.finishOperation()
+ self.myNbEdgesInSketch = len(CURVES) - 1
+ self.myNbFixedConstraints = len(CURVES)
+ model.begin()
+
+
+if __name__ == "__main__":
+ model.begin()
+ partSet = model.moduleDocument()
+ Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+ SketchPoint_1 = Sketch_1.addPoint(35, -40)
+ CURVES.append(model.selection("VERTEX", Sketch_1.name() + "/" + SketchPoint_1.name()))
+ SketchLine_1 = Sketch_1.addLine(20, -15, 40, 15)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchLine_1.name()))
+ SketchCircle_1 = Sketch_1.addCircle(65, -30, 20)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchCircle_1.defaultResult().data().name()))
+ SketchArc_1 = Sketch_1.addArc(60, 15, 80, 0, 50, 33, False)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchArc_1.defaultResult().data().name()))
+ SketchEllipse_1 = Sketch_1.addEllipse(25, 30, 40, 30, 10)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchEllipse_1.defaultResult().data().name()))
+ SketchEllipticArc_1 = Sketch_1.addEllipticArc(40, 70, 55, 70, 45, 50, 25, 56, False)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchEllipticArc_1.defaultResult().data().name()))
+ SketchBSpline_1_poles = [(95, -50), (130, -10), (100, 10), (125, 45), (90, 70), (55, 45)]
+ SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchBSpline_1.name()))
+ SketchBSplinePeriodic_1_poles = [(95, 80), (135, 90), (145, 55), (130, 30), (125, 70), (105, 60)]
+ SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, periodic = True)
+ CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchBSplinePeriodic_1.name()))
+ model.do()
+ PLANE = model.addPlane(partSet, model.selection("FACE", "XOY"), model.selection("EDGE", "OY"), 45)
+ model.end()
+
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
mirrorFeature.rst
translationFeature.rst
rotationFeature.rst
+ offsetFeature.rst
sketchDrawer.rst
sketchCopy.rst
--- /dev/null
+
+ .. _tui_create_interpolation:
+
+Create interpolation curve
+==========================
+
+.. literalinclude:: examples/interpolation.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/interpolation.py>`
+
+
+ .. _tui_create_approximation:
+
+Create approximation curve
+==========================
+
+.. literalinclude:: examples/approximation.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/approximation.py>`
--- /dev/null
+
+ .. _tui_create_offset:
+
+Create Offset
+=============
+
+.. literalinclude:: examples/offset.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/offset.py>`
--- /dev/null
+.. |curvefitting.icon| image:: images/curvefitting.png
+
+Curve Fitting
+=============
+
+The Curve Fitting is a tool to create a curve by a set of given points.
+
+To start this operation:
+
+#. select *Sketch - > Curve fitting* item in the Main Menu or
+#. click |curvefitting.icon| **Curve fitting** button in the Sketch toolbar:
+
+There are 2 algorithms for the curve creation:
+
+- **Interpolation** - the curve passes exactly through the selected points;
+- **Approximation** - curve passes near the selected points to some extent.
+
+Both algorithms have additional options:
+
+- **Periodic** - forces the created curve to be smooth periodic curve;
+- **Closed** - produces closed, but non-periodic curve. As a result, it has the same start and end points, but it may be connected non-smoothly there;
+- **Create control polygon** - if the fitting curve is a B-spline curve, this option will create it's control polygon.
+
+
+Interpolation
+"""""""""""""
+
+.. image:: images/curvefitting_panel_interpolation.png
+ :align: center
+
+Select the list of points to create a curve. The curve will pass directly through these points in the given order.
+
+Clicking the **Reorder points** button will change the order of selected points to minimize the distances between the neighbors.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addInterpolation(points, periodic = False, closed = False)
+
+ :param list: points for the curve.
+ :param boolean: flag to make the curve periodic.
+ :param boolean: flag to make the curve closed but not periodic.
+ :return: Created B-spline curve.
+
+Result
+""""""
+
+The created B-spline curve appears in the view.
+
+.. image:: images/curvefitting_interpolation_res.png
+ :align: center
+
+.. centered::
+ Interpolation curve (non-closed, periodic and closed)
+
+**See Also** a sample TUI Script of :ref:`tui_create_interpolation` operation.
+
+
+Approximation
+"""""""""""""
+
+.. image:: images/curvefitting_panel_approximation.png
+ :align: center
+
+Select the list of points to create a curve and set the **Precision** value. The curve will pass not far than the precision of these points.
+
+Clicking the **Reorder points** button will change the order of selected points to minimize the distances between the neighbors.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addApproximation(points, precision = 0.001, periodic = False, closed = False)
+
+ :param list: points for the curve.
+ :param double: how close the curve should pass according to the points.
+ :param boolean: flag to make the curve periodic.
+ :param boolean: flag to make the curve closed but not periodic.
+ :return: Created B-spline curve.
+
+Result
+""""""
+
+The created B-spline curve appears in the view.
+
+.. image:: images/curvefitting_approximation_res.png
+ :align: center
+
+.. centered::
+ Approximated curve (non-closed, periodic and closed)
+
+**See Also** a sample TUI Script of :ref:`tui_create_approximation` operation.
--- /dev/null
+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 SketchPoints
+SketchPoint_1 = Sketch_1.addPoint(-70.28350515463917, 1.388316151202744)
+SketchPoint_2 = Sketch_1.addPoint(-26.89862542955327, 51.7147766323024)
+SketchPoint_3 = Sketch_1.addPoint(40.08762886597938, 32.27835051546391)
+SketchPoint_4 = Sketch_1.addPoint(66.46563573883162, -29.8487972508591)
+
+### Create approximating curve
+ApproximationPoints = [SketchPoint_1.coordinates(),
+ SketchPoint_2.coordinates(),
+ SketchPoint_3.coordinates(),
+ SketchPoint_4.coordinates()]
+SketchBSpline_1 = Sketch_1.addApproximation(ApproximationPoints, precision = 30)
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_1.startPoint())
+Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchBSpline_1.endPoint())
+
+### Create periodic approximating curve
+SketchBSpline_2 = Sketch_1.addApproximation(ApproximationPoints, precision = 30, periodic = True)
+
+### Create closed approximating curve
+SketchBSpline_3 = Sketch_1.addApproximation(ApproximationPoints, precision = 30, closed = True)
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_3.startPoint())
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_3.endPoint())
+
+model.do()
+
+model.end()
--- /dev/null
+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 SketchPoints
+SketchPoint_1 = Sketch_1.addPoint(-70.28350515463917, 1.388316151202744)
+SketchPoint_2 = Sketch_1.addPoint(-26.89862542955327, 51.7147766323024)
+SketchPoint_3 = Sketch_1.addPoint(40.08762886597938, 32.27835051546391)
+SketchPoint_4 = Sketch_1.addPoint(66.46563573883162, -29.8487972508591)
+
+### Create interpolation curve
+InterpolationPoints = [SketchPoint_1.coordinates(),
+ SketchPoint_2.coordinates(),
+ SketchPoint_3.coordinates(),
+ SketchPoint_4.coordinates()]
+SketchBSpline_1 = Sketch_1.addInterpolation(InterpolationPoints)
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_1.startPoint())
+Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchBSpline_1.result())
+Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchBSpline_1.result())
+Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchBSpline_1.endPoint())
+
+### Create periodic interpolation curve
+SketchBSpline_2 = Sketch_1.addInterpolation(InterpolationPoints, periodic = True)
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_2.result())
+Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchBSpline_2.result())
+Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchBSpline_2.result())
+Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchBSpline_2.result())
+
+### Create closed interpolation curve
+SketchBSpline_3 = Sketch_1.addInterpolation(InterpolationPoints, closed = True)
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_3.startPoint())
+Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchBSpline_3.result())
+Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchBSpline_3.result())
+Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchBSpline_3.result())
+Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchBSpline_3.endPoint())
+
+model.do()
+
+model.end()
--- /dev/null
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+SketchLine_1 = Sketch_1.addLine(0, 0, 0, 100)
+SketchLine_2 = Sketch_1.addLine(0, 100, 100, 100)
+SketchLine_3 = Sketch_1.addLine(100, 100, 100, 0)
+SketchLine_4 = Sketch_1.addLine(0, 0, 100, 0)
+
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.endPoint())
+Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+
+SketchOffset_1_objects = [SketchLine_1.result(), SketchLine_2.result(), SketchLine_3.result(), SketchLine_4.result()]
+SketchOffset_1 = Sketch_1.addOffset(SketchOffset_1_objects, 10.0, False)
+
+model.do()
+model.end()
--- /dev/null
+.. |offset.icon| image:: images/offset.png
+
+Offset
+======
+
+Offset operation offsets sketch entities on a given distance.
+Gaps are filled by arcs.
+Offset is performed outside a closed contour or to the right
+of an open one, unless the **Reversed** flag is not set.
+
+To create an Offset in the active Sketch:
+
+#. select in the Main Menu *Sketch - > Offset* item or
+#. click |offset.icon| **Offset** button in Sketch toolbar:
+
+Property panel:
+
+.. image:: images/Offset_panel.png
+ :align: center
+
+.. centered::
+ Offset
+
+Input fields:
+
+- **Edges** is the list of segments (lines, circles, arcs) selected in the view.
+- **Offset value** is the offset distance.
+- **Reversed** sets the reversed offset side (inside a closed contour or to the left of an open one).
+
+Button:
+
+- **Select wire** button adds edges connected by coincident boundary constraint
+ and composing a wire with the already selected segments.
+ Not more than 2 edges can be connected with one coincident point.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addOffset(Objects, Distance, isReversed)
+
+ :param list: A list of objects.
+ :param real: An offset distance.
+ :param boolean: Reversed flag.
+ :return: Result object.
+
+Result
+""""""
+
+Created Offset appears in the view.
+
+| The original and the offset objects are marked with a special sign.
+| Offset object is drawn with a thinner line.
+
+.. image:: images/Offset_res.png
+ :align: center
+
+.. centered::
+ Offset created
+
+**See Also** a sample TUI Script of :ref:`tui_create_offset` operation.
SketchBSpline SketchMacroBSpline SketchMacroBSplinePeriodic SketchBSplinePeriodic
SketchRectangle
SketchProjection
+ SketchCurveFitting
SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
SketchConstraintParallel SketchConstraintPerpendicular
SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical
SketchConstraintCoincidence SketchConstraintCoincidenceInternal
SketchConstraintMirror SketchConstraintAngle
SketchMultiRotation SketchMultiTranslation
+ SketchOffset
SketchConstraintCollinear SketchConstraintMiddle"
when_nested="accept abort"
title="Sketch"
obligatory="0"
change_visual_attributes="true"/>
</feature>
+
+ <!-- Curve fitting -->
+ <feature id="SketchCurveFitting"
+ title="Curve fitting"
+ tooltip="Create curve passing through the points"
+ icon="icons/Sketch/curvefitting.png"
+ helpfile="curveFittingFeature.html">
+ <sketch_multi_selector id="points"
+ label="Points"
+ tooltip="Select points for curve fitting"
+ shape_types="Vertices"
+ use_external="true"
+ greed="true">
+ </sketch_multi_selector>
+ <switch id="type">
+ <case id="interpolation_type" title="Interpolation"/>
+ <case id="approximation_type" title="Approximation">
+ <doublevalue id="precision"
+ label="Precision"
+ tooltip="Maximal distance from selected points to the curve"
+ default="0.001"
+ min="1.e-7"
+ use_reset="false">
+ <validator id="GeomValidators_Positive" parameters="0"/>
+ </doublevalue>
+ </case>
+ </switch>
+ <boolvalue id="need_control_poly"
+ label="Create control polygon"
+ default="true"
+ tooltip="Specify if the control polygon should be created"/>
+ <optionalbox id="periodic"
+ title="Periodic"
+ tooltip="Make curve periodic"
+ default="false"
+ has_frame="false"
+ enable_on_check="false"
+ show_title="true">
+ <boolvalue id="closed"
+ label="Closed"
+ default="false"
+ tooltip="Make curve closed, but not periodic"
+ obligatory="1"/>
+ </optionalbox>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ <validator id="SketchPlugin_CurveFittingValidator"/>
+ <action id="reorder_points"
+ label="Reorder points"
+ tooltip="Sort selected points to minimize the distance heighbors"/>
+ </feature>
</group>
<group id="Segmentation">
use_sketch_plane="false">
<validator id="SketchPlugin_ProjectionValidator"/>
</sketch_shape_selector>
- <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"
- change_visual_attributes="true"/>
+ <radiobox id="keep_reference"
+ align_subs="vertical">
+ <radio id="true"
+ title="Keep reference to the original shape"
+ tooltip="The reference to the original curve is stored. So it can be changed later.">
+ <boolvalue id="IncludeToResult"
+ label="Include into the sketch result"
+ default="true"
+ tooltip="Include projected feature into the sketch result"
+ change_visual_attributes="true"/>
+ </radio>
+ <radio id="false"
+ title="Break connection with the original shape"
+ tooltip="A sketch entity will be created without connection to the selected shape.">
+ <boolvalue id="make_fixed"
+ label="Make projected curve fixed"
+ default="true"
+ tooltip="Assign the Fixed constraint to the result of projection"/>
+ </radio>
+ </radiobox>
<validator id="PartSet_ProjectionSelection"/>
</feature>
</integervalue>
<validator id="PartSet_MultyTranslationSelection" />
</feature>
+
+ <!-- Offset curve -->
+ <feature id="SketchOffset"
+ title="Offset"
+ tooltip="Offset a curve to a distance"
+ icon="icons/Sketch/offset.png"
+ helpfile="offsetFeature.html">
+ <sketch_multi_selector id="segments"
+ label="Edges"
+ tooltip="Select edges to offset"
+ shape_types="Edges"
+ use_external="true"
+ greed="true">
+ <validator id="SketchPlugin_CopyValidator" />
+ </sketch_multi_selector>
+ <doublevalue id="offset_value"
+ label="Offset value"
+ tooltip="Offset value"
+ default="1" min="0.000001"
+ use_reset="false">
+ <validator id="GeomValidators_Positive" parameters="1e-07"/>
+ </doublevalue>
+ <boolvalue id="reversed"
+ label="Reversed"
+ tooltip="Reverse the offset"
+ default="false"
+ obligatory="0"/>
+ <action id="add_wire"
+ label="Select wire"
+ tooltip="Add the list of segments composing a wire with the selected items through the coincidence by boundary points"/>
+ </feature>
</group>
<group id="Dimensional constraints">
SketchSolver_ConstraintMultiRotation.h
SketchSolver_ConstraintMultiTranslation.h
SketchSolver_ConstraintMovement.h
+ SketchSolver_ConstraintOffset.h
)
SET(SKETCHSOLVER_SOURCES
SketchSolver_ConstraintMultiRotation.cpp
SketchSolver_ConstraintMultiTranslation.cpp
SketchSolver_ConstraintMovement.cpp
+ SketchSolver_ConstraintOffset.cpp
)
SET(SKETCHSOLVER_LIBRARIES
#include <GeomAPI_BSpline2d.h>
#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
#include <cmath>
namespace GCS
{
-DeriVector2 BSplineImpl::Value(double u, double du, double* derivparam)
-{
- if (!isCacheValid())
- rebuildCache();
-
- std::shared_ptr<GeomAPI_Pnt2d> aValue;
- std::shared_ptr<GeomAPI_XY> aDeriv;
- myCurve->D1(u, aValue, aDeriv);
-
- // calculate the derivative on solver's parameter
- std::shared_ptr<GeomAPI_Pnt2d> aValueDeriv(new GeomAPI_Pnt2d(0.0, 0.0));
- bool hasParam = false;
- std::list<GeomPnt2dPtr> aPolesDeriv;
- for (GCS::VEC_P::iterator anIt = poles.begin(); anIt != poles.end(); ++anIt) {
- double x = 0.0, y = 0.0;
- if (anIt->x == derivparam) {
- x = 1.0;
- hasParam = true;
- }
- else if (anIt->y == derivparam) {
- y = 1.0;
- hasParam = true;
+ static void periodicNormalization(double& theParam, double thePeriodStart, double thePeriodEnd)
+ {
+ double aPeriod = thePeriodEnd - thePeriodStart;
+ if (aPeriod > tolerance) {
+ theParam = std::max(thePeriodStart,
+ theParam + aPeriod * std::ceil((thePeriodStart - theParam) / aPeriod));
}
- aPolesDeriv.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(x, y)));
- }
- if (hasParam) {
- // use non-periodic curve, because the most of B-spline coefficients are 0,
- // thus, it is not necessary to keep original knots and multiplicities to get correct value
- std::shared_ptr<GeomAPI_BSpline2d> aCurveDeriv(
- new GeomAPI_BSpline2d(degree, aPolesDeriv, myCachedWeights));
- aCurveDeriv->D0(u, aValueDeriv);
}
- return DeriVector2(aValue->x(), aValue->y(),
- aValueDeriv->x() + aDeriv->x() * du, aValueDeriv->y() + aDeriv->y() * du);
+
+DeriVector2 BSplineImpl::Value(double u, double du, double* derivparam)
+{
+ DeriVector2 value, deriv;
+ d1(u, derivparam, value, deriv);
+ return value.sum(GCS::DeriVector2(0., 0., deriv.x, deriv.y).mult(du));
}
DeriVector2 BSplineImpl::CalculateNormal(Point &p, double* derivparam)
{
- if (!isCacheValid())
- rebuildCache();
-
double u = 0.0;
- if (!myCurve->parameter(GeomPnt2dPtr(new GeomAPI_Pnt2d(*p.x, *p.y)), 1e100, u))
+ if (!parameter(p, u))
return DeriVector2();
- std::shared_ptr<GeomAPI_Pnt2d> aValue;
- std::shared_ptr<GeomAPI_XY> aDeriv;
- myCurve->D1(u, aValue, aDeriv);
-
- DeriVector2 norm(aDeriv->x(), aDeriv->y(), 0.0, 0.0);
- return norm.rotate90ccw();
+ DeriVector2 value, deriv;
+ d1(u, derivparam, value, deriv);
+ return deriv.rotate90ccw();
}
BSplineImpl* BSplineImpl::Copy()
return new BSplineImpl(*this);
}
+void BSplineImpl::d1(double theU,
+ double* theDerivParam,
+ GCS::DeriVector2& theValue,
+ GCS::DeriVector2& theDerivative)
+{
+ int aSpan = spanIndex(theU);
+ std::vector<GCS::DeriVector2> aPoles;
+ std::vector<double> aWeights;
+ spanPolesAndWeights(aSpan, theDerivParam, aPoles, aWeights);
+ performDeBoor(theU, aSpan, aPoles, aWeights, theValue, theDerivative);
+}
-bool BSplineImpl::isCacheValid() const
+int BSplineImpl::spanIndex(double& u)
{
- // curve has to be initialized
- bool isValid = myCurve.get() && !myCurve->isNull();
-
- static const double THE_TOLERANCE = 1.e-7;
- // compare poles
- isValid = isValid && poles.size() == myCachedPoles.size();
- std::list<GeomPnt2dPtr>::const_iterator aCachePIt = myCachedPoles.begin();
- GCS::VEC_P::const_iterator aPolesIt = poles.begin();
- for (; isValid && aPolesIt != poles.end(); ++aPolesIt, ++aCachePIt) {
- isValid = isValid && fabs((*aCachePIt)->x() - *aPolesIt->x) < THE_TOLERANCE
- && fabs((*aCachePIt)->y() - *aPolesIt->y) < THE_TOLERANCE;
+ if (myFlatKnots.empty()) {
+ // fill flat knots indices
+ for (int i = 0; i < (int)mult.size(); ++i)
+ myFlatKnots.resize(myFlatKnots.size() + mult[i], *knots[i]);
+ if (periodic) {
+ // additional knots at the beginning and the end to complete periodity
+ int anExtraBegin = degree + 1 - mult.front();
+ int anExtraEnd = degree + 1 - mult.back();
+ double aPeriod = *knots.back() - *knots.front();
+ VEC_D aNewFlatKnots;
+ aNewFlatKnots.reserve(myFlatKnots.size() + (size_t)(anExtraBegin + anExtraEnd));
+ auto it = myFlatKnots.end() - mult.back() - anExtraBegin;
+ while (anExtraBegin > 0) {
+ aNewFlatKnots.push_back(*(it++) - aPeriod);
+ --anExtraBegin;
+ }
+ aNewFlatKnots.insert(aNewFlatKnots.end(), myFlatKnots.begin(), myFlatKnots.end());
+ it = myFlatKnots.begin() + mult.front();
+ while (anExtraEnd > 0) {
+ aNewFlatKnots.push_back(*(it++) + aPeriod);
+ --anExtraEnd;
+ }
+ myFlatKnots = aNewFlatKnots;
+ }
}
- // compare weights
- isValid = isValid && weights.size() == myCachedWeights.size();
- std::list<double>::const_iterator aCacheWIt = myCachedWeights.begin();
- GCS::VEC_pD::const_iterator aWeightsIt = weights.begin();
- for (; isValid && aWeightsIt != weights.end(); ++aWeightsIt, ++aCacheWIt)
- isValid = isValid && fabs(*aCacheWIt - **aWeightsIt) < THE_TOLERANCE;
+ if (periodic)
+ periodicNormalization(u, *knots.front(), *knots.back());
+
+ int anIndex = 0;
+ for (int i = 1; i < (int)knots.size() - 1; ++i) {
+ if (u <= *knots[i])
+ break;
+ anIndex += mult[i];
+ }
+ return anIndex;
+}
- return isValid;
+void BSplineImpl::spanPolesAndWeights(int theSpanIndex,
+ double* theDerivParam,
+ std::vector<GCS::DeriVector2>& thePoles,
+ std::vector<double>& theWeights) const
+{
+ thePoles.reserve(degree + 1);
+ theWeights.reserve(degree + 1);
+ for (int i = theSpanIndex; i <= theSpanIndex + degree; ++i) {
+ // optimization: weighted pole
+ int idx = i % (int)poles.size();
+ thePoles.push_back(GCS::DeriVector2(poles[idx], theDerivParam).mult(*weights[idx]));
+ theWeights.push_back(*weights[idx]);
+ }
+}
+
+void BSplineImpl::performDeBoor(double theU,
+ int theSpanIndex,
+ std::vector<GCS::DeriVector2>& thePoles,
+ std::vector<double>& theWeights,
+ GCS::DeriVector2& theValue,
+ GCS::DeriVector2& theDerivative) const
+{
+ std::vector<GCS::DeriVector2> aPDeriv(thePoles.size(), DeriVector2());
+ std::vector<double> aWDeriv(theWeights.size(), 0.0);
+ for (int i = 0; i < degree; ++i) {
+ for (int j = degree; j > i; --j) {
+ double denom = (myFlatKnots[theSpanIndex + j + degree - i] -
+ myFlatKnots[theSpanIndex + j]);
+ double a = (theU - myFlatKnots[theSpanIndex + j]) / denom;
+ aPDeriv[j] = aPDeriv[j].linCombi(a, aPDeriv[j - 1], 1.0 - a).sum(
+ thePoles[j].subtr(thePoles[j - 1]).mult(1.0 / denom));
+ aWDeriv[j] = aWDeriv[j] * a + aWDeriv[j - 1] * (1.0 - a)
+ + (theWeights[j] - theWeights[j - 1]) / denom;
+ thePoles[j] = thePoles[j].linCombi(a, thePoles[j - 1], 1.0 - a);
+ theWeights[j] = theWeights[j] * a + theWeights[j - 1] * (1.0 - a);
+ }
+ }
+ double w = 1 / theWeights[degree];
+ theValue = thePoles[degree].mult(w);
+ theDerivative = aPDeriv[degree].subtr(theValue.mult(aWDeriv[degree])).mult(w);
}
-void BSplineImpl::rebuildCache()
+bool BSplineImpl::parameter(const Point& thePoint, double& theParam) const
{
- myCachedPoles.clear();
- myCachedWeights.clear();
- myCachedKnots.clear();
- myCachedMultiplicities.clear();
-
- for (GCS::VEC_P::iterator anIt = poles.begin(); anIt != poles.end(); ++anIt)
- myCachedPoles.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(*anIt->x, *anIt->y)));
- for (GCS::VEC_pD::iterator anIt = weights.begin(); anIt != weights.end(); ++anIt)
- myCachedWeights.push_back(**anIt);
- for (GCS::VEC_pD::iterator anIt = knots.begin(); anIt != knots.end(); ++anIt)
- myCachedKnots.push_back(**anIt);
- myCachedMultiplicities.assign(mult.begin(), mult.end());
-
- myCurve.reset(new GeomAPI_BSpline2d(degree, myCachedPoles, myCachedWeights,
- myCachedKnots, myCachedMultiplicities, periodic));
+ std::list<GeomPnt2dPtr> aPoles;
+ std::list<double> aWeights;
+ std::list<double> aKnots;
+ std::list<int> aMults;
+
+ for (GCS::VEC_P::const_iterator anIt = poles.begin(); anIt != poles.end(); ++anIt)
+ aPoles.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(*anIt->x, *anIt->y)));
+ for (GCS::VEC_pD::const_iterator anIt = weights.begin(); anIt != weights.end(); ++anIt)
+ aWeights.push_back(**anIt);
+ for (GCS::VEC_pD::const_iterator anIt = knots.begin(); anIt != knots.end(); ++anIt)
+ aKnots.push_back(**anIt);
+ aMults.assign(mult.begin(), mult.end());
+
+ std::shared_ptr<GeomAPI_BSpline2d> aCurve(
+ new GeomAPI_BSpline2d(degree, aPoles, aWeights, aKnots, aMults, periodic));
+
+ GeomPnt2dPtr aPoint(new GeomAPI_Pnt2d(*thePoint.x, *thePoint.y));
+ return aCurve->parameter(aPoint, 1e100, theParam);
}
} // namespace GCS
#include <PlaneGCSSolver_Defs.h>
-#include <list>
-#include <memory>
-
-class GeomAPI_BSpline2d;
-class GeomAPI_Pnt2d;
-
namespace GCS {
/// \brife SHAPER's implementation of B-spline curves in PlaneGCS solver
class BSplineImpl : public BSpline
virtual BSplineImpl* Copy();
private:
- /// Verify the cached curve satisfies to the parameters
- bool isCacheValid() const;
- /// Poles or weights are changed, cache curve has to be rebuilt
- void rebuildCache();
+ /// Return the index of start knot for the given parameter.
+ /// Parameter is updated accordingly, if the B-spline curve is periodic
+ /// and the parameter is out of period.
+ int spanIndex(double& u);
+
+ /// Collect the list of poles and their weights affecting the given span
+ void spanPolesAndWeights(int theSpanIndex,
+ double* theDerivParam,
+ std::vector<GCS::DeriVector2>& thePoles,
+ std::vector<double>& theWeights) const;
+
+ /// Execute De Boor algorithm to calculate B-spline curve's value
+ void performDeBoor(double theU, int theSpanIndex,
+ std::vector<GCS::DeriVector2>& thePoles, std::vector<double>& theWeights,
+ GCS::DeriVector2& theValue, GCS::DeriVector2& theDerivative) const;
+
+ /// Calculate the value and the first derivative for the given parameter on B-spline
+ void d1(double theU, double* theDerivParam,
+ GCS::DeriVector2& theValue, GCS::DeriVector2& theDerivative);
+
+ /// Find the parameter on B-spline corresponding to the given point
+ /// \return \c false if it is unable to calculate the parameter
+ bool parameter(const Point& thePoint, double& theParam) const;
private:
- std::shared_ptr<GeomAPI_BSpline2d> myCurve; /// cached B-spline curve
- std::list<std::shared_ptr<GeomAPI_Pnt2d> > myCachedPoles; /// cached B-spline poles
- std::list<double> myCachedWeights; /// cached B-spline weights
- std::list<double> myCachedKnots; /// cached B-spline knots
- std::list<int> myCachedMultiplicities; /// cached B-spline multiplicities
+ VEC_D myFlatKnots; /// indices of knots duplicated by multiplicity
};
}
for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
aRefIt != aRefs.end(); ++aRefIt) {
FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
- if (anOwner && anOwner->getKind() == theFeatureKind)
+ if (anOwner && !anOwner->isMacro() && anOwner->getKind() == theFeatureKind)
return true;
}
return false;
#include <SketchSolver_ConstraintTangent.h>
#include <SketchSolver_ConstraintMultiRotation.h>
#include <SketchSolver_ConstraintMultiTranslation.h>
+#include <SketchSolver_ConstraintOffset.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
+#include <SketchPlugin_Offset.h>
#include <SketchPlugin_Point.h>
#include <GeomAPI_BSpline2d.h>
return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_Offset::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintOffset(theConstraint));
}
// All other types of constraints
return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint));
--- /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 <SketchSolver_ConstraintOffset.h>
+
+
+void SketchSolver_ConstraintOffset::getAttributes(
+ EntityWrapperPtr&,
+ std::vector<EntityWrapperPtr>&)
+{
+}
+
+void SketchSolver_ConstraintOffset::process()
+{
+ cleanErrorMsg();
+}
+
+
+void SketchSolver_ConstraintOffset::update()
+{
+ cleanErrorMsg();
+ remove();
+ process();
+}
--- /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 SketchSolver_ConstraintOffset_H_
+#define SketchSolver_ConstraintOffset_H_
+
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintOffset
+ * \ingroup Plugins
+ * \brief Convert offset to the solver's data model
+ */
+class SketchSolver_ConstraintOffset : public SketchSolver_Constraint
+{
+public:
+ /// Constructor based on SketchPlugin constraint
+ SketchSolver_ConstraintOffset(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ /// \brief Update constraint
+ virtual void update();
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of entities of mirror constraint
+ virtual void getAttributes(EntityWrapperPtr&, std::vector<EntityWrapperPtr>&);
+};
+
+#endif
SketcherPrs_Mirror.h
SketcherPrs_Transformation.h
SketcherPrs_Angle.h
+ SketcherPrs_Offset.h
)
SET(PROJECT_SOURCES
SketcherPrs_Mirror.cpp
SketcherPrs_Transformation.cpp
SketcherPrs_Angle.cpp
+ SketcherPrs_Offset.cpp
)
SET(PROJECT_LIBRARIES
icons/mirror.png
icons/rotate.png
icons/translate.png
+ icons/offset.png
)
ADD_DEFINITIONS(-DSKETCHERPRS_EXPORTS ${OpenCASCADE_DEFINITIONS} -D_CRT_SECURE_NO_WARNINGS)
#include "SketcherPrs_Mirror.h"
#include "SketcherPrs_Transformation.h"
#include "SketcherPrs_Angle.h"
+#include "SketcherPrs_Offset.h"
// Macros for constraint presentation definition
#define CONSTRAINT_PRS_IMPL(NAME, CLASS) \
CONSTRAINT_PRS_IMPL(lengthDimensionConstraint, SketcherPrs_LengthDimension);
CONSTRAINT_PRS_IMPL(angleConstraint, SketcherPrs_Angle);
CONSTRAINT_PRS_IMPL(radiusConstraint, SketcherPrs_Radius);
+CONSTRAINT_PRS_IMPL(offsetObject, SketcherPrs_Offset);
// Non-standard constraints definition
AISObjectPtr SketcherPrs_Factory::horisontalConstraint(ModelAPI_Feature* theConstraint,
/// \param thePlane the current sketch plane
/// \param thePrevious the previous presentation
GET_CONSTRAINT_PRS(radiusConstraint)
+
+ /// Creates radius dimension presentation
+ /// \param theConstraint the constraint
+ /// \param thePlane the current sketch plane
+ /// \param thePrevious the previous presentation
+ GET_CONSTRAINT_PRS(offsetObject)
};
#endif
--- /dev/null
+// Copyright (C) 2014-2019 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 "SketcherPrs_Offset.h"
+#include "SketcherPrs_Tools.h"
+#include "SketcherPrs_PositionMgr.h"
+
+#include <SketchPlugin_Offset.h>
+
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <Graphic3d_AspectLine3d.hxx>
+#include <Prs3d_Root.hxx>
+
+
+IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Offset, SketcherPrs_SymbolPrs);
+
+static Handle(Image_AlienPixMap) MyPixMap;
+
+SketcherPrs_Offset::SketcherPrs_Offset(ModelAPI_Feature* theConstraint,
+ SketchPlugin_Sketch* theSketcher)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher)
+{
+}
+
+bool SketcherPrs_Offset::IsReadyToDisplay(ModelAPI_Feature* theConstraint,
+ const std::shared_ptr<GeomAPI_Ax3>&/* thePlane*/)
+{
+ bool aReadyToDisplay = false;
+
+ AttributeDoublePtr aValueAttr = theConstraint->real(SketchPlugin_Offset::VALUE_ID());
+ if (aValueAttr->isInitialized()) {
+ AttributeRefListPtr aSelectedEdges = theConstraint->reflist(SketchPlugin_Offset::ENTITY_A());
+ aReadyToDisplay = (aSelectedEdges->list().size() > 0);
+ if (aReadyToDisplay) {
+ AttributeRefListPtr aOffcetEdges = theConstraint->reflist(SketchPlugin_Offset::ENTITY_B());
+ aReadyToDisplay = (aOffcetEdges->list().size() > 0);
+ }
+ }
+ return aReadyToDisplay;
+}
+
+bool SketcherPrs_Offset::updateIfReadyToDisplay(double theStep, bool withColor) const
+{
+ if (!IsReadyToDisplay(myConstraint, plane()))
+ return false;
+ if (!plane())
+ return false;
+
+ // Set points of the presentation
+ SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
+
+ AttributeRefListPtr aSelectedEdges = myConstraint->reflist(SketchPlugin_Offset::ENTITY_A());
+ int aNb = aSelectedEdges->size();
+
+ AttributeRefListPtr aOffcetEdges = myConstraint->reflist(SketchPlugin_Offset::ENTITY_B());
+ int aOffNb = aOffcetEdges->size();
+
+ myPntArray = new Graphic3d_ArrayOfPoints(aNb + aOffNb, withColor);
+ int i;
+ ObjectPtr aObj;
+ gp_Pnt aP1;
+ // get position for each source object
+ for (i = 0; i < aNb; i++) {
+ aObj = aSelectedEdges->object(i);
+ if (SketcherPrs_Tools::getShape(aObj).get() == NULL)
+ continue;
+ aP1 = aMgr->getPosition(aObj, this, theStep);
+ myPntArray->SetVertice(i + 1, aP1);
+ }
+ for (i = aNb; i < aNb + aOffNb; i++) {
+ aObj = aOffcetEdges->object(i - aNb);
+ if (SketcherPrs_Tools::getShape(aObj).get() == NULL)
+ continue;
+ aP1 = aMgr->getPosition(aObj, this, theStep);
+ myPntArray->SetVertice(i + 1, aP1);
+ }
+ return true;
+}
+
+void SketcherPrs_Offset::drawLines(const Handle(Prs3d_Presentation)& thePrs,
+ Quantity_Color theColor) const
+{
+ AttributeRefListPtr aSelectedEdges = myConstraint->reflist(SketchPlugin_Offset::ENTITY_A());
+ if (aSelectedEdges.get() == NULL)
+ return;
+ AttributeRefListPtr aOffcetEdges = myConstraint->reflist(SketchPlugin_Offset::ENTITY_B());
+ if (aOffcetEdges.get() == NULL)
+ return;
+
+ if (aSelectedEdges->size() == 0)
+ return;
+
+ if (aOffcetEdges->size() == 0)
+ return;
+
+ // Draw source objects
+ drawListOfShapes(aSelectedEdges, thePrs, theColor);
+ // Draw offcet objects
+ drawListOfShapes(aOffcetEdges, thePrs, theColor);
+}
--- /dev/null
+// Copyright (C) 2014-2019 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 SketcherPrs_Offset_H
+#define SketcherPrs_Offset_H
+
+#include "SketcherPrs_SymbolPrs.h"
+
+
+DEFINE_STANDARD_HANDLE(SketcherPrs_Offset, SketcherPrs_SymbolPrs)
+
+/**
+* \ingroup GUI
+* A redefinition of standard AIS Interactive Object in order to provide
+* presentation of Equal constraint
+*/
+class SketcherPrs_Offset : public SketcherPrs_SymbolPrs
+{
+public:
+ /// Constructor
+ /// \param theConstraint a constraint feature
+ /// \param theSketcher a sketcher object
+ Standard_EXPORT SketcherPrs_Offset(ModelAPI_Feature* theConstraint,
+ SketchPlugin_Sketch* theSketcher);
+ DEFINE_STANDARD_RTTIEXT(SketcherPrs_Offset, SketcherPrs_SymbolPrs)
+
+ /// Returns true if the constraint feature arguments are correcly
+ /// filled to build AIS presentation
+ /// \param theConstraint a constraint feature
+ /// \param thePlane a coordinate plane of current sketch
+ /// \return boolean result value
+ static bool IsReadyToDisplay(ModelAPI_Feature* theConstraint,
+ const std::shared_ptr<GeomAPI_Ax3>& thePlane);
+protected:
+
+ virtual const char* iconName() const { return "offset.png"; }
+
+ virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const;
+
+ /// Update myPntArray according to presentation positions
+ /// \return true in case of success
+ virtual bool updateIfReadyToDisplay(double theStep, bool withColor) const;
+};
+
+#endif
\ No newline at end of file
std::shared_ptr<GeomAPI_Shape> getShape(ObjectPtr theObject)
{
ResultConstructionPtr aRes = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theObject);
+ if (!aRes.get()) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
+ if (aFeature.get())
+ aRes = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aFeature->lastResult());
+ }
if (aRes.get() != NULL && aRes->data()->isValid()) {
/// essential check as it is called in openGl thread
return aRes->shape();
aAction = ModuleBase_Tools::createAction(QIcon(":pictures/rename_edit.png"), tr("Rename"),
aDesktop, this, SLOT(onRename()));
+ aAction->setShortcut(Qt::Key_F2);
addAction("RENAME_CMD", aAction);
aAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_to_end.png"),
/// Constructor
/// \param theParent the parent to be deleted when the parent is deleted
/// \param theOperationMgr the class to perform deletion
- XGUI_ShortCutListener(QObject* theParent, XGUI_OperationMgr* theOperationMgr)
- : QObject(theParent), myOperationMgr(theOperationMgr), myIsActive(false)
+ XGUI_ShortCutListener(XGUI_OperationMgr* theOperationMgr)
+ : QObject(theOperationMgr), myOperationMgr(theOperationMgr), myIsActive(false)
{
qApp->installEventFilter(this);
}
void setActive(const bool theIsActive) { myIsActive = theIsActive; }
/// Redefinition of virtual function to process Delete key release
- virtual bool eventFilter(QObject *theObject, QEvent *theEvent)
- {
- bool isAccepted = false;
-
- if (myIsActive) {
- // Do not process keys for modal dialogues: all keys has to be processed within the dialog
- // There is only one exception: ModuleBase_EditorDialog
- QWindow* aWnd = qApp->modalWindow();
- QString aName = "NoModal";
- if (aWnd) {
- if (!aWnd->objectName().startsWith("ModuleBase_EditorDialog"))
- aName = aWnd->objectName();
- }
- if (aName == "NoModal") {
- if (theEvent->type() == QEvent::KeyRelease) {
- QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
- if (aKeyEvent) {
- myOperationMgr->setSHIFTPressed(aKeyEvent->modifiers() & Qt::ShiftModifier);
- switch (aKeyEvent->key()) {
- case Qt::Key_Delete:
- isAccepted = myOperationMgr->onProcessDelete(theObject);
- break;
- default:
- isAccepted = myOperationMgr->onKeyReleased(theObject, aKeyEvent);
- break;
- }
+ virtual bool eventFilter(QObject *theObject, QEvent *theEvent);
+
+private:
+ XGUI_OperationMgr* myOperationMgr; /// processor for key event
+ bool myIsActive; /// boolean state whether the event filter perform own signal processing
+};
+
+bool XGUI_ShortCutListener::eventFilter(QObject *theObject, QEvent *theEvent)
+{
+ bool isAccepted = false;
+
+ if (myIsActive) {
+ // Do not process keys for modal dialogues: all keys has to be processed within the dialog
+ // There is only one exception: ModuleBase_EditorDialog
+ QWindow* aWnd = qApp->modalWindow();
+ QString aName = "NoModal";
+ if (aWnd) {
+ if (!aWnd->objectName().startsWith("ModuleBase_EditorDialog"))
+ aName = aWnd->objectName();
+ }
+ if (aName == "NoModal") {
+ if (theEvent->type() == QEvent::KeyRelease) {
+ QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
+ if (aKeyEvent) {
+ myOperationMgr->setSHIFTPressed(aKeyEvent->modifiers() & Qt::ShiftModifier);
+ switch (aKeyEvent->key()) {
+ case Qt::Key_Delete:
+ isAccepted = myOperationMgr->onProcessDelete(theObject);
+ break;
+ case Qt::Key_F2:
+ myOperationMgr->xworkshop()->objectBrowser()->onEditItem();
+ isAccepted = true;
+ break;
+ default:
+ isAccepted = myOperationMgr->onKeyReleased(theObject, aKeyEvent);
+ break;
}
}
- else if (theEvent->type() == QEvent::KeyPress) {
- if (myOperationMgr->hasOperation()) {
- QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
- myOperationMgr->setSHIFTPressed(aKeyEvent->modifiers() & Qt::ShiftModifier);
- isAccepted = myOperationMgr->onKeyPressed(theObject, aKeyEvent);
- }
+ }
+ else if (theEvent->type() == QEvent::KeyPress) {
+ if (myOperationMgr->hasOperation()) {
+ QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
+ myOperationMgr->setSHIFTPressed(aKeyEvent->modifiers() & Qt::ShiftModifier);
+ isAccepted = myOperationMgr->onKeyPressed(theObject, aKeyEvent);
}
}
}
- if (!isAccepted)
- isAccepted = QObject::eventFilter(theObject, theEvent);
- return isAccepted;
}
+ if (!isAccepted)
+ isAccepted = QObject::eventFilter(theObject, theEvent);
+ return isAccepted;
+}
+
-private:
- XGUI_OperationMgr* myOperationMgr; /// processor for key event
- bool myIsActive; /// boolean state whether the event filter perform own signal processing
-};
XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
- ModuleBase_IWorkshop* theWorkshop)
+ ModuleBase_IWorkshop* theWorkshop)
: QObject(theParent), myWorkshop(theWorkshop), myActiveMessageBox(0), mySHIFTPressed(false)
{
/// we need to install filter to the application in order to react to 'Delete' key button
/// this key can not be a short cut for a corresponded action because we need to set
/// the actions priority
- myShortCutListener = new XGUI_ShortCutListener(theParent, this);
+ myShortCutListener = new XGUI_ShortCutListener(this);
}
XGUI_OperationMgr::~XGUI_OperationMgr()
return aMessageBox;
}
+
+XGUI_Workshop* XGUI_OperationMgr::xworkshop() const
+{
+ XGUI_ModuleConnector* aConnector = (XGUI_ModuleConnector*) myWorkshop;
+ return aConnector->workshop();
+}
/// Current workshop
ModuleBase_IWorkshop* workshop() const { return myWorkshop; }
+ /// Current workshop
+ XGUI_Workshop* xworkshop() const;
+
/// Returns the current operation or NULL
/// \return the current operation
ModuleBase_Operation* currentOperation() const;
{
mySelector = new XGUI_SelectionMgr(this);
myModuleConnector = new XGUI_ModuleConnector(this);
- myOperationMgr = new XGUI_OperationMgr(this, 0);
+ myOperationMgr = new XGUI_OperationMgr(this, myModuleConnector);
ModuleBase_IWorkshop* aWorkshop = moduleConnector();
// Has to be defined first in order to get errors and messages from other components
myEventsListener = new XGUI_WorkshopListener(this);
//connect(myViewerProxy, SIGNAL(selectionChanged()),
// myActionsMgr, SLOT(updateOnViewSelection()));
- myOperationMgr->setWorkshop(aWorkshop);
-
myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop);
connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)),