\r
- :ref:`object_browser`\r
- :ref:`inspection_panel`\r
+- :ref:`hidefaces_panel`\r
- :ref:`python console`\r
- :ref:`property_panel`\r
\r
.. centered::\r
Inspection panel for Face \r
\r
+.. _hidefaces_panel:\r
+\r
+Hide Faces panel\r
+^^^^^^^^^^^^^^^^\r
+\r
+**Hide Faces** panel makes possible to hide temporary faces of any displayed object. **Hide Faces** panel looks like following:\r
+\r
+.. image:: images/hide_faces_panel.png\r
+ :align: center\r
+\r
+.. centered::\r
+ Hide Faces panel\r
+\r
+- If this panel is activated it "listens" user selection.\r
+- If a face is selected then its name will be shown in the panel's list and hidden in the viewer. \r
+- If user selects a group of faces (or at least a one face of this group) then whole group will be hidden and also all faces from all objects referenced by this group.\r
+- If user will display the hidden group again (by a show operation) then the group will be removed from Hide Faces list and visibility of all referenced faces will be restored.\r
+\r
+Also it is possible do not to hide faces, but make them transparent. For this purpose **"Transparent"** check-box can be used. Value of the transparency can be changed in **Visualization** tab of **Preferences** dialog box.\r
+Closing of **Hide Faces** panel restores visibility state of all objects. If it is necessary to deactivete the **Hide Faces** panel (preserving the current display state) then user has to press **"Esc"** button.\r
+\r
+\r
.. _python console:\r
\r
Python console\r
- **Thickness** defines thickness of coordinate plane borders; \r
- **Rotate to plane when selected** check-box turns on/off automatic switch the viewer to the top view for the selected sketch plane. \r
- **Angular tolerance** defines defines an angular tolerance for automatic creation of horizontal and vertical constraints;\r
+- **Default spline weight** defines default weight for B-spline nodes during creation. The default value can be changed by editing of the spline;\r
+- **Cursor for sketch operation** defines a cursor which indicates a launched sketcher sub-operation.\r
+- **Create sketch entities by dragging** defines a style of sketche etities creation. It concerns creation of lines, rectangles, circles, arcs, ellipses, elliptic arcs. If it is switched ON then points of objects has to be defined by mouse press - mouse move - mouse rellease. Otherwise every point of an object has to be defined by mouse click;\r
\r
\r
.. _viewer_preferences:\r
#!/bin/bash -x
-export SALOME_DIR=/dn46/SALOME/series9x/current-2019-10-10
+export SALOME_DIR=/dn46/SALOME/series9x/current-2020-02-03
# Path to sources
export SOURCES_DIR=$(pwd)
# make a working copy of report
cp -f coverage.info.noext covfile
# remove all reports of GUI and external parts (for all the next kinds of reports)
-# RefAttrList is unused type of attribute for now
-for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*' '*RefAttrList*'; do
+for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*'; do
lcov -r covfile ${MASK} --output-file covfile_res -q
mv -f covfile_res covfile
done
@SET OCC_LIB_PREFIX=d
call env_Salome.bat d run
+rem Variable which is necessary for launching SALOME
+SET SALOME_PLEASE_SETUP_ENVIRONMENT_AS_BEFORE=1
+
@SET SHAPER_ROOT_DIR=%ROOT_DIR%\install
@SET SalomeAppConfig=%SHAPER_ROOT_DIR%\share\salome\resources\shaper;%GUI_ROOT_DIR%\share\salome\resources\gui
call env_Salome.bat
+rem Variable which is necessary for launching SALOME
+SET SALOME_PLEASE_SETUP_ENVIRONMENT_AS_BEFORE=1
+
@SET SHAPER_ROOT_DIR=%ROOT_DIR%\install
@SET SalomeAppConfig=%SHAPER_ROOT_DIR%\share\salome\resources\shaper;%GUI_ROOT_DIR%\share\salome\resources\gui
Test2415.py
Test2439.py
Test2454.py
+ Test3125.py
)
--- /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
+#
+
+# Checking of adding a partset-sketcher edges into the wire by the "Add contour" action
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(-24.8768472906404, 33.33497536945814, 36.81773399014779, 23.38423645320196)
+SketchLine_2 = Sketch_1.addLine(36.81773399014779, 23.38423645320196, 11.31896551724138, -27.61330049261085)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(11.31896551724138, -27.61330049261085, -24.8768472906404, 33.33497536945814)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+model.do()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Wire_1_objects = [model.selection("EDGE", "PartSet/Sketch_1/SketchLine_3")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+Wire_1.feature().customAction("add_contour")
+model.end()
+
+from ModelAPI import *
+from GeomAPI import *
+
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Wire_1.feature()))
+
+model.testNbResults(Wire_1, 1)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [3])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [6])
Select one or several faces in viewer. Additionally, a face can be build by a closed wire or a set of edges composing a closed wire.
-It also allowed to select a whole sketch result from the object browser. In this case, the smallest closed contour of the sketch will be transformed to the planar face.
+It is also possible to select a whole sketch result from the object browser. In this case, the smallest closed contour of the sketch will be transformed to the planar face.
**Apply** button creates faces.
.. centered::
Create vertices
-Select one or several vertices in the viewer. It also allowed to select a whole sketch result in the object browser, then all start and end points of the sketch segments will be added into result. Checkbox **Compute intersections** forces to include intersection vertices of edges of the selected sketch.
+Select one or several vertices in the viewer. It is also possible to select a whole sketch result or feature in the object browser, then all start and end points of the sketch segments will be added into result. Checkbox **Compute intersections** forces to include intersection vertices of edges of the selected sketch.
**Apply** button creates vertices.
<source>
<multi_selector id="base_objects"
- label="Segments and wires:"
- tooltip="Select edges on sketch, edges or wires objects."
+ label="Segments, wires or sketches:"
+ tooltip="Select edges on sketch (or the whole sketch), edges or wires objects."
shape_types="edges wires"
concealment="true">
<validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire,compound"/>
TestGroupMoveAndSplit1.py
TestGroupMoveAndSplit2.py
TestGroupMoveAndSplit3.py
+ Test3114.py
+ Test18739.py
)
std::list<ObjectPtr> aResults;
for(int aNext = aList->size() - 1; aNext >= 0; aNext--) {
AttributeSelectionPtr anOldAttr = aList->value(aNext);
- if (anOldAttr->isInvalid() || !anOldAttr->context().get()) {// remove invalids
+ if (anOldAttr->isInvalid() || !anOldAttr->contextObject().get()) {// remove invalids
aRemoved.insert(aNext);
continue;
}
--- /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
+#
+
+# Test of move to the end and split on LinearCopy: check that order in result is correct
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "d", "8")
+model.addParameter(Part_1_doc, "nb", "3")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(-34, 28, 1)
+SketchCircle_2 = Sketch_1.addCircle(-34, 28, 3)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchCircle_2.center())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Sketch_1/Face-SketchCircle_2_2f-SketchCircle_1_2r_wire_2")], model.selection(), 2, -1)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Sketch_1/Face-SketchCircle_2_2f-SketchCircle_1_2r_wire")], model.selection(), 5, 0)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_1"), model.selection("COMPOUND", "all-in-Extrusion_2")])
+Group_1 = model.addGroup(Part_1_doc, "Solids", [model.selection("SOLID", "Partition_1_1_1")])
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPSOLID", "Partition_1_1")], model.selection("EDGE", "PartSet/OX"), "d", "nb", model.selection("EDGE", "PartSet/OY"), "d", "nb")
+model.do()
+Part_1_doc.moveFeature(Group_1.feature(), LinearCopy_1.feature(), True)
+model.end()
+
+for a in range(9):
+ aGroup = Part_1_doc.objectByName("Features", "Group_1_" + str(a + 1))
+ aSelName = aGroup.data().selectionList("group_list").value(0).context().data().name()
+ assert(aSelName == "LinearCopy_1_1_" + str(a + 1) + "_1")
--- /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
+#
+
+# Test of move to the end and split of the group of whole feature selected and no new results appeared
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(45.19889502762433, 34.03867403314917, -47.9889502762431, 34.03867403314917)
+SketchLine_2 = Sketch_1.addLine(-47.9889502762431, 34.03867403314917, -47.9889502762431, -32.64364640883979)
+SketchLine_3 = Sketch_1.addLine(-47.9889502762431, -32.64364640883979, 45.19889502762433, -32.64364640883979)
+SketchLine_4 = Sketch_1.addLine(45.19889502762433, -32.64364640883979, 45.19889502762433, 34.03867403314917)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchCircle_1 = Sketch_1.addCircle(-0.27900552486187, -3.9060773480663, 16.61196177134834)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchCircle_1_2r")])
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("FACE", "Face_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Recover_1 = model.addRecover(Part_1_doc, Translation_1, [Face_1.result()])
+Symmetry_1 = model.addSymmetry(Part_1_doc, [model.selection("FACE", "Translation_1_1")], model.selection("EDGE", "PartSet/OZ"), True)
+Extrusion_1_objects = [model.selection("FACE", "Recover_1_1"), model.selection("FACE", "Symmetry_1_1_1"), model.selection("FACE", "Symmetry_1_1_2")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 50, 0)
+Group_3 = model.addGroup(Part_1_doc, "Edges", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_5 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_6 = model.addGroup(Part_1_doc, "Solids", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+LinearCopy_1_objects = [model.selection("SOLID", "Extrusion_1_3"), model.selection("SOLID", "Extrusion_1_1"), model.selection("SOLID", "Extrusion_1_2")]
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, LinearCopy_1_objects, model.selection("EDGE", "PartSet/OY"), 80, 2, model.selection("EDGE", "PartSet/OZ"), 70, 3)
+model.do()
+Part_1_doc.moveFeature(Group_3.feature(), LinearCopy_1.feature(), True)
+Part_1_doc.moveFeature(Group_5.feature(), LinearCopy_1.feature(), True)
+Part_1_doc.moveFeature(Group_6.feature(), LinearCopy_1.feature(), True)
+model.end()
+
+assert(Part_1_doc.size("Groups") == 3) # equal to the number of original groups
+
+# check names of results
+from ModelAPI import *
+
+aFactory = ModelAPI_Session.get().validators()
+for group in [Group_3, Group_5, Group_6]:
+ assert(aFactory.validate(group.feature()))
+ selectionList = group.feature().selectionList("group_list")
+ assert(selectionList.size() == 1)
+
+assert(model.checkPythonDump())
ShortcutTree,
BiColor,
Background,
- Directory
+ Directory,
+ Cursor
+ };
+
+ enum CursorType
+ {
+ ArrowCursor,
+ CrossCursor,
+ HandCursor
};
/**
Config_Prop::IntSpin, SKETCH_WIDTH);
Config_PropManager::registerProp(SKETCH_TAB_NAME, "angular_tolerance", "Angular tolerance",
Config_Prop::DblSpin, "0.04");
+ Config_PropManager::registerProp(SKETCH_TAB_NAME, "spline_weight", "Default spline weight",
+ Config_Prop::DblSpin, "1.0");
Config_PropManager::registerProp(SKETCH_TAB_NAME, "rotate_to_plane",
"Rotate to plane when selected", Config_Prop::Boolean, "false");
+ Config_PropManager::registerProp(SKETCH_TAB_NAME, "operation_cursor",
+ "Cursor for Sketch operation", Config_Prop::Cursor, "0");
+ Config_PropManager::registerProp(SKETCH_TAB_NAME, "create_by_dragging",
+ "Create sketch enities by dragging", Config_Prop::Boolean, "false");
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
.. centered::
**Along an edge**
-To create a point, select an edge in a viewer and define a distance along the edge, where point will be defined. This distance can be defined by an absolute value or by a relative one as a ratio to the edge length. The direction of the edge can be reversed by the corresponded check box.
+To create a point, select an edge in a viewer and define a distance along the edge, where point will be defined. This distance can be defined by an absolute value or by a relative one as a ratio to the edge length. The direction of the edge can be reversed by the corresponding check-box.
**TUI Commands**:
By projection on edge or plane
------------------------------
+To create a point by projection it is necessary to select an existing point or wertex which will be projected and an edge or a plane (planar face) on which it will be projected:
+
+**On an edge:**
+
.. image:: images/Point3.png
:align: center
.. centered::
- **By projection**
+ **By projection on an edge**
+
+**On a plane:**
+
+.. image:: images/Point3-1.png
+ :align: center
+
+.. centered::
+ **By projection on a plane**
-To create a point, select an existing point or vertex and an edge or face. The new point will be created by projection of the selected point on the edge or face.
+
+The new point will be created by projection of the selected point on the selected object.
**TUI Commands**:
By intersection of objects
--------------------------
+A point can be created by intersection of selected objects:
+
+**Two edges**
+
.. image:: images/Point4.png
:align: center
.. centered::
- **Intersection of objects**
+ **Intersection of edges**
-To create a point, select:
+**Edge and plane**
-#. two edges,
-#. edge and plane,
-#. three planes
+.. image:: images/Point4-1.png
+ :align: center
+
+.. centered::
+ **Intersection of and edge and a plane**
+
+In this case it is possible to define an offset from a plane along the plane normal for the created point.
+
+**Three planes**
+
+.. image:: images/Point4-2.png
+ :align: center
+
+.. centered::
+ **Intersection of three planes**
The new point will be defined by intersection of the selected objects.
By geometrical property of object
---------------------------------
+It is possible to use the following property of selected object:
+
+**A center of gravity**
+
.. image:: images/Point5.png
:align: center
.. centered::
- **By geometrical property**
+ **By center of gravity**
+
+**A center of circle or arc**
-In this case the new point can be defined as a center of gravity of the selected object or as a center of a circle. To create a point, select the desirable object.
+.. image:: images/Point5-1.png
+ :align: center
+
+.. centered::
+ **By center of a circle**
+
+To create a point, select a desirable object.
**TUI Commands**:
std::list<ModelHighAPI_Selection> aListOfOneSel;
aListOfOneSel.push_back(theResult);
fillAttribute(aListOfOneSel,
- theFeature->selectionList(ExchangePlugin_ExportFeature::SELECTION_LIST_ID()));
+ theFeature->selectionList(ExchangePlugin_ExportFeature::XAO_SELECTION_LIST_ID()));
execute();
apply(); // finish operation to make sure the export is done on the current state of the history
}
correctSeparators(aTmpXAOFile);
theDumper << "exportToXAO(" << aDocName << ", '" << aTmpXAOFile << "'" ;
AttributeSelectionListPtr aShapeSelected =
- aBase->selectionList(ExchangePlugin_ExportFeature::SELECTION_LIST_ID());
+ aBase->selectionList(ExchangePlugin_ExportFeature::XAO_SELECTION_LIST_ID());
if (aShapeSelected->isInitialized() && aShapeSelected->size() == 1) {
theDumper<<", "<<aShapeSelected->value(0);
}
)
SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
+# default dump approaches (will be set if not initialized)
+SET(PYTHONDUMP_NAMING ON CACHE BOOL "Dump named references to shapes")
+SET(PYTHONDUMP_GEO ON CACHE BOOL "Dump references to shapes by the geometric properties")
+SET(PYTHONDUMP_WEAK OFF CACHE BOOL "Dump weak named references to shapes")
+
ADD_DEFINITIONS(-DEXCHANGEPLUGIN_EXPORTS)
+IF(${PYTHONDUMP_NAMING})
+ ADD_DEFINITIONS(-DEXCHANGEPLUGIN_DUMP_NAMING)
+ENDIF()
+IF(${PYTHONDUMP_GEO})
+ ADD_DEFINITIONS(-DEXCHANGEPLUGIN_DUMP_GEO)
+ENDIF()
+IF(${PYTHONDUMP_WEAK})
+ ADD_DEFINITIONS(-DEXCHANGEPLUGIN_DUMP_WEAK)
+ENDIF()
ADD_LIBRARY(ExchangePlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES})
TARGET_LINK_LIBRARIES(ExchangePlugin ${PROJECT_LIBRARIES})
TestExport.py
Test2290.py
Test2459.py
+ Test18710.py
TestExportToXAOWithFields.py
TestExportToXAOWithGroupNotUpdated.py
TestExport_FiniteValidator.py
#include <Config_ModuleReader.h>
+#ifdef EXCHANGEPLUGIN_DUMP_NAMING
+static const bool THE_DUMP_NAMING = true;
+#else
+static const bool THE_DUMP_NAMING = false;
+#endif
+
+#ifdef EXCHANGEPLUGIN_DUMP_GEO
+static const bool THE_DUMP_GEO = true;
+#else
+static const bool THE_DUMP_GEO = false;
+#endif
+
+#ifdef EXCHANGEPLUGIN_DUMP_WEAK
+static const bool THE_DUMP_WEAK = true;
+#else
+static const bool THE_DUMP_WEAK = false;
+#endif
+
ExchangePlugin_Dump::ExchangePlugin_Dump()
{
data()->addAttribute(EXPORT_VARIABLES_ID(), ModelAPI_AttributeBoolean::typeId());
// default values
- boolean(TOPOLOGICAL_NAMING_DUMP_ID())->setValue(true);
- boolean(GEOMETRIC_DUMP_ID())->setValue(true);
- boolean(WEAK_NAMING_DUMP_ID())->setValue(false);
+ boolean(TOPOLOGICAL_NAMING_DUMP_ID())->setValue(THE_DUMP_NAMING);
+ boolean(GEOMETRIC_DUMP_ID())->setValue(THE_DUMP_GEO);
+ boolean(WEAK_NAMING_DUMP_ID())->setValue(THE_DUMP_WEAK);
boolean(EXPORT_VARIABLES_ID())->setValue(false);
}
ModelAPI_AttributeString::typeId());
data()->addAttribute(ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID(),
ModelAPI_AttributeString::typeId());
+ data()->addAttribute(ExchangePlugin_ExportFeature::XAO_SELECTION_LIST_ID(),
+ ModelAPI_AttributeSelectionList::typeId());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(),
ExchangePlugin_ExportFeature::XAO_FILE_PATH_ID());
ExchangePlugin_ExportFeature::XAO_AUTHOR_ID());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(),
ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(),
+ ExchangePlugin_ExportFeature::XAO_SELECTION_LIST_ID());
+
+ // to support previous version of document, move the selection list
+ // if the type of export operation is XAO
+ AttributeStringPtr aTypeAttr = string(EXPORT_TYPE_ID());
+ if (aTypeAttr->isInitialized() && aTypeAttr->value() == "XAO") {
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true, false);
+ AttributeSelectionListPtr aSelList = selectionList(SELECTION_LIST_ID());
+ AttributeSelectionListPtr aXAOSelList = selectionList(XAO_SELECTION_LIST_ID());
+ if (aSelList->size() > 0 && aXAOSelList->size() == 0)
+ aSelList->copyTo(aXAOSelList);
+ aSelList->clear();
+ data()->blockSendAttributeUpdated(aWasBlocked, false);
+ }
}
void ExchangePlugin_ExportFeature::attributeChanged(const std::string& theID)
std::list<DocumentPtr> aDocuments; /// documents of Parts selected and used in export
std::map<DocumentPtr, GeomTrsfPtr> aDocTrsf; /// translation of the part
- AttributeSelectionListPtr aSelection = selectionList(SELECTION_LIST_ID());
+ AttributeSelectionListPtr aSelection = selectionList(XAO_SELECTION_LIST_ID());
bool aIsSelection = aSelection->isInitialized() && aSelection->size() > 0;
if (aIsSelection) { // a mode for export to geom result by result
for(int a = 0; a < aSelection->size(); a++) {
if (aFormat == "XAO") { // on export to GEOM the selection attribute is filled - this is
// an exceptional case where export to XAO feature must be kept
- AttributeSelectionListPtr aList = aThis->selectionList(SELECTION_LIST_ID());
+ AttributeSelectionListPtr aList = aThis->selectionList(XAO_SELECTION_LIST_ID());
return !aList->isInitialized() || aList->size() == 0;
}
return true;
static const std::string MY_SELECTION_LIST_ID("selection_list");
return MY_SELECTION_LIST_ID;
}
+ /// attribute name of xao selection list
+ inline static const std::string& XAO_SELECTION_LIST_ID()
+ {
+ static const std::string MY_SELECTION_LIST_ID("xao_selection_list");
+ return MY_SELECTION_LIST_ID;
+ }
/// attribute name of author for XAO format
inline static const std::string& XAO_AUTHOR_ID()
{
// Returns true if all features can be exported.
static bool verifyExport(const std::list<FeaturePtr>& theFeatures,
std::list<FeaturePtr>& theExternalReferences,
- std::list<FeaturePtr>& theExportedParts);
+ std::list<FeaturePtr>& theExportedParts,
+ std::list<FeaturePtr>& theReferredParts);
+// Collect names of features as a single string
+static std::string namesOfFeatures(const std::list<FeaturePtr>& theFeatures);
ExchangePlugin_ExportPart::ExchangePlugin_ExportPart()
if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID())
aFeaturesToExport.pop_back();
- std::list<FeaturePtr> anExternalLinks, aReferredParts;
- if (!verifyExport(aFeaturesToExport, anExternalLinks, aReferredParts)) {
+ std::list<FeaturePtr> anExternalLinks, anExportedParts, aReferredParts;
+ if (!verifyExport(aFeaturesToExport, anExternalLinks, anExportedParts, aReferredParts)) {
if (!anExternalLinks.empty()) {
- // collect names of features as a string
- std::ostringstream aListOfFeatures;
- for (std::list<FeaturePtr>::iterator anIt = anExternalLinks.begin();
- anIt != anExternalLinks.end(); ++anIt) {
- if (anIt != anExternalLinks.begin())
- aListOfFeatures << ", ";
- aListOfFeatures << "'" << (*anIt)->name() << "'";
- }
+ std::string aListOfFeatures = namesOfFeatures(anExternalLinks);
std::string aMessage = "The selected results were created using external references "
"outside of this Part from features %1. "
"Please, remove these references or select another "
"sub-set of results to be able to export.";
- Events_InfoMessage(getKind(), aMessage).arg(aListOfFeatures.str()).send();
+ Events_InfoMessage(getKind(), aMessage).arg(aListOfFeatures).send();
}
if (!aReferredParts.empty()) {
- // collect names of parts as a string
- std::ostringstream aListOfParts;
- for (std::list<FeaturePtr>::iterator anIt = aReferredParts.begin();
- anIt != aReferredParts.end(); ++anIt) {
- if (anIt != aReferredParts.begin())
- aListOfParts << ", ";
- aListOfParts << "'" << (*anIt)->name() << "'";
- }
+ std::string aListOfParts = namesOfFeatures(aReferredParts);
std::string aMessage = "The selected results were created using references "
- "to results of Parts %1. Please, remove these references "
+ "to the results of Parts: %1. Please, remove these references "
"or select another sub-set of results to be able to export.";
- Events_InfoMessage(getKind(), aMessage).arg(aListOfParts.str()).send();
+ Events_InfoMessage(getKind(), aMessage).arg(aListOfParts).send();
+ }
+ if (!anExportedParts.empty()) {
+ std::string aListOfParts = namesOfFeatures(anExportedParts);
+
+ std::string aMessage = "The export of Part's result is forbidden (%1).";
+ Events_InfoMessage(getKind(), aMessage).arg(aListOfParts).send();
}
// should not export anything
aFeaturesToExport.clear();
bool verifyExport(const std::list<FeaturePtr>& theFeatures,
std::list<FeaturePtr>& theExternalReferences,
- std::list<FeaturePtr>& theExportedParts)
+ std::list<FeaturePtr>& theExportedParts,
+ std::list<FeaturePtr>& theReferredParts)
{
for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
anIt != theFeatures.end(); ++anIt) {
theExternalReferences.push_back(*anIt);
// feature refers to result of a part
if (aFeature->getKind() == PartSetPlugin_Part::ID())
- theExportedParts.push_back(*anIt);
+ theReferredParts.push_back(*anIt);
}
}
}
}
- return theExternalReferences.empty() && theExportedParts.empty();
+ return theExternalReferences.empty() && theExportedParts.empty() && theReferredParts.empty();
+}
+
+std::string namesOfFeatures(const std::list<FeaturePtr>& theFeatures)
+{
+ std::ostringstream aListOfFeatures;
+ for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
+ anIt != theFeatures.end(); ++anIt) {
+ if (anIt != theFeatures.begin())
+ aListOfFeatures << ", ";
+ aListOfFeatures << "'" << (*anIt)->name() << "'";
+ }
+ return aListOfFeatures.str();
}
<translation>The selected results were created using external references outside of this Part from features %1. Please, remove these references or select another sub-set of results to be able to export.</translation>
</message>
<message>
- <source>The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export.</source>
- <translation>The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export.</translation>
+ <source>The selected results were created using references to the results of Parts: %1. Please, remove these references or select another sub-set of results to be able to export.</source>
+ <translation>The selected results were created using references to the results of Parts: %1. Please, remove these references or select another sub-set of results to be able to export.</translation>
+ </message>
+ <message>
+ <source>The export of Part's result is forbidden (%1).</source>
+ <translation>The export of Part's result is forbidden (%1).</translation>
</message>
</context>
</message>
</context>
+ <context>
+ <name>Export:ExchangePlugin_ExportPart</name>
+ <message>
+ <source>Cannot save the document.</source>
+ <translation>Impossible d'enregistrer le document.</translation>
+ </message>
+ <message>
+ <source>Selected features cannot be exported from the document.</source>
+ <translation>Les fonctions sélectionnées ne peuvent pas être exportées à partir du document.</translation>
+ </message>
+ <message>
+ <source>The selected results were created using external references outside of this Part from features %1. Please, remove these references or select another sub-set of results to be able to export.</source>
+ <translation>Les résultats sélectionnés ont été créés à l'aide de références externes en dehors de cette pièce à partir des fonctions %1. Veuillez supprimer ces références ou sélectionner un autre sous-ensemble de résultats pour pouvoir exporter.</translation>
+ </message>
+ <message>
+ <source>The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export.</source>
+ <translation>Les résultats sélectionnés ont été créés en utilisant des références aux résultats des pièces: %1. Veuillez supprimer ces références ou sélectionner un autre sous-ensemble de résultats pour pouvoir exporter.</translation>
+ </message>
+ <message>
+ <source>The export of Part's result is forbidden (%1).</source>
+ <translation>L'exportation du résultat de la pièce est interdite (%1).</translation>
+ </message>
+ </context>
+
+ <context>
+ <name>Import:ExchangePlugin_ImportPart</name>
+ <message>
+ <source>Cannot import the document.</source>
+ <translation>Impossible d'importer le document.</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
+
+from GeomAPI import *
+from ModelAPI import *
+from SketchAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Export_1 = model.exportToXAO(Part_1_doc, '/tmp/shaper_vcnhioqf.xao', model.selection("SOLID", "Cylinder_1_1"), 'XAO')
+Export_1.setName("XAO")
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+model.end()
+
+model.testNbResults(Part_1, 1)
+model.testNbSubResults(Part_1, [0])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.EDGE, [30])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.VERTEX, [60])
+model.testResultsVolumes(Part_1, [1785.39816339744857])
+
+model.begin()
+ModelAPI.removeFeaturesAndReferences(FeatureSet([Cylinder_1.feature()]))
+model.end()
+
+model.testNbResults(Part_1, 1)
+model.testNbSubResults(Part_1, [0])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Part_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Part_1, [1000])
+
+assert(model.checkPythonDump())
FeaturesAPI_Translation.h
FeaturesAPI_Union.h
FeaturesAPI_FusionFaces.h
+ FeaturesAPI_Copy.h
+ FeaturesAPI_ImportResult.h
+ FeaturesAPI_Defeaturing.h
)
SET(PROJECT_SOURCES
FeaturesAPI_Translation.cpp
FeaturesAPI_Union.cpp
FeaturesAPI_FusionFaces.cpp
+ FeaturesAPI_Copy.cpp
+ FeaturesAPI_ImportResult.cpp
+ FeaturesAPI_Defeaturing.cpp
)
SET(PROJECT_LIBRARIES
%shared_ptr(FeaturesAPI_Union)
%shared_ptr(FeaturesAPI_FusionFaces)
%shared_ptr(FeaturesAPI_RemoveResults)
+%shared_ptr(FeaturesAPI_Copy)
+%shared_ptr(FeaturesAPI_ImportResult)
+%shared_ptr(FeaturesAPI_Defeaturing)
%typecheck(SWIG_TYPECHECK_POINTER) std::pair<std::list<ModelHighAPI_Selection>, bool>, const std::pair<std::list<ModelHighAPI_Selection>, bool> & {
%include "FeaturesAPI_BooleanSmash.h"
%include "FeaturesAPI_BooleanFill.h"
%include "FeaturesAPI_Chamfer.h"
+%include "FeaturesAPI_Defeaturing.h"
%include "FeaturesAPI_Extrusion.h"
%include "FeaturesAPI_ExtrusionBoolean.h"
%include "FeaturesAPI_Fillet.h"
%include "FeaturesAPI_Union.h"
%include "FeaturesAPI_FusionFaces.h"
%include "FeaturesAPI_RemoveResults.h"
+%include "FeaturesAPI_Copy.h"
+%include "FeaturesAPI_ImportResult.h"
--- /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 "FeaturesAPI_Copy.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+//================================================================================================
+FeaturesAPI_Copy::FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+: ModelHighAPI_Interface(theFeature)
+{
+ initialize();
+}
+
+//================================================================================================
+FeaturesAPI_Copy::FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theObjects,
+ const int theNumber)
+: ModelHighAPI_Interface(theFeature)
+{
+ if(initialize()) {
+ setNumber(theNumber);
+ setObjects(theObjects);
+ }
+}
+
+//================================================================================================
+FeaturesAPI_Copy::~FeaturesAPI_Copy() {}
+
+//=================================================================================================
+void FeaturesAPI_Copy::setObjects(const std::list<ModelHighAPI_Selection>& theObjects)
+{
+ fillAttribute(theObjects, myobjects);
+ execute();
+}
+//=================================================================================================
+void FeaturesAPI_Copy::setNumber(const int theNumber)
+{
+ fillAttribute(theNumber, mynumber);
+ execute();
+}
+
+//=================================================================================================
+void FeaturesAPI_Copy::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ FeaturePtr aBase = feature();
+ const std::string& aDocName = theDumper.name(aBase->document());
+
+ AttributeSelectionListPtr anObjects = aBase->selectionList(FeaturesPlugin_Copy::OBJECTS());
+ AttributeIntegerPtr aNumber = aBase->integer(FeaturesPlugin_Copy::NUMBER());
+
+ theDumper << aBase << " = model.addCopy("
+ << aDocName << ", " << anObjects << ", " << aNumber << ")" << std::endl;
+}
+
+//=================================================================================================
+CopyPtr addCopy(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theObjects,
+ const int theNumber)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Copy::ID());
+ return CopyPtr(new FeaturesAPI_Copy(aFeature, theObjects, theNumber));
+}
--- /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 FeaturesAPI_Copy_H_
+#define FeaturesAPI_Copy_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Copy.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Dumper;
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Copy
+/// \ingroup CPPHighAPI
+/// \brief Interface for Copy feature.
+class FeaturesAPI_Copy: public ModelHighAPI_Interface
+{
+public:
+ /// Constructor without values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Constructor with values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Copy(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects,
+ const int theNumber);
+
+ /// Destructor.
+ FEATURESAPI_EXPORT virtual ~FeaturesAPI_Copy();
+
+ INTERFACE_2(FeaturesPlugin_Copy::ID(),
+ objects, FeaturesPlugin_Copy::OBJECTS(),
+ ModelAPI_AttributeSelectionList, /** Source objects */,
+ number, FeaturesPlugin_Copy::NUMBER(),
+ ModelAPI_AttributeInteger, /** Number of copies */)
+
+ /// Modify objects attribute of the feature.
+ FEATURESAPI_EXPORT void setObjects(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+ /// Modify number of copies attribute of the feature.
+ FEATURESAPI_EXPORT void setNumber(const int theNumber);
+
+ /// Dump wrapped feature
+ FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on Copy object.
+typedef std::shared_ptr<FeaturesAPI_Copy> CopyPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Copy feature.
+FEATURESAPI_EXPORT
+CopyPtr addCopy(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theObjects,
+ const int theNumber);
+
+#endif // FeaturesAPI_Copy_H_
--- /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 "FeaturesAPI_Defeaturing.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+FeaturesAPI_Defeaturing::FeaturesAPI_Defeaturing(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature)
+ : ModelHighAPI_Interface(theFeature)
+{
+ initialize();
+}
+
+FeaturesAPI_Defeaturing::FeaturesAPI_Defeaturing(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theFacesToRemove)
+ : ModelHighAPI_Interface(theFeature)
+{
+ if (initialize())
+ setFaces(theFacesToRemove);
+}
+
+FeaturesAPI_Defeaturing::~FeaturesAPI_Defeaturing()
+{
+}
+
+void FeaturesAPI_Defeaturing::setFaces(const std::list<ModelHighAPI_Selection>& theFacesToRemove)
+{
+ mybaseObjects->clear();
+ fillAttribute(theFacesToRemove, mybaseObjects);
+
+ execIfBaseNotEmpty();
+}
+
+void FeaturesAPI_Defeaturing::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ FeaturePtr aBase = feature();
+ const std::string& aDocName = theDumper.name(aBase->document());
+
+ AttributeSelectionListPtr anAttrObjects =
+ aBase->selectionList(FeaturesPlugin_Defeaturing::OBJECT_LIST_ID());
+
+ theDumper << aBase << " = model.addDefeaturing(" << aDocName << ", "
+ << anAttrObjects << ")" << std::endl;
+}
+
+void FeaturesAPI_Defeaturing::execIfBaseNotEmpty()
+{
+ if (mybaseObjects->size() > 0)
+ execute();
+}
+
+
+//==================================================================================================
+
+DefeaturingPtr addDefeaturing(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theFaces)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Defeaturing::ID());
+ return DefeaturingPtr(new FeaturesAPI_Defeaturing(aFeature, theFaces));
+}
--- /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 FeaturesAPI_Defeaturing_H_
+#define FeaturesAPI_Defeaturing_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_Defeaturing.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_Defeaturing
+/// \ingroup CPPHighAPI
+/// \brief Interface for the Defeaturing feature.
+class FeaturesAPI_Defeaturing: public ModelHighAPI_Interface
+{
+public:
+ /// Constructor without values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Defeaturing(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Constructor with values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_Defeaturing(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theFacesToRemove);
+
+ /// Destructor.
+ FEATURESAPI_EXPORT
+ virtual ~FeaturesAPI_Defeaturing();
+
+ INTERFACE_1(FeaturesPlugin_Defeaturing::ID(),
+ baseObjects, FeaturesPlugin_Defeaturing::OBJECT_LIST_ID(),
+ ModelAPI_AttributeSelectionList, /** Base objects */)
+
+ /// Modify faces to be removed.
+ FEATURESAPI_EXPORT
+ void setFaces(const std::list<ModelHighAPI_Selection>& theFacesToRemove);
+
+ /// Dump wrapped feature
+ FEATURESAPI_EXPORT
+ virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+private:
+ void execIfBaseNotEmpty();
+};
+
+/// Pointer on the Defeaturing object.
+typedef std::shared_ptr<FeaturesAPI_Defeaturing> DefeaturingPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Defeaturing feature.
+FEATURESAPI_EXPORT
+DefeaturingPtr addDefeaturing(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theFaces);
+
+#endif // FeaturesAPI_Defeaturing_H_
--- /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 "FeaturesAPI_ImportResult.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+//================================================================================================
+FeaturesAPI_ImportResult::FeaturesAPI_ImportResult(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature) : ModelHighAPI_Interface(theFeature)
+{
+ initialize();
+}
+
+//================================================================================================
+FeaturesAPI_ImportResult::FeaturesAPI_ImportResult(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theObjects) : ModelHighAPI_Interface(theFeature)
+{
+ if(initialize()) {
+ setObjects(theObjects);
+ }
+}
+
+//=================================================================================================
+FeaturesAPI_ImportResult::~FeaturesAPI_ImportResult() {}
+
+//=================================================================================================
+void FeaturesAPI_ImportResult::setObjects(const std::list<ModelHighAPI_Selection>& theObjects)
+{
+ fillAttribute(theObjects, myobjects);
+ execute();
+}
+
+//=================================================================================================
+void FeaturesAPI_ImportResult::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ FeaturePtr aBase = feature();
+ const std::string& aDocName = theDumper.name(aBase->document());
+ AttributeSelectionListPtr anObjects =
+ aBase->selectionList(FeaturesPlugin_ImportResult::OBJECTS());
+
+ theDumper << aBase << " = model.addImportResult("
+ << aDocName << ", " << anObjects << ")" << std::endl;
+}
+
+//=================================================================================================
+ImportResultPtr addImportResult(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theObjects)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_ImportResult::ID());
+ return ImportResultPtr(new FeaturesAPI_ImportResult(aFeature, theObjects));
+}
--- /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 FeaturesAPI_ImportResult_H_
+#define FeaturesAPI_ImportResult_H_
+
+#include "FeaturesAPI.h"
+
+#include <FeaturesPlugin_ImportResult.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Dumper;
+class ModelHighAPI_Selection;
+
+/// \class FeaturesAPI_ImportResult
+/// \ingroup CPPHighAPI
+/// \brief Interface for ImportResult feature.
+class FeaturesAPI_ImportResult: public ModelHighAPI_Interface
+{
+public:
+ /// Constructor without values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_ImportResult(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Constructor with values.
+ FEATURESAPI_EXPORT
+ explicit FeaturesAPI_ImportResult(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+ /// Destructor.
+ FEATURESAPI_EXPORT virtual ~FeaturesAPI_ImportResult();
+
+ INTERFACE_1(FeaturesPlugin_ImportResult::ID(),
+ objects, FeaturesPlugin_ImportResult::OBJECTS(),
+ ModelAPI_AttributeSelectionList, /** Source objects */)
+
+ /// Modify objects attribute of the feature.
+ FEATURESAPI_EXPORT void setObjects(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+ /// Dump wrapped feature
+ FEATURESAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on ImportResult object.
+typedef std::shared_ptr<FeaturesAPI_ImportResult> ImportResultPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create ImportResult feature.
+FEATURESAPI_EXPORT
+ImportResultPtr addImportResult(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theObjects);
+
+#endif // FeaturesAPI_ImportResult_H_
#include "FeaturesAPI_BooleanSmash.h"
#include "FeaturesAPI_BooleanFill.h"
#include "FeaturesAPI_Chamfer.h"
+ #include "FeaturesAPI_Defeaturing.h"
#include "FeaturesAPI_Extrusion.h"
#include "FeaturesAPI_ExtrusionBoolean.h"
#include "FeaturesAPI_Fillet.h"
#include "FeaturesAPI_Union.h"
#include "FeaturesAPI_FusionFaces.h"
#include "FeaturesAPI_RemoveResults.h"
+ #include "FeaturesAPI_Copy.h"
+ #include "FeaturesAPI_ImportResult.h"
#endif // FeaturesAPI_swig_H_
FeaturesPlugin_FusionFaces.h
FeaturesPlugin_RemoveResults.h
FeaturesPlugin_Chamfer.h
+ FeaturesPlugin_Copy.h
+ FeaturesPlugin_ImportResult.h
+ FeaturesPlugin_Defeaturing.h
)
SET(PROJECT_SOURCES
FeaturesPlugin_FusionFaces.cpp
FeaturesPlugin_RemoveResults.cpp
FeaturesPlugin_Chamfer.cpp
+ FeaturesPlugin_Copy.cpp
+ FeaturesPlugin_ImportResult.cpp
+ FeaturesPlugin_Defeaturing.cpp
)
SET(XML_RESOURCES
measurement_widget.xml
fusion_faces_widget.xml
chamfer_widget.xml
+ copy_widget.xml
+ import_result_widget.xml
+ defeaturing_widget.xml
)
SET(TEXT_RESOURCES
Test3033.py
Test3076.py
Test17909.py
+ TestCopyFeature.py
+ TestCopyFeatureMoveGroupOfFeature.py
+ TestCopyMoveResult.py
+ TestCopyMoveSubShapes.py
+ TestCopyNames.py
+ TestCopySubShapes.py
+ TestCopyWholeFeature.py
+ TestImportResult.py
+ TestDefeaturing_ErrorMsg.py
+ TestDefeaturing_OnSolid1.py
+ TestDefeaturing_OnSolid2.py
+ TestDefeaturing_OnSolid3.py
+ TestDefeaturing_OnCompsolid1.py
+ TestDefeaturing_OnCompsolid2.py
+ TestDefeaturing_OnCompsolid3.py
+ TestDefeaturing_OnCompound.py
+ Test3137_1.py
+ Test3137_2.py
+ Test2918.py
)
--- /dev/null
+// Copyright (C) 2017-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 "FeaturesPlugin_Copy.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAlgoAPI_Copy.h>
+#include <GeomAlgoAPI_Tools.h>
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <sstream>
+
+void FeaturesPlugin_Copy::initAttributes()
+{
+ data()->addAttribute(OBJECTS(), ModelAPI_AttributeSelectionList::typeId());
+ data()->addAttribute(NUMBER(), ModelAPI_AttributeInteger::typeId());
+}
+
+static GeomShapePtr shapeOfSelection(AttributeSelectionPtr theSel) {
+ GeomShapePtr aResult;
+ FeaturePtr aSelFeature = theSel->contextFeature();
+ if (aSelFeature.get()) {
+ if (aSelFeature->results().empty()) // if selected feature has no results, make nothing
+ return aResult;
+ if (aSelFeature->results().size() == 1) { // for one sub-result don't make compound
+ aResult = aSelFeature->firstResult()->shape();
+ }
+ }
+ if (!aResult.get())
+ aResult = theSel->value();
+ if (!aResult.get()) {
+ if (theSel->context().get())
+ aResult = theSel->context()->shape();
+ }
+ return aResult;
+}
+
+void FeaturesPlugin_Copy::execute()
+{
+ int aCopiesNum = integer(NUMBER())->value();
+ AttributeSelectionListPtr aList = selectionList(OBJECTS());
+ int aResultIndex = 0;
+ std::set<std::string> anExistingNames; // to avoid names duplication
+ for(int aCopy = 0; aCopy < aCopiesNum; aCopy++) {
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ AttributeSelectionPtr aSel = aList->value(aSelIndex);
+ GeomShapePtr aShape = shapeOfSelection(aSel);
+ if (!aShape.get())
+ continue;
+ std::shared_ptr<GeomAlgoAPI_Copy> aCopyBuilder(new GeomAlgoAPI_Copy(aShape, false, false));
+ std::string anError;
+ if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCopyBuilder, getKind(), anError)) {
+ setError(anError);
+ return;
+ }
+ GeomShapePtr aResult = aCopyBuilder->shape();
+
+ std::string aBaseName = aSel->context() ? aSel->context()->data()->name() :
+ aSel->contextFeature()->firstResult()->data()->name();
+ std::string aName;
+ int anInd = 0;
+ do {
+ anInd++;
+ std::ostringstream aNameStr;
+ aNameStr << aBaseName << "_" << (aCopy + anInd);
+ aName = aNameStr.str();
+ } while (anExistingNames.count(aName));
+ anExistingNames.insert(aName);
+
+ std::shared_ptr<ModelAPI_ResultBody> aResultBody =
+ document()->createBody(data(), aResultIndex);
+ aResultBody->data()->setName(aName);
+ // to make sub-results also names with a similar name temporarily rename the feature
+ std::string anOrigName = name();
+ data()->setName(aBaseName);
+ aResultBody->store(aResult);
+ data()->setName(anOrigName);
+ aResultBody->loadFirstLevel(aResult, "Copy");
+ setResult(aResultBody, aResultIndex++);
+ }
+ }
+ removeResults(aResultIndex);
+}
+
+void FeaturesPlugin_Copy::getCopies(
+ ObjectPtr theContext, std::shared_ptr<GeomAPI_Shape> theValue,
+ std::list<ObjectPtr>& theCopyContext, std::list<std::shared_ptr<GeomAPI_Shape> >& theCopyVals)
+{
+ ResultPtr aContextRes = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
+ GeomShapePtr aGroupValue = theValue.get() ? theValue : aContextRes->shape();
+
+ AttributeSelectionListPtr aList = selectionList(OBJECTS());
+ std::list<ResultPtr>::const_iterator aResIter = results().cbegin();
+ while(aResIter != results().cend()) { // do as long as many iterations
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ if (aResIter == results().cend()) // no more results corresponding to the selection
+ return;
+ AttributeSelectionPtr aSel = aList->value(aSelIndex);
+ GeomShapePtr aShape = shapeOfSelection(aSel);
+ if (!aShape.get())
+ continue;
+
+ if (aShape->isSubShape(aGroupValue, false)) { // group value is subshape of copied => copy
+ // search the same result in the copy by the same index of sub-shape in the shape
+ GeomAPI_ShapeExplorer anOrigExp(aShape, aGroupValue->shapeType());
+ GeomAPI_ShapeExplorer aCopyShape((*aResIter)->shape(), aGroupValue->shapeType());
+ for(; anOrigExp.more(); anOrigExp.next(), aCopyShape.next()) {
+ if (anOrigExp.current()->isSame(aGroupValue)) {
+ // searching for sub-result if it is composite result, but context-not
+ ResultPtr aResContext = *aResIter;
+ if (aContextRes->shape()->shapeType() > (*aResIter)->shape()->shapeType()) {
+ ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResContext);
+ if (aResBody.get()) {
+ std::list<ResultPtr> aSubs;
+ ModelAPI_Tools::allSubs(aResBody, aSubs, true);
+ std::list<ResultPtr>::iterator aSubIter = aSubs.begin();
+ for(; aSubIter != aSubs.end(); aSubIter++) {
+ GeomShapePtr aSubShape = (*aSubIter)->shape();
+ if (aSubShape.get() && aSubShape->isSubShape(aCopyShape.current(), false)) {
+ aResContext = *aSubIter;
+ break;
+ }
+ }
+ }
+ }
+ theCopyContext.push_back(aResContext);
+ theCopyVals.push_back(aResContext->shape()->isSame(
+ aCopyShape.current()) ? GeomShapePtr() : aCopyShape.current());
+ break;
+ }
+ }
+ }
+ aResIter++;
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2017-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 FeaturesPlugin_Copy_H_
+#define FeaturesPlugin_Copy_H_
+
+#include "FeaturesPlugin.h"
+
+#include <ModelAPI_Feature.h>
+
+/// \class FeaturesPlugin_Copy
+/// \ingroup Plugins
+/// \brief This feature copies the selected results and sub-results (for the whole feature selected
+/// all results of this feature are copied). The referenced arguments of this feature are
+/// not concealed. The difference with \94Recover\94 feature is that not concealed results may
+/// be selected and in the history behavior: the \93Move to the End\94 of groups will move to
+/// all copy-results.
+
+class FeaturesPlugin_Copy : public ModelAPI_Feature, public ModelAPI_FeatureCopyInterface
+{
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("Copy");
+ return MY_ID;
+ }
+
+ /// \return the kind of a feature.
+ FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = FeaturesPlugin_Copy::ID();
+ return MY_KIND;
+ }
+
+ /// Selection list attribute that contains all copied shapes selection.
+ inline static const std::string& OBJECTS()
+ {
+ static const std::string MY_OBJECTS("objects");
+ return MY_OBJECTS;
+ }
+ /// Integer attribute that contains the number of resulting copies needed
+ inline static const std::string NUMBER()
+ {
+ static std::string MY_NUMBER("number");
+ return MY_NUMBER;
+ }
+
+ /// Performs the algorithm and stores results it in the data structure.
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Request for initialization of data model of the feature: adding all attributes.
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// To update the group feature which is moved over this copy feature (to add copies to selection)
+ FEATURESPLUGIN_EXPORT virtual void getCopies(
+ ObjectPtr theContext, std::shared_ptr<GeomAPI_Shape> theValue,
+ std::list<ObjectPtr>& theCopyContext, std::list<std::shared_ptr<GeomAPI_Shape> >& theCopyVals);
+
+ /// Use plugin manager for features creation.
+ FeaturesPlugin_Copy() {}
+};
+
+#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 <FeaturesPlugin_Defeaturing.h>
+#include <FeaturesPlugin_Tools.h>
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_Defeaturing.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_Tools.h>
+
+#include <unordered_map>
+
+
+FeaturesPlugin_Defeaturing::FeaturesPlugin_Defeaturing()
+{
+}
+
+void FeaturesPlugin_Defeaturing::initAttributes()
+{
+ data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+}
+
+
+void FeaturesPlugin_Defeaturing::execute()
+{
+ typedef std::unordered_map<GeomShapePtr, ListOfShape,
+ GeomAPI_Shape::Hash, GeomAPI_Shape::Equal> SolidFaces;
+ SolidFaces aBodiesAndFacesToRemove;
+
+ // getting objects and sort them according to parent solids
+ AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID());
+ for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); ++anObjectsIndex) {
+ AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
+ GeomShapePtr anObject = anObjectAttr->value();
+ if (!anObject)
+ return;
+
+ ResultPtr aContext = anObjectAttr->context();
+ if (!aContext.get())
+ return;
+
+ ResultBodyPtr aCtxOwner = ModelAPI_Tools::bodyOwner(aContext, true);
+ GeomShapePtr aParent = aCtxOwner ? aCtxOwner->shape() : aContext->shape();
+ aBodiesAndFacesToRemove[aParent].push_back(anObject);
+ }
+
+ // Perform Defeaturing algorithm
+ GeomAlgoAPI_MakeShapeList aMakeShapeList;
+ std::shared_ptr<GeomAlgoAPI_Defeaturing> anAlgo;
+ int aResultIndex = 0;
+ std::string anError;
+
+ std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
+ ListOfShape anOriginalShapesList, aResultShapesList;
+
+ for (SolidFaces::iterator anIt = aBodiesAndFacesToRemove.begin();
+ anIt != aBodiesAndFacesToRemove.end(); ++anIt) {
+ GeomShapePtr aParent = anIt->first;
+ anAlgo.reset(new GeomAlgoAPI_Defeaturing(aParent, anIt->second));
+ if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anAlgo, getKind(), anError)) {
+ setError(anError);
+ return;
+ }
+
+ GeomShapePtr aResult = anAlgo->shape();
+ ListOfShape aBaseShapes;
+ for (GeomAPI_ShapeExplorer anExp(aParent, GeomAPI_Shape::SOLID); anExp.more(); anExp.next())
+ aBaseShapes.push_back(anExp.current());
+
+ std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
+ FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, aBaseShapes, ListOfShape(),
+ anAlgo, aResult, "Defeaturing");
+
+ setResult(aResultBody, aResultIndex);
+ aResultIndex++;
+
+ FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
+ aRBA.resultBody = aResultBody;
+ aRBA.baseShape = aParent;
+ aRBA.makeShape = anAlgo;
+ aResultBaseAlgoList.push_back(aRBA);
+ aResultShapesList.push_back(aResult);
+ anOriginalShapesList.insert(anOriginalShapesList.end(), aBaseShapes.begin(), aBaseShapes.end());
+ }
+
+ // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one
+ // result shape has been deleted, but in another it was modified or stayed.
+ GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList);
+ FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList,
+ anOriginalShapesList, aResultShapesCompound);
+
+ removeResults(aResultIndex);
+}
--- /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_Defeaturing_H_
+#define FeaturesPlugin_Defeaturing_H_
+
+#include "FeaturesPlugin.h"
+
+#include <ModelAPI_Feature.h>
+
+class GeomAlgoAPI_MakeShape;
+class GeomAPI_Shape;
+
+/// \class FeaturesPlugin_Defeaturing
+/// \ingroup Plugins
+/// \brief Feature for the removal of the unwanted parts or features from the model.
+class FeaturesPlugin_Defeaturing : public ModelAPI_Feature
+{
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("Defeaturing");
+ return MY_ID;
+ }
+
+ /// \return the kind of a feature.
+ FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = FeaturesPlugin_Defeaturing::ID();
+ return MY_KIND;
+ }
+
+ /// Attribute name of main objects.
+ inline static const std::string& OBJECT_LIST_ID()
+ {
+ static const std::string MY_OBJECT_LIST_ID("main_objects");
+ return MY_OBJECT_LIST_ID;
+ }
+
+ /// Performs the defeaturing algorithm and stores it in the data structure.
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Request for initialization of data model of the feature: adding all attributes.
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Use plugin manager for features creation.
+ FeaturesPlugin_Defeaturing();
+
+private:
+ /// Load Naming data structure of the feature to the document
+ void loadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
+ const std::shared_ptr<GeomAPI_Shape> theBaseShape,
+ const std::shared_ptr<GeomAPI_Shape> theResultShape,
+ const std::shared_ptr<GeomAlgoAPI_MakeShape>& theMakeShape);
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2017-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 "FeaturesPlugin_ImportResult.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_ResultPart.h>
+#include <Events_InfoMessage.h>
+
+void FeaturesPlugin_ImportResult::initAttributes()
+{
+ data()->addAttribute(OBJECTS(), ModelAPI_AttributeSelectionList::typeId());
+}
+
+void FeaturesPlugin_ImportResult::execute()
+{
+ AttributeSelectionListPtr aList = selectionList(OBJECTS());
+ int aResultIndex = 0;
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ AttributeSelectionPtr aSel = aList->value(aSelIndex);
+ ResultPtr aContext = aSel->context();
+ if (!aContext.get())
+ continue;
+ GeomShapePtr aShape = aContext->shape();
+ if (!aShape.get() || aShape->isNull())
+ continue;
+ std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
+ aResultBody->store(aShape);
+ aResultBody->loadFirstLevel(aShape, "ImportResult");
+ setResult(aResultBody, aResultIndex++);
+ }
+ removeResults(aResultIndex);
+}
+
+bool FeaturesPlugin_ValidatorImportResults::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>&, Events_InfoMessage& theError) const
+{
+ AttributeSelectionListPtr aList =
+ std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+ if (aList->size() == 0) {
+ // LCOV_EXCL_START
+ theError = "Please select sources.";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+ // store documents in the Part-fesatures in order to check
+ // the selection is located in the previous documents
+ std::map<DocumentPtr, int> aDocIndices;
+ DocumentPtr aRoot = ModelAPI_Session::get()->moduleDocument();
+ int aNum = aRoot->size(ModelAPI_Feature::group());
+ for (int a = 0; a < aNum; a++) {
+ FeaturePtr aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(
+ aRoot->object(ModelAPI_Feature::group(), a));
+ if (aFeat.get() && aFeat->data() && aFeat->data()->isValid() && aFeat->getKind() == "Part" &&
+ aFeat->results().size()) {
+ ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFeat->firstResult());
+ if (aPart.get() && aPart->partDoc()) {
+ aDocIndices[aPart->partDoc()] = a;
+ }
+ }
+ }
+ int aThisIndex = aDocIndices[aList->owner()->document()];
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ AttributeSelectionPtr aSel = aList->value(aSelIndex);
+ ResultPtr aContext = aSel->context();
+ if (!aContext.get()) {
+ // LCOV_EXCL_START
+ theError = "Empty context.";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+ GeomShapePtr aShape = aSel->value();
+ if (aShape.get() && !aShape->isNull() && !aShape->isSame(aContext->shape())) {
+ // LCOV_EXCL_START
+ theError = "Import results does not support selection of sub-shapes";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
+ if (!aBody.get()) {
+ // LCOV_EXCL_START
+ theError = "Only results may be selected.";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+ if (!aBody->shape()) {
+ // LCOV_EXCL_START
+ theError = "Result is empty.";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+ int aBodyIndex = aDocIndices[aBody->document()];
+ if (aBodyIndex >= aThisIndex) {
+ theError = "The selected result must be located in earlier part.";
+ return false;
+ }
+ }
+ return true;
+}
--- /dev/null
+// Copyright (C) 2017-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 FeaturesPlugin_ImportResult_H_
+#define FeaturesPlugin_ImportResult_H_
+
+#include "FeaturesPlugin.h"
+
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_AttributeValidator.h>
+
+/// \class FeaturesPlugin_ImportResult
+/// \ingroup Plugins
+/// \brief The Import Result feature allows the user to import one or several results
+/// from another Part.
+
+class FeaturesPlugin_ImportResult : public ModelAPI_Feature
+{
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("ImportResult");
+ return MY_ID;
+ }
+
+ /// \return the kind of a feature.
+ FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = FeaturesPlugin_ImportResult::ID();
+ return MY_KIND;
+ }
+
+ /// Selection list attribute that contains all copied shapes selection.
+ inline static const std::string& OBJECTS()
+ {
+ static const std::string MY_OBJECTS("objects");
+ return MY_OBJECTS;
+ }
+
+ /// Performs the algorithm and stores results it in the data structure.
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Request for initialization of data model of the feature: adding all attributes.
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Use plugin manager for features creation.
+ FeaturesPlugin_ImportResult() {}
+};
+
+/// \class FeaturesPlugin_ValidatorImportResults
+/// \ingroup Validators
+/// \brief A validator for selection of objects that may be imported:
+/// from another part, result bodies.
+class FeaturesPlugin_ValidatorImportResults : public ModelAPI_AttributeValidator
+{
+public:
+ //! \return True if selection is valid.
+ //! \param[in] theAttribute the checked attribute.
+ //! \param[in] theArguments arguments of the attribute.
+ //! \param[out] theError error message.
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments, Events_InfoMessage& theError) const;
+};
+
+#endif
aListOfRotationAlgo, aCompound, "Rotated");
setResult(aResultBody, aResultIndex);
+ aResultIndex++;
}
- aResultIndex++;
}
// Remove the rest results if there were produced in the previous pass.
loadNamingDS2(aListOfTranslationAlgo, aResultBody, aBaseShape);
loadNamingDS3(aListOfRotationAlgo, aResultBody, aBaseShape, nbRadial);
setResult(aResultBody, aResultIndex);
+ aResultIndex++;
}
- aResultIndex++;
}
// Remove the rest results if there were produced in the previous pass.
aListOfTranslationAlgo, aCompound, "Translated");
setResult(aResultBody, aResultIndex);
+ aResultIndex++;
}
- aResultIndex++;
}
// Remove the rest results if there were produced in the previous pass.
aListOfTranslationAlgo, aCompound, "Translated");
setResult(aResultBody, aResultIndex);
+ aResultIndex++;
}
- aResultIndex++;
}
// Remove the rest results if there were produced in the previous pass.
#include <FeaturesPlugin_BooleanSmash.h>
#include <FeaturesPlugin_BooleanFill.h>
#include <FeaturesPlugin_Chamfer.h>
+#include <FeaturesPlugin_Defeaturing.h>
#include <FeaturesPlugin_Extrusion.h>
#include <FeaturesPlugin_ExtrusionCut.h>
#include <FeaturesPlugin_ExtrusionFuse.h>
#include <FeaturesPlugin_Union.h>
#include <FeaturesPlugin_FusionFaces.h>
#include <FeaturesPlugin_RemoveResults.h>
+#include <FeaturesPlugin_Copy.h>
+#include <FeaturesPlugin_ImportResult.h>
#include <FeaturesPlugin_ValidatorTransform.h>
#include <FeaturesPlugin_Validators.h>
new FeaturesPlugin_ValidatorBooleanCommonSelection);
aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanCommonArguments",
new FeaturesPlugin_ValidatorBooleanCommonArguments);
+ aFactory->registerValidator("FeaturesPlugin_ValidatorImportResults",
+ new FeaturesPlugin_ValidatorImportResults);
+ aFactory->registerValidator("FeaturesPlugin_ValidatorDefeaturingSelection",
+ new FeaturesPlugin_ValidatorDefeaturingSelection);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new FeaturesPlugin_RemoveResults);
} else if (theFeatureID == FeaturesPlugin_Chamfer::ID()) {
return FeaturePtr(new FeaturesPlugin_Chamfer);
+ } else if (theFeatureID == FeaturesPlugin_Copy::ID()) {
+ return FeaturePtr(new FeaturesPlugin_Copy);
+ } else if (theFeatureID == FeaturesPlugin_ImportResult::ID()) {
+ return FeaturePtr(new FeaturesPlugin_ImportResult);
+ } else if (theFeatureID == FeaturesPlugin_Defeaturing::ID()) {
+ return FeaturePtr(new FeaturesPlugin_Defeaturing);
}
+
// feature of such kind is not found
return FeaturePtr();
}
return false;
}
// LCOV_EXCL_STOP
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorDefeaturingSelection::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.";
+ return false;
+ // LCOV_EXCL_STOP
+ }
+
+ // Check selected entities are sub-shapes of solid or compsolid
+ GeomShapePtr aBaseSolid;
+ for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
+ AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
+ if (!anAttrSelection.get()) {
+ theError = "Error: Empty attribute selection.";
+ return false;
+ }
+ ResultPtr aContext = anAttrSelection->context();
+ if (!aContext.get()) {
+ theError = "Error: Empty selection context.";
+ return false;
+ }
+
+ GeomShapePtr aContextShape = aContext->shape();
+ if (aContextShape->shapeType() != GeomAPI_Shape::SOLID) {
+ theError = "Error: Not all selected shapes are sub-shapes of solids.";
+ return false;
+ }
+ }
+
+ return true;
+}
virtual bool isNotObligatory(std::string theFeature, std::string theAttribute);
};
+/// \class FeaturesPlugin_ValidatorDefeaturingSelection
+/// \ingroup Validators
+/// \brief Validates selection for fillet operation.
+class FeaturesPlugin_ValidatorDefeaturingSelection : public ModelAPI_AttributeValidator
+{
+public:
+ /// \return True if the attribute is valid. It checks whether the selection
+ /// is acceptable for boolean operation.
+ /// \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;
+};
+
#endif
<source>Recover</source>
<translation>Récupérer</translation>
</message>
+ <message>
+ <source>Copy</source>
+ <translation>Copie</translation>
+ </message>
+ <message>
+ <source>Import Result</source>
+ <translation>Importer le résultat</translation>
+ </message>
<message>
<source>Remove Sub-Shapes</source>
<translation>Supprimer les sous-formes</translation>
</message>
</context>
+ <!-- Defeaturing -->
+ <context>
+ <name>Defeaturing</name>
+ <message>
+ <source>Defeaturing</source>
+ <translation>Vaincre</translation>
+ </message>
+ <message>
+ <source>Faces to remove</source>
+ <translation>Visages à retirer</translation>
+ </message>
+ <message>
+ <source>Select faces</source>
+ <translation>Sélectionnez des faces</translation>
+ </message>
+ </context>
+ <context>
+ <name>Defeaturing:FeaturesPlugin_ValidatorDefeaturingSelection</name>
+ <message>
+ <source>Error: This validator can only work with selection list attributes.</source>
+ <translation>Erreur: ce validateur ne peut fonctionner qu'avec des attributs de liste de sélection.</translation>
+ </message>
+ <message>
+ <source>Error: Empty attribute selection.</source>
+ <translation>La sélection d'attribut est vide.</translation>
+ </message>
+ <message>
+ <source>Error: Empty selection context.</source>
+ <translation>Erreur: contexte de sélection vide.</translation>
+ </message>
+ <message>
+ <source>Error: Not all selected shapes are sub-shapes of solids.</source>
+ <translation>Erreur: toutes les formes sélectionnées ne sont pas des sous-formes de solides.</translation>
+ </message>
+ </context>
+
<!-- Extrusion -->
<context>
<name>Extrusion</name>
</message>
</context>
+ <!-- Copy -->
+ <context>
+ <name>Copy</name>
+ <message>
+ <source>Copy</source>
+ <translation>Copie</translation>
+ </message>
+ <message>
+ <source>Copies results or sub-results</source>
+ <translation>Copie les résultats ou les sous-résultats</translation>
+ </message>
+ </context>
+ <context>
+ <name>Recover:objects</name>
+ <message>
+ <source>Sources:</source>
+ <translation>Sources:</translation>
+ </message>
+ <message>
+ <source>Select copied objects</source>
+ <translation>Sélectionnez les objets copiés</translation>
+ </message>
+ </context>
+ <context>
+ <name>Recover:number</name>
+ <message>
+ <source>Nb copies</source>
+ <translation>Nb de copies</translation>
+ </message>
+ <message>
+ <source>Number of copies</source>
+ <translation>Nombre de copies</translation>
+ </message>
+ </context>
+
+ <!-- Import result -->
+ <context>
+ <name>ImportResult</name>
+ <message>
+ <source>ImportResult</source>
+ <translation>Importer le résultat</translation>
+ </message>
+ <message>
+ <source>Copies results from other parts</source>
+ <translation>Copie les résultats d'autres pièces</translation>
+ </message>
+ </context>
+ <context>
+ <name>ImportResult:objects</name>
+ <message>
+ <source>Sources:</source>
+ <translation>Sources:</translation>
+ </message>
+ <message>
+ <source>Select copied results</source>
+ <translation>Sélectionnez les résultats copiés</translation>
+ </message>
+ </context>
+
<!-- Remove_SubShapes -->
<context>
<name>Remove_SubShapes</name>
<translation>Выберите вспомогательные объекты.</translation>
</message>
</context>
+
+ <!-- Defeaturing -->
+ <context>
+ <name>Defeaturing</name>
+ <message>
+ <source>Defeaturing</source>
+ <translation>Удаление фичеров</translation>
+ </message>
+ <message>
+ <source>Faces to remove</source>
+ <translation>Удаляемые грани</translation>
+ </message>
+ <message>
+ <source>Select faces</source>
+ <translation>Выберите грани</translation>
+ </message>
+ </context>
+ <context>
+ <name>Defeaturing:FeaturesPlugin_ValidatorDefeaturingSelection</name>
+ <message>
+ <source>Error: This validator can only work with selection list attributes.</source>
+ <translation>Ошибка: валидатор поддерживает только аттрибуты типа SelectionList.</translation>
+ </message>
+ <message>
+ <source>Error: Empty attribute selection.</source>
+ <translation>Ошибка: незаполненный аттрибут.</translation>
+ </message>
+ <message>
+ <source>Error: Empty selection context.</source>
+ <translation>Ошибка: пустой контекст.</translation>
+ </message>
+ <message>
+ <source>Error: Not all selected shapes are sub-shapes of solids.</source>
+ <translation>Ошибка: не все выбранные объекты являются подэлементами твердых тел.</translation>
+ </message>
+ </context>
</TS>
--- /dev/null
+# Copyright (C) 2019-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 GeomAPI import *
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(6.188, 9.028, 6.188, -3.45)
+SketchLine_2 = Sketch_1.addLine(6.188, -3.45, 0, -3.45)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(0, -3.45, 0, -6.45)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(0, -6.45, 7.782, -6.45)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(7.782, -6.45, 7.782, -3.45)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(7.782, -3.45, 6.538, -3.45)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(6.538, -3.45, 6.538, -2.4)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(6.538, -2.4, 6.376, -2.25)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(6.376, -2.25, 6.376, 9.028)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchLine_10 = Sketch_1.addLine(6.376, 9.028, 6.188, 9.028)
+SketchLine_10.setAuxiliary(True)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_10.endPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_10.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_9.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_2.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_11 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_3.startPoint(), SketchLine_11.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_5.result(), 3)
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Line(SketchLine_11).startPoint(), SketchLine_1.result(), 6.188, True)
+SketchConstraintVertical_5 = Sketch_1.setVertical(SketchLine_7.result())
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_12 = SketchProjection_2.createdFeature()
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_9.endPoint(), SketchLine_12.result(), 9.028, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchLine_2.startPoint(), SketchLine_9.result(), 0.188, True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_2.startPoint(), SketchLine_7.result(), 0.35, True)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_7.endPoint(), SketchLine_8.endPoint(), 0.15)
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchLine_5.endPoint(), SketchLine_12.result(), 3.45, True)
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchLine_8.endPoint(), SketchLine_12.result(), 2.25, True)
+SketchLine_13 = Sketch_1.addLine(7.032, -4.05, 5.532, -4.05)
+SketchLine_14 = Sketch_1.addLine(5.532, -4.05, 5.532, -5.85)
+SketchLine_15 = Sketch_1.addLine(5.532, -5.85, 7.032, -5.85)
+SketchLine_16 = Sketch_1.addLine(7.032, -5.85, 7.032, -4.05)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_16.endPoint(), SketchLine_13.startPoint())
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchLine_13.endPoint(), SketchLine_14.startPoint())
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchLine_14.endPoint(), SketchLine_15.startPoint())
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchLine_15.endPoint(), SketchLine_16.startPoint())
+SketchConstraintHorizontal_5 = Sketch_1.setHorizontal(SketchLine_13.result())
+SketchConstraintVertical_6 = Sketch_1.setVertical(SketchLine_14.result())
+SketchConstraintHorizontal_6 = Sketch_1.setHorizontal(SketchLine_15.result())
+SketchConstraintVertical_7 = Sketch_1.setVertical(SketchLine_16.result())
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_14.result(), 1.8)
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_15.result(), 1.5)
+SketchLine_17 = Sketch_1.addLine(6.282, -4.05, 6.282, 9.028)
+SketchLine_17.setAuxiliary(True)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_17.startPoint(), SketchLine_13.result())
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_10.result())
+SketchConstraintVertical_8 = Sketch_1.setVertical(SketchLine_17.result())
+SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchLine_17.startPoint(), SketchLine_13.result())
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchLine_17.startPoint(), SketchLine_5.result(), 1.5, True)
+SketchConstraintMiddle_2 = Sketch_1.setMiddlePoint(SketchLine_10.result(), SketchLine_17.endPoint())
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchLine_14.startPoint(), SketchLine_2.result(), 0.6, True)
+SketchLine_18 = Sketch_1.addLine(6.376, 9.028, 6.535, 9.187)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_18.startPoint())
+SketchLine_19 = Sketch_1.addLine(6.535, 9.187, 6.535, 10.256)
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_18.endPoint(), SketchLine_19.startPoint())
+SketchLine_20 = Sketch_1.addLine(6.535, 10.256, 6.185, 10.256)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_19.endPoint(), SketchLine_20.startPoint())
+SketchLine_21 = Sketch_1.addLine(6.185, 10.256, 4.9175, 10.94235984621998)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_20.endPoint(), SketchLine_21.startPoint())
+SketchConstraintHorizontal_7 = Sketch_1.setHorizontal(SketchLine_20.result())
+SketchConstraintVertical_9 = Sketch_1.setVertical(SketchLine_19.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_10.result(), SketchLine_18.result(), 45, type = "Supplementary")
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_20.result(), 0.35)
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchLine_19.endPoint(), SketchLine_12.result(), 10.256, True)
+SketchArc_1 = Sketch_1.addArc(0, 2.425, 4.9175, 10.94235984621998, 0, 12.26, False)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_11.result(), SketchArc_1.center())
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchLine_21.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchLine_11.result(), SketchArc_1.endPoint())
+SketchLine_22 = Sketch_1.addLine(6.188, 9.028, 6.082, 9.532)
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_22.startPoint())
+SketchArc_2 = Sketch_1.addArc(4.79378612024245, 9.263, 6.082, 9.532, 5.676067550792229, 10.23944020672391, False)
+SketchConstraintCoincidence_27 = Sketch_1.setCoincident(SketchLine_22.endPoint(), SketchArc_2.startPoint())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_2.results()[1], 1.316)
+SketchConstraintDistance_10 = Sketch_1.setDistance(SketchArc_2.startPoint(), SketchLine_1.result(), 0.106, True)
+SketchLine_23 = Sketch_1.addLine(5.676067550792229, 10.23944020672391, 5.405090045827156, 10.43837553323928)
+SketchConstraintCoincidence_28 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_23.startPoint())
+SketchLine_24 = Sketch_1.addLine(5.405090045827156, 10.43837553323928, 5.126644475052085, 10.62934617154252)
+SketchConstraintCoincidence_29 = Sketch_1.setCoincident(SketchLine_23.endPoint(), SketchLine_24.startPoint())
+SketchLine_25 = Sketch_1.addLine(5.126644475052085, 10.62934617154252, 4.8355, 10.80033167999934)
+SketchConstraintCoincidence_30 = Sketch_1.setCoincident(SketchLine_24.endPoint(), SketchLine_25.startPoint())
+SketchArc_3 = Sketch_1.addArc(0, 2.425, 4.8355, 10.80033167999934, 0, 12.096, False)
+SketchConstraintCoincidence_31 = Sketch_1.setCoincident(SketchLine_11.result(), SketchArc_3.center())
+SketchConstraintCoincidence_32 = Sketch_1.setCoincident(SketchLine_25.endPoint(), SketchArc_3.startPoint())
+SketchConstraintCoincidence_33 = Sketch_1.setCoincident(SketchLine_11.result(), SketchArc_3.endPoint())
+SketchLine_26 = Sketch_1.addLine(0, 12.096, 0, 12.26)
+SketchConstraintCoincidence_34 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_26.startPoint())
+SketchConstraintCoincidence_35 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_26.endPoint())
+SketchConstraintDistance_11 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_12.result(), 2.425, True)
+SketchConstraintCoincidence_36 = Sketch_1.setCoincident(SketchArc_3.center(), SketchArc_1.center())
+SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_26.result(), 0.164)
+SketchLine_27 = Sketch_1.addLine(0, 2.425, 4.9175, 10.94235984621998)
+SketchLine_27.setAuxiliary(True)
+SketchConstraintCoincidence_37 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_27.startPoint())
+SketchConstraintCoincidence_38 = Sketch_1.setCoincident(SketchLine_21.endPoint(), SketchLine_27.endPoint())
+SketchConstraintCoincidence_39 = Sketch_1.setCoincident(SketchArc_3.startPoint(), SketchLine_27.result())
+SketchLine_28 = Sketch_1.addLine(0, 2.425, 5.21991026555713, 10.77860263646605)
+SketchLine_28.setAuxiliary(True)
+SketchConstraintCoincidence_40 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_28.startPoint())
+SketchConstraintCoincidence_41 = Sketch_1.setCoincident(SketchLine_28.endPoint(), SketchLine_21.result())
+SketchConstraintCoincidence_42 = Sketch_1.setCoincident(SketchLine_28.result(), SketchLine_25.startPoint())
+SketchLine_29 = Sketch_1.addLine(0, 2.425, 5.523638941362955, 10.61413149862094)
+SketchLine_29.setAuxiliary(True)
+SketchConstraintCoincidence_43 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_29.startPoint())
+SketchConstraintCoincidence_44 = Sketch_1.setCoincident(SketchLine_29.endPoint(), SketchLine_21.result())
+SketchConstraintCoincidence_45 = Sketch_1.setCoincident(SketchLine_29.result(), SketchLine_24.startPoint())
+SketchConstraintDistance_12 = Sketch_1.setDistance(SketchLine_25.startPoint(), SketchLine_28.endPoint(), 0.176, True)
+SketchConstraintDistance_13 = Sketch_1.setDistance(SketchLine_24.startPoint(), SketchLine_29.endPoint(), 0.212, True)
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_28.result(), SketchLine_11.result(), 32, type = "Direct")
+SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_29.result(), SketchLine_11.result(), 34, type = "Direct")
+SketchConstraintAngle_4 = Sketch_1.setAngle(SketchLine_27.result(), SketchLine_11.result(), 30, type = "Direct")
+SketchLine_30 = Sketch_1.addLine(4.79378612024245, 9.263, 5.676067550792229, 10.23944020672391)
+SketchLine_30.setAuxiliary(True)
+SketchConstraintCoincidence_46 = Sketch_1.setCoincident(SketchArc_2.center(), SketchLine_30.startPoint())
+SketchConstraintCoincidence_47 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_30.endPoint())
+SketchLine_31 = Sketch_1.addLine(4.79378612024245, 9.263, 4.79378612024245, 10.72808112087839)
+SketchLine_31.setAuxiliary(True)
+SketchConstraintCoincidence_48 = Sketch_1.setCoincident(SketchArc_2.center(), SketchLine_31.startPoint())
+SketchConstraintVertical_10 = Sketch_1.setVertical(SketchLine_31.result())
+SketchConstraintAngle_5 = Sketch_1.setAngle(SketchLine_30.result(), SketchLine_31.result(), 42.1, type = "Direct")
+SketchConstraintDistance_14 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_12.result(), 9.263, True)
+SketchConstraintCoincidence_49 = Sketch_1.setCoincident(SketchLine_31.endPoint(), SketchLine_27.result())
+SketchConstraintDistance_15 = Sketch_1.setDistance(SketchLine_22.endPoint(), SketchLine_12.result(), 9.532, True)
+SketchConstraintDistance_16 = Sketch_1.setDistance(SketchLine_18.endPoint(), SketchLine_12.result(), 9.187, True)
+SketchConstraintRadius_2 = Sketch_1.setRadius(SketchArc_1.results()[1], 9.835)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", (3.891, 0, 2.905000000000017))], model.selection("EDGE", "PartSet/OZ"), 360, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchProjection_3 = Sketch_2.addProjection(model.selection("VERTEX_5", (0, 0, 2.425)), False)
+SketchPoint_1 = SketchProjection_3.createdFeature()
+SketchProjection_4 = Sketch_2.addProjection(model.selection("EDGE", (0, 0, 12.178)), False)
+SketchLine_32 = SketchProjection_4.createdFeature()
+SketchArc_4 = Sketch_2.addArc(0, 2.425, 0, 12.178, 5.453808387550563, 10.51060344512907, True)
+SketchArc_4.setAuxiliary(True)
+SketchConstraintCoincidence_50 = Sketch_2.setCoincident(SketchPoint_1.result(), SketchArc_4.center())
+SketchConstraintCoincidence_51 = Sketch_2.setCoincident(SketchLine_32.result(), SketchArc_4.startPoint())
+SketchProjection_5 = Sketch_2.addProjection(model.selection("EDGE", (2.761819470681477, 0, 6.519565749310471)), False)
+SketchLine_33 = SketchProjection_5.createdFeature()
+SketchConstraintCoincidence_52 = Sketch_2.setCoincident(SketchArc_4.endPoint(), SketchLine_33.result())
+SketchConstraintMiddle_3 = Sketch_2.setMiddlePoint(SketchArc_4.startPoint(), SketchLine_32.result())
+SketchLine_34 = Sketch_2.addLine(0, 2.425, 3.282538500974084, 11.74164236673399)
+SketchLine_34.setAuxiliary(True)
+SketchConstraintCoincidence_53 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_34.startPoint())
+SketchLine_35 = Sketch_2.addLine(3.282538500974084, 11.74164236673399, 3.199461499025965, 11.50584963625379)
+SketchConstraintCoincidence_54 = Sketch_2.setCoincident(SketchLine_34.endPoint(), SketchLine_35.startPoint())
+SketchConstraintCoincidence_55 = Sketch_2.setCoincident(SketchLine_35.endPoint(), SketchLine_34.result())
+SketchConstraintLength_6 = Sketch_2.setLength(SketchLine_35.result(), 0.25)
+SketchPoint_2 = Sketch_2.addPoint(3.241, 11.6237460014939)
+SketchConstraintCoincidence_56 = Sketch_2.setCoincident(SketchPoint_2.coordinates(), SketchArc_4.results()[1])
+SketchConstraintCoincidence_57 = Sketch_2.setCoincident(SketchPoint_2.coordinates(), SketchLine_35.result())
+SketchProjection_6 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_36 = SketchProjection_6.createdFeature()
+SketchConstraintDistance_17 = Sketch_2.setDistance(SketchPoint_2.coordinates(), SketchLine_36.result(), 3.241, True)
+SketchArc_5 = Sketch_2.addArc(0, 2.425, 3.282538500974084, 11.74164236673399, 4.1398177019328, 11.393656164374, True)
+SketchConstraintCoincidence_58 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchArc_5.center())
+SketchConstraintCoincidence_59 = Sketch_2.setCoincident(SketchLine_34.endPoint(), SketchArc_5.startPoint())
+SketchArc_6 = Sketch_2.addArc(0, 2.425, 3.199461499025965, 11.50584963625379, 4.035044020470642, 11.16667053559353, True)
+SketchConstraintCoincidence_60 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_33).startPoint(), SketchArc_6.center())
+SketchConstraintCoincidence_61 = Sketch_2.setCoincident(SketchLine_35.endPoint(), SketchArc_6.startPoint())
+SketchLine_37 = Sketch_2.addLine(0, 2.425, 3.911506014428326, 11.49555702253677)
+SketchLine_37.setAuxiliary(True)
+SketchConstraintCoincidence_62 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_37.startPoint())
+SketchConstraintCoincidence_63 = Sketch_2.setCoincident(SketchLine_37.endPoint(), SketchArc_5.results()[1])
+SketchLine_38 = Sketch_2.addLine(0, 2.425, 4.1398177019328, 11.393656164374)
+SketchLine_38.setAuxiliary(True)
+SketchConstraintCoincidence_64 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_38.startPoint())
+SketchConstraintCoincidence_65 = Sketch_2.setCoincident(SketchArc_5.endPoint(), SketchLine_38.endPoint())
+SketchConstraintCoincidence_66 = Sketch_2.setCoincident(SketchArc_6.endPoint(), SketchLine_38.result())
+SketchConstraintDistance_18 = Sketch_2.setDistance(SketchLine_35.startPoint(), SketchLine_37.result(), 0.675, True)
+SketchConstraintMiddle_4 = Sketch_2.setMiddlePoint(SketchPoint_2.coordinates(), SketchLine_35.result())
+SketchLine_39 = Sketch_2.addLine(3.911506014428326, 11.49555702253677, 3.81251062025875, 11.26599240868435)
+SketchConstraintCoincidence_67 = Sketch_2.setCoincident(SketchLine_37.endPoint(), SketchLine_39.startPoint())
+SketchConstraintCoincidence_68 = Sketch_2.setCoincident(SketchLine_39.endPoint(), SketchArc_6.results()[1])
+SketchConstraintCoincidence_69 = Sketch_2.setCoincident(SketchLine_39.endPoint(), SketchLine_37.result())
+SketchLine_40 = Sketch_2.addLine(4.1398177019328, 11.393656164374, 4.459277785066647, 11.19096067956113)
+SketchConstraintCoincidence_70 = Sketch_2.setCoincident(SketchArc_5.endPoint(), SketchLine_40.startPoint())
+SketchProjection_7 = Sketch_2.addProjection(model.selection("EDGE_3", (2.545485308583308, 0, 11.92488050155302)), False)
+SketchArc_7 = SketchProjection_7.createdFeature()
+SketchConstraintCoincidence_71 = Sketch_2.setCoincident(SketchLine_40.endPoint(), SketchArc_7.results()[1])
+SketchLine_41 = Sketch_2.addLine(4.459277785066647, 11.19096067956113, 4.390495384356095, 11.04194790978503)
+SketchConstraintCoincidence_72 = Sketch_2.setCoincident(SketchLine_40.endPoint(), SketchLine_41.startPoint())
+SketchProjection_8 = Sketch_2.addProjection(model.selection("EDGE_3", (2.503038985186497, 0, 11.76646866604162)), False)
+SketchArc_8 = SketchProjection_8.createdFeature()
+SketchConstraintCoincidence_73 = Sketch_2.setCoincident(SketchLine_41.endPoint(), SketchArc_8.results()[1])
+SketchLine_42 = Sketch_2.addLine(4.390495384356095, 11.04194790978503, 4.035044020470642, 11.16667053559353)
+SketchConstraintCoincidence_74 = Sketch_2.setCoincident(SketchLine_41.endPoint(), SketchLine_42.startPoint())
+SketchConstraintCoincidence_75 = Sketch_2.setCoincident(SketchLine_42.endPoint(), SketchLine_38.result())
+SketchConstraintCoincidence_76 = Sketch_2.setCoincident(SketchLine_42.endPoint(), SketchArc_6.endPoint())
+SketchConstraintDistance_19 = Sketch_2.setDistance(SketchArc_5.endPoint(), SketchLine_41.result(), 0.375, True)
+SketchConstraintDistance_20 = Sketch_2.setDistance(SketchLine_39.startPoint(), SketchLine_38.result(), 0.25, True)
+SketchConstraintParallel_1 = Sketch_2.setParallel(SketchLine_41.result(), SketchLine_38.result())
+model.do()
+Revolution_2 = model.addRevolution(Part_1_doc, [model.selection("WIRE", (3.862008317343538, 0, 11.38077471561056))], model.selection("EDGE", (3.241000000000025, 0, 11.62374600149389)), 360, 0)
+Revolution_3 = model.addRevolution(Part_1_doc, [model.selection("WIRE", (4.212769702413368, 0, 11.10430922268928))], model.selection("EDGE", (3.241000000000025, 0, 11.62374600149389)), 360, 0)
+Symmetry_1 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", (3.237001631529592, 7.752869270149964e-17, 11.61239765963003)), model.selection("SOLID", (3.223059230627338, 1.806177914907969e-16, 11.57282573597984))], model.selection("FACE", "PartSet/YOZ"), True)
+Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", (9.171993615882458e-05, 1.467829010982793e-16, 1.298864381774082))], [model.selection("COMPOUND", (0, 0, 11.60508262087049))])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", (9.190387067667382e-05, -2.335384201710612e-09, 1.278348504308934)), model.selection("COMPOUND", (0, 0, 11.54608275997197))], removeEdges = True)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), 3.6, False)
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", (0, 0, 3.6)))
+SketchProjection_9 = Sketch_3.addProjection(model.selection("EDGE", (-6.188, 7.578114393123822e-16, -3.45)), True)
+SketchCircle_1 = SketchProjection_9.createdFeature()
+SketchProjection_10 = Sketch_3.addProjection(model.selection("EDGE", (-6.376, 7.808347991363525e-16, -2.25)), True)
+SketchCircle_2 = SketchProjection_10.createdFeature()
+SketchArc_9 = Sketch_3.addArc(0, 0, 6.094, 0, 5.859569950090201, -1.674, True)
+SketchConstraintCoincidence_77 = Sketch_3.setCoincident(SketchAPI_Circle(SketchCircle_1).center(), SketchArc_9.center())
+SketchProjection_11 = Sketch_3.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_43 = SketchProjection_11.createdFeature()
+SketchConstraintCoincidence_78 = Sketch_3.setCoincident(SketchArc_9.startPoint(), SketchLine_43.result())
+SketchPoint_3 = Sketch_3.addPoint(6.188, 0)
+SketchConstraintCoincidence_79 = Sketch_3.setCoincident(SketchPoint_3.coordinates(), SketchLine_43.result())
+SketchConstraintCoincidence_80 = Sketch_3.setCoincident(SketchPoint_3.coordinates(), SketchCircle_1.results()[1])
+SketchConstraintDistance_21 = Sketch_3.setDistance(SketchArc_9.startPoint(), SketchPoint_3.coordinates(), 0.094, True)
+SketchConstraintDistance_22 = Sketch_3.setDistance(SketchArc_9.endPoint(), SketchLine_43.result(), 1.674, True)
+SketchLine_44 = Sketch_3.addLine(5.859569950090201, -1.674, 5.870724657144867, -1.956)
+SketchConstraintCoincidence_81 = Sketch_3.setCoincident(SketchArc_9.endPoint(), SketchLine_44.startPoint())
+SketchConstraintCoincidence_82 = Sketch_3.setCoincident(SketchLine_44.endPoint(), SketchCircle_1.results()[1])
+SketchArc_10 = Sketch_3.addArc(0, 0, 6.47, 0, 6.167249305809295, -1.956, True)
+SketchConstraintCoincidence_83 = Sketch_3.setCoincident(SketchAPI_Circle(SketchCircle_1).center(), SketchArc_10.center())
+SketchConstraintCoincidence_84 = Sketch_3.setCoincident(SketchLine_43.result(), SketchArc_10.startPoint())
+SketchLine_45 = Sketch_3.addLine(6.167249305809295, -1.956, 6.068561608816571, -1.956)
+SketchConstraintCoincidence_85 = Sketch_3.setCoincident(SketchArc_10.endPoint(), SketchLine_45.startPoint())
+SketchConstraintCoincidence_86 = Sketch_3.setCoincident(SketchLine_45.endPoint(), SketchCircle_2.results()[1])
+SketchConstraintHorizontal_8 = Sketch_3.setHorizontal(SketchLine_45.result())
+SketchConstraintCoincidence_87 = Sketch_3.setCoincident(SketchLine_44.endPoint(), SketchLine_45.result())
+SketchConstraintDistance_23 = Sketch_3.setDistance(SketchArc_10.startPoint(), SketchLine_45.result(), 1.956, True)
+SketchPoint_4 = Sketch_3.addPoint(6.376, 0)
+SketchConstraintCoincidence_88 = Sketch_3.setCoincident(SketchPoint_4.coordinates(), SketchCircle_2.results()[1])
+SketchConstraintCoincidence_89 = Sketch_3.setCoincident(SketchPoint_4.coordinates(), SketchLine_43.result())
+SketchConstraintDistance_24 = Sketch_3.setDistance(SketchPoint_4.coordinates(), SketchArc_10.startPoint(), 0.094, True)
+SketchConstraintMirror_1_objects = [SketchArc_9.results()[1], SketchLine_44.result(), SketchArc_10.results()[1], SketchLine_45.result()]
+SketchConstraintMirror_1 = Sketch_3.addMirror(SketchLine_43.result(), SketchConstraintMirror_1_objects)
+[SketchArc_11, SketchLine_46, SketchArc_12, SketchLine_47] = SketchConstraintMirror_1.mirrored()
+model.do()
+Sketch_3.changeFacesOrder([[SketchProjection_9.result(), SketchProjection_9.result(), SketchLine_46.result(), SketchArc_11.results()[1], SketchArc_9.results()[1], SketchLine_44.result()],
+ [SketchProjection_10.result(), SketchProjection_10.result(), SketchProjection_10.result(), SketchProjection_9.result(), SketchProjection_9.result(), SketchProjection_9.result()],
+ [SketchProjection_9.result(), SketchLine_44.result(), SketchArc_9.results()[1], SketchArc_11.results()[1], SketchLine_46.result()],
+ [SketchProjection_10.result(), SketchLine_45.result(), SketchArc_10.results()[1], SketchArc_12.results()[1], SketchLine_47.result(), SketchProjection_10.result()]
+ ])
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", (6.023784975045098, 0, 3.6)), model.selection("WIRE", (6.393864363926704, 0.9896456414839456, 3.6))], model.selection(), 0, 4.2)
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchLine_48 = Sketch_4.addLine(0.75, 2.1, -0.75, 2.1)
+SketchLine_49 = Sketch_4.addLine(-0.75, 2.1, -0.75, 0.3)
+SketchLine_50 = Sketch_4.addLine(-0.75, 0.3, 0.75, 0.3)
+SketchLine_51 = Sketch_4.addLine(0.75, 0.3, 0.75, 2.1)
+SketchConstraintCoincidence_90 = Sketch_4.setCoincident(SketchLine_51.endPoint(), SketchLine_48.startPoint())
+SketchConstraintCoincidence_91 = Sketch_4.setCoincident(SketchLine_48.endPoint(), SketchLine_49.startPoint())
+SketchConstraintCoincidence_92 = Sketch_4.setCoincident(SketchLine_49.endPoint(), SketchLine_50.startPoint())
+SketchConstraintCoincidence_93 = Sketch_4.setCoincident(SketchLine_50.endPoint(), SketchLine_51.startPoint())
+SketchConstraintHorizontal_9 = Sketch_4.setHorizontal(SketchLine_48.result())
+SketchConstraintVertical_11 = Sketch_4.setVertical(SketchLine_49.result())
+SketchConstraintHorizontal_10 = Sketch_4.setHorizontal(SketchLine_50.result())
+SketchConstraintVertical_12 = Sketch_4.setVertical(SketchLine_51.result())
+SketchProjection_12 = Sketch_4.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_52 = SketchProjection_12.createdFeature()
+SketchConstraintDistance_25 = Sketch_4.setDistance(SketchLine_52.result(), SketchLine_50.endPoint(), 0.3, True)
+SketchConstraintDistance_26 = Sketch_4.setDistance(SketchLine_51.endPoint(), SketchLine_52.result(), 2.1, True)
+SketchPoint_5 = Sketch_4.addPoint(0, 2.1)
+SketchConstraintCoincidence_94 = Sketch_4.setCoincident(SketchPoint_5.coordinates(), SketchLine_48.result())
+SketchConstraintMiddle_5 = Sketch_4.setMiddlePoint(SketchLine_48.result(), SketchPoint_5.coordinates())
+SketchProjection_13 = Sketch_4.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_53 = SketchProjection_13.createdFeature()
+SketchConstraintCoincidence_95 = Sketch_4.setCoincident(SketchPoint_5.coordinates(), SketchLine_53.result())
+SketchConstraintDistance_27 = Sketch_4.setDistance(SketchPoint_5.coordinates(), SketchLine_51.endPoint(), 0.75, True)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", (0, 0, 1.2))], model.selection(), 10, 0)
+Rotation_1_objects = [model.selection("SOLID", (5, 1.166200656118862e-18, 1.2)), model.selection("SOLID", (6.038396788450424, -2.054057850558325e-15, 1.5)), model.selection("SOLID", (6.316150725419533, -7.758519898162708e-14, 1.5))]
+Rotation_1 = model.addRotation(Part_1_doc, Rotation_1_objects, model.selection("EDGE", "PartSet/OZ"), -90)
+Fuse_2_objects_1 = [model.selection("SOLID", (9.187239971515918e-05, -6.832080613557312e-09, 1.282177819724956)), model.selection("SOLID", (-1.349638054860434e-15, -6.038396788450424, 1.5)), model.selection("SOLID", (-7.680624658573511e-14, -6.316150725419533, 1.5))]
+Fuse_2 = model.addFuse(Part_1_doc, Fuse_2_objects_1)
+Cut_2 = model.addCut(Part_1_doc, [model.selection("SOLID", (9.177890659903279e-05, -0.006341145656800184, 1.28239948002437))], [model.selection("SOLID", (6.393306363619619e-16, -4.999999999999998, 1.2))])
+FusionFaces_1 = model.addFusionFaces(Part_1_doc, model.selection("SOLID", (9.190526314899106e-05, 0.002297421001363739, 1.282512923455053)))
+
+model.end()
+
+model.testNbResults(FusionFaces_1, 1)
+model.testNbSubResults(FusionFaces_1, [0])
+model.testNbSubShapes(FusionFaces_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(FusionFaces_1, GeomAPI_Shape.FACE, [47])
+model.testNbSubShapes(FusionFaces_1, GeomAPI_Shape.EDGE, [202])
+model.testNbSubShapes(FusionFaces_1, GeomAPI_Shape.VERTEX, [404])
+model.testResultsVolumes(FusionFaces_1, [612.7268292882])
+
+assert(model.checkPythonDump())
\ No newline at end of file
--- /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()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 20, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(15.15541180270434, 24.41800127226657, 10.26187655283108)
+Extrusion_1.setNestedSketch(Sketch_1)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Extrusion_2 = model.addExtrusion(Part_2_doc, [], model.selection(), 10, 0)
+Sketch_2 = model.addSketch(Part_2_doc, model.defaultPlane("YOZ"))
+SketchLine_1 = Sketch_2.addLine(-19.91316598300577, 19.16479847747027, -37.02832010642763, 19.16479847747027)
+SketchLine_2 = Sketch_2.addLine(-37.02832010642763, 19.16479847747027, -37.02832010642763, 36.27995260089213)
+SketchLine_3 = Sketch_2.addLine(-37.02832010642763, 36.27995260089213, -19.91316598300577, 36.27995260089213)
+SketchLine_4 = Sketch_2.addLine(-19.91316598300577, 36.27995260089213, -19.91316598300577, 19.16479847747027)
+SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_2.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_2.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_4.result(), SketchLine_3.result())
+Extrusion_2.setNestedSketch(Sketch_2)
+model.do()
+
+LinearCopy_1 = model.addMultiTranslation(partSet, [model.selection("COMPOUND", "Part_1/"), model.selection("COMPOUND", "Part_2/")], model.selection("EDGE", "OX"), 50, 2)
+LinearCopy_2_objects = [model.selection("COMPOUND", "LinearCopy_1/"), model.selection("COMPOUND", "LinearCopy_1_2/"), model.selection("COMPOUND", "LinearCopy_1_3/"), model.selection("COMPOUND", "LinearCopy_1_4/")]
+LinearCopy_2 = model.addMultiTranslation(partSet, LinearCopy_2_objects, model.selection("EDGE", "OY"), 30, 2, model.selection("EDGE", "OZ"), 25, 2)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(LinearCopy_2, 16)
+model.testNbSubResults(LinearCopy_2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+model.testNbSubShapes(LinearCopy_2, GeomAPI_Shape.SOLID, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
+model.testNbSubShapes(LinearCopy_2, GeomAPI_Shape.FACE, [3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6])
+model.testNbSubShapes(LinearCopy_2, GeomAPI_Shape.EDGE, [6, 6, 6, 6, 6, 6, 6, 6, 24, 24, 24, 24, 24, 24, 24, 24])
+model.testNbSubShapes(LinearCopy_2, GeomAPI_Shape.VERTEX, [12, 12, 12, 12, 12, 12, 12, 12, 48, 48, 48, 48, 48, 48, 48, 48])
+model.testResultsVolumes(LinearCopy_2, [6616.5780553, 6616.5780553, 6616.5780553, 6616.5780553, 6616.5780553, 6616.5780553, 6616.5780553, 6616.5780553, 2929.285, 2929.285, 2929.285, 2929.285, 2929.285, 2929.285, 2929.285, 2929.285])
--- /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()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 20, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(15.15541180270434, 24.41800127226657, 10.26187655283108)
+Extrusion_1.setNestedSketch(Sketch_1)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Extrusion_2 = model.addExtrusion(Part_2_doc, [], model.selection(), 10, 0)
+Sketch_2 = model.addSketch(Part_2_doc, model.defaultPlane("YOZ"))
+SketchLine_1 = Sketch_2.addLine(-19.91316598300577, 19.16479847747027, -37.02832010642763, 19.16479847747027)
+SketchLine_2 = Sketch_2.addLine(-37.02832010642763, 19.16479847747027, -37.02832010642763, 36.27995260089213)
+SketchLine_3 = Sketch_2.addLine(-37.02832010642763, 36.27995260089213, -19.91316598300577, 36.27995260089213)
+SketchLine_4 = Sketch_2.addLine(-19.91316598300577, 36.27995260089213, -19.91316598300577, 19.16479847747027)
+SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_2.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_2.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_4.result(), SketchLine_3.result())
+Extrusion_2.setNestedSketch(Sketch_2)
+model.do()
+
+AngularCopy_1 = model.addMultiRotation(partSet, [model.selection("COMPOUND", "Part_1/"), model.selection("COMPOUND", "Part_2/")], model.selection("EDGE", "OZ"), 90, 2)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(AngularCopy_1, 4)
+model.testNbSubResults(AngularCopy_1, [0, 0, 0, 0])
+model.testNbSubShapes(AngularCopy_1, GeomAPI_Shape.SOLID, [1, 1, 1, 1])
+model.testNbSubShapes(AngularCopy_1, GeomAPI_Shape.FACE, [3, 3, 6, 6])
+model.testNbSubShapes(AngularCopy_1, GeomAPI_Shape.EDGE, [6, 6, 24, 24])
+model.testNbSubShapes(AngularCopy_1, GeomAPI_Shape.VERTEX, [12, 12, 48, 48])
+model.testResultsVolumes(AngularCopy_1, [6616.5780553, 6616.5780553, 2929.285, 2929.285])
--- /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
+#
+
+# Checks selection of the whole featurte and move to the end of the group created on results of this feature..
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(11.02869497636673, 9.8764247475525, 3.312248077480665)
+SketchCircle_2 = Sketch_1.addCircle(4.278198729238611, 4.677840612715367, 1.794922837237287)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_1"), model.selection("SOLID", "Extrusion_1_2")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_1")], 1)
+model.do()
+# move the group feature to the end - through copy of the whole feature
+Part_1_doc.moveFeature(Group_1.feature(), Copy_1.feature())
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 4) # two original solids plus two copies
+assert(selectionList.value(3).namingName() == "Extrusion_1_1_1_1")
+assert(selectionList.value(2).namingName() == "Extrusion_1_1_1_2")
+
+assert(model.checkPythonDump())
--- /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
+#
+
+# Checks selection of the whole featurte and move to the end of the group created on this feature..
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(11.02869497636673, 9.8764247475525, 3.312248077480665)
+SketchCircle_2 = Sketch_1.addCircle(4.278198729238611, 4.677840612715367, 1.794922837237287)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_1")], 1)
+model.do()
+# move the group feature to the end - through copy of the whole feature
+Part_1_doc.moveFeature(Group_1.feature(), Copy_1.feature())
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 2) # two: original feature and the copy-feature
+assert(selectionList.value(0).namingName() == "all-in-Extrusion_1")
+assert(selectionList.value(1).namingName() == "all-in-Copy_1")
+
+assert(model.checkPythonDump())
--- /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
+#
+
+# Checks selection of the whole shape and move to the end of the simple copy wihtout the
+# next modifications applied.
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(38.31034482758622, 31.49775664633739, 7.836206896551726, 31.49775664633739)
+SketchLine_2 = Sketch_1.addLine(7.836206896551726, 31.49775664633739, 7.836206896551726, 8.984209848307833)
+SketchLine_3 = Sketch_1.addLine(7.836206896551726, 8.984209848307833, 38.31034482758622, 8.984209848307833)
+SketchLine_4 = Sketch_1.addLine(38.31034482758622, 8.984209848307833, 38.31034482758622, 31.49775664633739)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(21.64285714285715, 31.4977566463374, 25.0012315270936, 8.984209848307833)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_3.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_5r"), model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_5f-SketchLine_3f-SketchLine_4f")], model.selection(), 7, 0)
+Extrusion_1.result().setName("Origin")
+Group_1 = model.addGroup(Part_1_doc, "Solids", [model.selection("SOLID", "Extrusion_1_1_1")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPSOLID", "Origin")], 1)
+Copy_1.result().setName("Origin_1")
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Origin_1_1/Copy_3][Origin_1_1/Copy_7]"), model.selection("EDGE", "[Origin_1_1/Copy_12][Origin_1_1/Copy_14]")], 2)
+Fillet_1.result().setName("CopyCompound")
+model.do()
+# move the group feature to the end - through copy and fillet on this copy (to distinguish the origin and the copy)
+Part_1_doc.moveFeature(Group_1.feature(), Fillet_1.feature())
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 2) # still the same solid + the copied and filleted
+
+assert(selectionList.value(0).namingName() == "Extrusion_1_1_1")
+assert(selectionList.value(1).namingName() == "Fillet_1_1_1")
+
+assert(model.checkPythonDump())
--- /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
+#
+
+# Checks selection of the sub-shapes move to the end with combination of 2 Copy features in history
+
+from salome.shaper import model
+from ModelAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Group_1 = model.addGroup(Part_1_doc, "Edges", [model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]")])
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("FACE", "Box_1_1/Front")], 2)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 5, [model.selection("SOLID", "Box_1_1")])
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Front"))
+SketchCircle_1 = Sketch_1.addCircle(9.650212071680357, 9.344990586582618, 1.565166813054581)
+ExtrusionCut_1.setNestedSketch(Sketch_1)
+ExtrusionCut_1.result().setColor(225, 0, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1_1"))
+SketchCircle_2 = Sketch_2.addCircle(0.7603686814133139, 9.06793355634084, 1.630854194501576)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_2_2r")])
+Cut_1 = model.addCut(Part_1_doc, [model.selection("FACE", "Box_1_1_1")], [model.selection("FACE", "Face_1_1")], keepSubResults = True)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("FACE", "Box_1_1_2")], model.selection("EDGE", "PartSet/OX"), 5)
+Copy_2 = model.addCopy(Part_1_doc, [model.selection("FACE", "Box_1_1_2")], 2)
+Rotation_1 = model.addRotation(Part_1_doc, [model.selection("FACE", "Box_1_1_2_1")], model.selection("EDGE", "PartSet/OZ"), 10)
+Rotation_2 = model.addRotation(Part_1_doc, [model.selection("FACE", "Box_1_1_2_2")], model.selection("EDGE", "PartSet/OZ"), 20)
+model.do()
+# move the group feature to the end - through 2 copies and many modifications of the selected edge
+Part_1_doc.moveFeature(Group_1.feature(), Rotation_2.feature())
+model.end()
+
+# result is 5 edges: cut, translation, 2 rotations, extrusion cut
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Group_1.feature()))
+selectionList = Group_1.feature().selectionList("group_list")
+assert(selectionList.size() == 5)
+
+assert(model.checkPythonDump())
--- /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
+#
+
+# Checks that the Copy feature produces correct names, same as in the description #3109
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-11.9408866995074, 14.67733990147784, -29.35467980295567, 14.67733990147784)
+SketchLine_2 = Sketch_1.addLine(-29.35467980295567, 14.67733990147784, -29.35467980295567, -7.960591133004924)
+SketchLine_3 = Sketch_1.addLine(-29.35467980295567, -7.960591133004924, -11.9408866995074, -7.960591133004924)
+SketchLine_4 = Sketch_1.addLine(-11.9408866995074, -7.960591133004924, -11.9408866995074, 14.67733990147784)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchCircle_1 = Sketch_1.addCircle(14.92610837438425, 16.04556650246306, 6.602917012013241)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 10, 0)
+Extrusion_1.result().setName("Box")
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 10, 0)
+Extrusion_2.result().setName("Cylinder")
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("SOLID", "Box"), model.selection("SOLID", "Cylinder")], 3)
+model.end()
+
+assert(Copy_1.feature().results().size() == 6)
+
+assert(Copy_1.feature().results()[0].data().name() == "Box_1")
+assert(Copy_1.feature().results()[1].data().name() == "Cylinder_1")
+assert(Copy_1.feature().results()[2].data().name() == "Box_2")
+assert(Copy_1.feature().results()[3].data().name() == "Cylinder_2")
+assert(Copy_1.feature().results()[4].data().name() == "Box_3")
+assert(Copy_1.feature().results()[5].data().name() == "Cylinder_3")
+
+model.begin()
+model.testHaveNamingSubshapes(Copy_1, model, Part_1_doc)
+model.end()
+
+assert(model.checkPythonDump())
--- /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
+#
+
+# Checks that the Copy feature produces correct results and names if sub-shapes of the same shape are selected
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-25.99630541871921, 19.52832512315271, -16.66748768472907, 29.72783251231528)
+SketchLine_2 = Sketch_1.addLine(-16.66748768472907, 29.72783251231528, -12.4384236453202, 17.66256157635469)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-12.4384236453202, 17.66256157635469, -25.99630541871921, 19.52832512315271)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 10, 0)
+Extrusion_1.result().setName("Prism")
+Copy_1_objects = [model.selection("FACE", "Prism/Generated_Face&Sketch_1/SketchLine_3"), model.selection("FACE", "Prism/Generated_Face&Sketch_1/SketchLine_2"), model.selection("EDGE", "[Prism/Generated_Face&Sketch_1/SketchLine_1][Prism/To_Face]")]
+Copy_1 = model.addCopy(Part_1_doc, Copy_1_objects, 2)
+Copy_1.result().setName("Prism_1")
+model.end()
+
+assert(Copy_1.feature().results().size() == 6)
+
+for index in range(6):
+ # name is just incremented
+ assert(Copy_1.feature().results()[index].data().name() == "Prism_" + str(index + 1))
+ # type of the shape corresponds to selection: 2 faces then edge
+ if index%3 == 2:
+ assert(Copy_1.feature().results()[index].shape().shapeTypeStr() == "EDGE")
+ else:
+ assert(Copy_1.feature().results()[index].shape().shapeTypeStr() == "FACE")
+
+model.begin()
+model.testHaveNamingSubshapes(Copy_1, model, Part_1_doc)
+model.end()
+
+assert(model.checkPythonDump())
--- /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
+#
+
+# Checks that the Copy feature produces correct results and names if the whole result and feature are copied.
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-19.47177806477657, -9.723714972297476, -32.14322074518937, 18.42485654704614)
+SketchLine_2 = Sketch_1.addLine(-32.14322074518937, 18.42485654704614, -13.96909823036938, 5.527027954588926)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-13.96909823036938, 5.527027954588926, -19.47177806477657, -9.723714972297476)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchLine_4 = Sketch_1.addLine(-19.47177806477657, -9.723714972297476, -38.20802856635906, 4.439747463237282)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-38.20802856635906, 4.439747463237282, -32.14322074518937, 18.42485654704614)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_5.endPoint())
+SketchCircle_1 = Sketch_1.addCircle(15.45187411494798, 10.57784256870842, 6.036432809751617)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_5r-SketchLine_4r"), model.selection("FACE", "Sketch_1/Face-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 10, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Sketch_1/Face-SketchCircle_1_2f_wire")], model.selection(), 10, 0)
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("COMPOUND", "all-in-Extrusion_2")], 1)
+model.end()
+
+assert(Copy_1.feature().results().size() == 2)
+
+from ModelAPI import *
+assert(Copy_1.feature().results()[0].data().name() == "Extrusion_1_1_1")
+assert(modelAPI_ResultBody(Copy_1.feature().results()[0]).subResult(0).data().name() == "Extrusion_1_1_1_1")
+assert(modelAPI_ResultBody(Copy_1.feature().results()[0]).subResult(1).data().name() == "Extrusion_1_1_1_2")
+assert(Copy_1.feature().results()[1].data().name() == "Extrusion_2_1_1")
+
+# Check that copy of the whole feature that contains several results produce compound of all results
+model.begin()
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 10, 0)
+Copy_2 = model.addCopy(Part_1_doc, [model.selection("COMPOUND", "all-in-Extrusion_3")], 1)
+model.end()
+
+assert(Copy_2.feature().results()[0].data().name() == "Extrusion_3_1_1")
+assert(Copy_2.feature().results()[0].shape().shapeTypeStr() == "COMPOUND")
+aSub1 = modelAPI_ResultBody(Copy_2.feature().results()[0]).subResult(0)
+assert(aSub1.shape().shapeTypeStr() == "COMPSOLID")
+aSub2 = modelAPI_ResultBody(Copy_2.feature().results()[0]).subResult(1)
+assert(aSub2.shape().shapeTypeStr() == "SOLID")
+
+model.begin()
+model.testHaveNamingSubshapes(Copy_1, model, Part_1_doc)
+model.testHaveNamingSubshapes(Copy_2, model, Part_1_doc)
+model.end()
+
+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
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Box_1_1/Top")])
+assert(Defeaturing_1.feature().error() != "")
+
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_2 = model.addBox(Part_2_doc, 10, 10, 10)
+ExtrusionCut_1 = model.addExtrusionCut(Part_2_doc, [], model.selection(), [model.selection("SOLID", "Box_1_1")])
+Sketch_1 = model.addSketch(Part_2_doc, model.selection("FACE", "Box_1_1/Top"))
+SketchCircle_1 = Sketch_1.addCircle(4, 5.137343601256935, 3)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 3)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), 4, True)
+ExtrusionCut_1.setNestedSketch(Sketch_1)
+Plane_4 = model.addPlane(Part_2_doc, model.selection("FACE", "Box_1_1/Back"), model.selection("FACE", "Box_1_1/Front"))
+Partition_1 = model.addPartition(Part_2_doc, [model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("FACE", "Plane_1")], keepSubResults = True)
+
+Defeaturing_2 = model.addDefeaturing(Part_2_doc, [model.selection("FACE", "Partition_1_1_1/Modified_Face&Sketch_1/SketchCircle_1_2")])
+assert(Defeaturing_2.feature().error() != "")
+
+model.end()
--- /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()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 20, 20, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], 10, 10, 0)
+Cylinder_2 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Cylinder_2_1")], keepSubResults = True)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cut_1_1")], model.selection("EDGE", "PartSet/OX"), 30, 2, model.selection("EDGE", "PartSet/OY"), 30, 2)
+Defeaturing_1_objects = [model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Cylinder_2_1/Face_1"), model.selection("FACE", "LinearCopy_1_1_4/MF:Translated&Cylinder_1_1/Face_1"), model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Cylinder_2_1/Face_1"), model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Cylinder_1_1/Face_1")]
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, Defeaturing_1_objects)
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [4])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [28])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [120])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [240])
+model.testResultsVolumes(Defeaturing_1, [14036.50459153])
+
+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
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Cut_1_1/Modified_Face&Box_1_1/Back"), model.selection("FACE", "Box_1_1/Front"))
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Cut_1_1"), model.selection("FACE", "Plane_1")], keepSubResults = True)
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Cut_1_1/Modified_Face&Cylinder_1_1/Face_1")])
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [2])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Defeaturing_1, [1000])
+
+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
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), [model.selection("SOLID", "Box_1_1")])
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Top"))
+SketchCircle_1 = Sketch_1.addCircle(4, 5.137343601256935, 3)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 3)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Top]"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), 4, True)
+ExtrusionCut_1.setNestedSketch(Sketch_1)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Back"), model.selection("FACE", "Box_1_1/Front"))
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("FACE", "Plane_1")], keepSubResults = True)
+Defeaturing_1_objects = [model.selection("FACE", "Partition_1_1_2/Modified_Face&Sketch_1/SketchCircle_1_2&weak_name_2"), model.selection("FACE", "Partition_1_1_2/Modified_Face&Sketch_1/SketchCircle_1_2&weak_name_1"), model.selection("FACE", "Partition_1_1_1/Modified_Face&Sketch_1/SketchCircle_1_2")]
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, Defeaturing_1_objects)
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [2])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Defeaturing_1, [1000])
+
+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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(5, 1.355252715607035e-20, 20, -1.336382355046098e-51)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(20, -1.336382355046098e-51, 20, 5.85786437626905)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchLine_3 = Sketch_1.addLine(20, 5.85786437626905, 15.85786437626905, 10)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(15.85786437626905, 10, 20, 14.14213562373095)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(20, 14.14213562373095, 20, 20)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, 20, 0, 20)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(0, 20, 0, 5)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_7.result())
+SketchConstraintVertical_2.setName("SketchConstraintVertical_3")
+SketchArc_1 = Sketch_1.addArc(0, 0, 5, 1.355252715607035e-20, 0, 5, False)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchArc_1.endPoint())
+SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_5.result())
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_3.result(), SketchLine_4.result())
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_1.result())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_7.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchArc_1.center(), SketchAPI_Point(SketchPoint_1).coordinates())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.endPoint(), 20, True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_7.startPoint(), 20, True)
+SketchLine_8 = Sketch_1.addLine(10, 0, 10, 20)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_6.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintVertical_3.setName("SketchConstraintVertical_4")
+SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchLine_8.endPoint(), SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_5.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_4.result())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 5)
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_3.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), 10, 0)
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchArc_1_2"), model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_3")])
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [2])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [14])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Defeaturing_1, [4000])
+
+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
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Box_1_1")], [model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Cut_1_1/Modified_Face&Cylinder_1_1/Face_1")])
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [0])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Defeaturing_1, [1000])
+
+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
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10.19197853506727, -21.07109716039953, 30.19197853506727, -21.07109716039953)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(30.19197853506727, -21.07109716039953, 30.19197853506727, -6.071097160399531)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchLine_3 = Sketch_1.addLine(30.19197853506727, -6.071097160399531, 20.19197853506727, -6.071097160399531)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(20.19197853506727, -6.071097160399531, 20.19197853506727, 8.928902839600468)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(20.19197853506727, 8.928902839600468, 30.19197853506727, 8.928902839600468)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchLine_6 = Sketch_1.addLine(30.19197853506727, 8.928902839600468, 30.19197853506727, 18.92890283960047)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(30.19197853506727, 18.92890283960047, 10.19197853506727, 18.92890283960047)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchLine_8 = Sketch_1.addLine(10.19197853506727, 18.92890283960047, 10.19197853506727, -21.07109716039953)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_8.endPoint())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintVertical_3.setName("SketchConstraintVertical_4")
+SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 20)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_8.result(), 40)
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_2.result(), 15)
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_6.result(), 10)
+SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_3.result(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f")], model.selection(), 10, 0)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"), 0, model.selection(), 0, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1"))
+SketchLine_9 = Sketch_2.addLine(30.19197853506727, 5, 25.19197853506727, 5)
+SketchLine_10 = Sketch_2.addLine(25.19197853506727, 5, 25.19197853506727, 10)
+SketchLine_11 = Sketch_2.addLine(25.19197853506727, 10, 30.19197853506727, 10)
+SketchLine_12 = Sketch_2.addLine(30.19197853506727, 10, 30.19197853506727, 5)
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_12.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint())
+SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchLine_12.startPoint())
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_2.setVertical(SketchLine_10.result())
+SketchConstraintVertical_4.setName("SketchConstraintVertical_5")
+SketchConstraintHorizontal_6 = Sketch_2.setHorizontal(SketchLine_11.result())
+SketchConstraintVertical_5 = Sketch_2.setVertical(SketchLine_12.result())
+SketchConstraintVertical_5.setName("SketchConstraintVertical_6")
+SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2][Extrusion_1_1/To_Face]"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchPoint_1.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_12.result(), SketchLine_11.result())
+SketchConstraintLength_6 = Sketch_2.setLength(SketchLine_12.result(), 5)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4"), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_5")])
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [0])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [42])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [84])
+model.testResultsVolumes(Defeaturing_1, [7625])
+
+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
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10.19197853506727, -21.07109716039953, 30.19197853506727, -21.07109716039953)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(30.19197853506727, -21.07109716039953, 30.19197853506727, -6.071097160399531)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchLine_3 = Sketch_1.addLine(30.19197853506727, -6.071097160399531, 20.19197853506727, -6.071097160399531)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(20.19197853506727, -6.071097160399531, 20.19197853506727, 8.928902839600468)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(20.19197853506727, 8.928902839600468, 30.19197853506727, 8.928902839600468)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchLine_6 = Sketch_1.addLine(30.19197853506727, 8.928902839600468, 30.19197853506727, 18.92890283960047)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(30.19197853506727, 18.92890283960047, 10.19197853506727, 18.92890283960047)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchLine_8 = Sketch_1.addLine(10.19197853506727, 18.92890283960047, 10.19197853506727, -21.07109716039953)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_8.endPoint())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintVertical_3.setName("SketchConstraintVertical_4")
+SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 20)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_8.result(), 40)
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_2.result(), 15)
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_6.result(), 10)
+SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_3.result(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f")], model.selection(), 10, 0)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"), 0, model.selection(), 0, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1"))
+SketchLine_9 = Sketch_2.addLine(30.19197853506727, 5, 25.19197853506727, 5)
+SketchLine_10 = Sketch_2.addLine(25.19197853506727, 5, 25.19197853506727, 10)
+SketchLine_11 = Sketch_2.addLine(25.19197853506727, 10, 30.19197853506727, 10)
+SketchLine_12 = Sketch_2.addLine(30.19197853506727, 10, 30.19197853506727, 5)
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_12.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint())
+SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchLine_12.startPoint())
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_2.setVertical(SketchLine_10.result())
+SketchConstraintVertical_4.setName("SketchConstraintVertical_5")
+SketchConstraintHorizontal_6 = Sketch_2.setHorizontal(SketchLine_11.result())
+SketchConstraintVertical_5 = Sketch_2.setVertical(SketchLine_12.result())
+SketchConstraintVertical_5.setName("SketchConstraintVertical_6")
+SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2][Extrusion_1_1/To_Face]"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchPoint_1.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_12.result(), SketchLine_11.result())
+SketchConstraintLength_6 = Sketch_2.setLength(SketchLine_12.result(), 5)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchLine_10"), model.selection("FACE", "ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchLine_9")])
+model.testHaveNamingSubshapes(Defeaturing_1, model, Part_1_doc)
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Defeaturing_1, 1)
+model.testNbSubResults(Defeaturing_1, [0])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Defeaturing_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Defeaturing_1, [6500])
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from salome.shaper import model
+from ModelAPI import *
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(15, 13, 11)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Sketch_2 = model.addSketch(Part_2_doc, model.defaultPlane("XOZ"))
+SketchCircle_2 = Sketch_2.addCircle(-13, -9, 5)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_2_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+ImportResult_1 = model.addImportResult(Part_2_doc, [model.selection("SOLID", "Part_1/Extrusion_1_1")])
+model.do()
+
+Part_3 = model.addPart(partSet)
+Part_3_doc = Part_3.document()
+Extrusion_3 = model.addExtrusion(Part_3_doc, [], model.selection(), 1, 0)
+Sketch_3 = model.addSketch(Part_3_doc, model.defaultPlane("XOZ"))
+SketchCircle_3 = Sketch_3.addCircle(-4, 2, 5)
+Extrusion_3.setNestedSketch(Sketch_3)
+model.do()
+
+model.end()
+
+# check Part_2 is ok and contains 2 solids in result
+assert(Part_2.feature().results().size() == 1)
+aPartShape = Part_2.feature().firstResult().shape()
+assert(aPartShape.shapeTypeStr() == "COMPOUND")
+aShapeExplorer = GeomAPI_ShapeExplorer(aPartShape, GeomAPI_Shape.SOLID)
+assert(aShapeExplorer.more())
+aShapeExplorer.next()
+assert(aShapeExplorer.more())
+
+# check that selection of this part and the lower part is impossible (by validator)
+model.begin()
+aSel = ImportResult_1.feature().selectionList("objects").value(0)
+aSel.selectSubShape("SOLID", "Part_2/Extrusion_1_1")
+model.end()
+aFactory = ModelAPI_Session.get().validators()
+assert(not aFactory.validate(ImportResult_1.feature()))
+
+model.begin()
+aSel = ImportResult_1.feature().selectionList("objects").value(0)
+aSel.selectSubShape("SOLID", "Part_3/Extrusion_1_1")
+model.end()
+assert(not aFactory.validate(ImportResult_1.feature()))
+
+# back to correct value
+model.begin()
+aSel = ImportResult_1.feature().selectionList("objects").value(0)
+aSel.selectSubShape("SOLID", "Part_1/Extrusion_1_1")
+model.end()
+assert(aFactory.validate(ImportResult_1.feature()))
+
+# TODO: implement for GEOMOETRICAL also
+assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING))
SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_4.result(), SketchLine_1.result())
SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_5.result(), SketchLine_1.result())
SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_6.result(), SketchLine_1.result())
-SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), 120)
+SketchConstraintAngle_1 = Sketch_1.setAngleBackward(SketchLine_1.result(), SketchLine_2.result(), 120)
SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 120)
-SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_4.result(), 120)
+SketchConstraintAngle_3 = Sketch_1.setAngleBackward(SketchLine_3.result(), SketchLine_4.result(), 120)
SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result())
SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_5.result(), 60)
SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
--- /dev/null
+<source>
+ <multi_selector id="objects"
+ label="Sources:"
+ tooltip="Select copied objects"
+ shape_types="vertices edges wires faces shells compsolids objects"
+ use_choice="false"
+ concealment="false">
+ </multi_selector>
+ <integervalue id="number"
+ label="Nb copies"
+ step="1"
+ default="1"
+ min="1"
+ tooltip="Number of copies">
+ </integervalue>
+</source>
--- /dev/null
+<source>
+ <multi_selector id="main_objects"
+ label="Faces to remove"
+ icon=""
+ tooltip="Select faces"
+ shape_types="faces"
+ use_choice="false"
+ concealment="true">
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="FeaturesPlugin_ValidatorDefeaturingSelection"/>
+ </multi_selector>
+</source>
angularCopyFeature.rst
chamferFeature.rst
commonFeature.rst
+ copyFeature.rst
cutFeature.rst
+ defeaturingFeature.rst
extrusionCutFeature.rst
extrusionFeature.rst
extrusionFuseFeature.rst
filletFeature.rst
fuseFeature.rst
fuseFeatureFaces.rst
+ importResult.rst
intersectionFeature.rst
linearCopyFeature.rst
measurementFeature.rst
--- /dev/null
+
+ .. _tui_create_copy:
+
+Create Copy
+============
+
+.. literalinclude:: examples/copy.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/copy.py>`
+
--- /dev/null
+
+ .. _tui_defeaturing:
+
+Perform Defeaturing
+===================
+
+.. literalinclude:: examples/defeaturing.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/defeaturing.py>`
+
--- /dev/null
+
+ .. _tui_create_import_result:
+
+Create Import Result
+============
+
+.. literalinclude:: examples/import_result.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/import_result.py>`
+
--- /dev/null
+.. |copy_btn.icon| image:: images/copy_btn.png
+
+Copy
+=====
+
+Copy feature makes duplicates of the selected features, results, sub-results and sub-shapes. For the whole feature selected
+all results of this feature are copied. The referenced arguments of this feature are not concealed. The history behavior of
+copy is specific: *Move to the End* of groups will move to all copy-results. For an example, if a face of a box was selected
+for a group and a copy of this box was done, the *Move to the End* of this group will cause two faces appeared in this Group:
+the original one and the copy.
+
+
+To create a Copy in the active part:
+
+#. select in the Main Menu *Features - > Copy* item or
+#. click |copy_btn.icon| **Copy** button in the toolbar
+
+The following property panel will be opened:
+
+.. image:: images/Copy.png
+ :align: center
+
+.. centered::
+ **Copy operation**
+
+Here it is necessary to select some objects. Only results and sub-results and their sub-shapes located in the folder **Results** can be selected and copied.
+Also it is possible to increase the number of resulting copies.
+
+**Apply** button creates a copy.
+
+**Cancel** button cancels the operation.
+
+**TUI Command**:
+
+.. py:function:: model.addCopy(Part_doc, objects, number_of_copies)
+
+ :param part: The current part object.
+ :param objects: A list of objects.
+ :param number_of_copies: A number of resulting copies.
+ :return: Result feature Copy.
+
+Result
+""""""
+
+The Result of the operation will be one or several copies of the selected shapes located in the same place:
+
+.. image:: images/CreatedCopy.png
+ :align: center
+
+.. centered::
+ **Copy created**
+
+**See Also** a sample TUI Script of :ref:`tui_create_copy` operation.
--- /dev/null
+.. |defeaturing.icon| image:: images/defeaturing.png
+
+Defeaturing
+===========
+
+**Defeaturing** operation is intended for removal of the unwanted parts or features from the model. These parts can be holes, protrusions, gaps, chamfers, fillets, etc.
+
+To create a Defeaturing in the active part:
+
+#. select in the Main Menu *Feature -> Defeaturing* item or
+#. click |defeaturing.icon| **Defeaturing** button in the toolbar.
+
+After that select one or more faces of solids to suppress them. The Defeaturing works with faces from comsolids and compounds of solids as well.
+
+.. image:: images/defeaturing_property_panel.png
+ :align: center
+
+.. centered::
+ Defeaturing property panel
+
+Input field:
+
+- **Faces to remove** panel contains the list of faces which should be suppressed.
+
+**TUI Command**:
+
+.. py:function:: model.addDefeaturing(Part_doc, [faces])
+
+ :param part: The current part object.
+ :param list: A list of faces in format *model.selection("FACE", shape)*.
+ :return: Created object.
+
+Result
+""""""
+
+Result of **Defeaturing** is shown below.
+
+.. image:: images/defeaturing_result.png
+ :align: center
+
+.. centered::
+ Defeaturing operation
+
+**See Also** a sample TUI Script of :ref:`tui_defeaturing` operation.
+
+References
+""""""""""
+
+For more information, please, visit `OpenCASCADE Documentation <https://dev.opencascade.org/doc/overview/html/occt_user_guides__modeling_algos.html#occt_modalg_defeaturing>`_.
--- /dev/null
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(7, 11, 2)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+Extrusion_1.result().setTransparency(0.75)
+Copy_1 = model.addCopy(Part_1_doc, [model.selection("FACE", "Extrusion_1_1/From_Face"), model.selection("FACE", "Extrusion_1_1/To_Face")], 2)
+Copy_1.result().setColor(0, 170, 0)
+Copy_1.results()[1].setColor(0, 170, 0)
+Copy_1.results()[2].setColor(0, 170, 0)
+Copy_1.results()[3].setColor(0, 170, 0)
+
+model.end()
--- /dev/null
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Fillet_1_objects = [model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Left]"), model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]")]
+Fillet_1 = model.addFillet(Part_1_doc, Fillet_1_objects, 2)
+Defeaturing_1 = model.addDefeaturing(Part_1_doc, [model.selection("FACE", "Fillet_1_1/GF:Fillet&Fillet_1_1/FilletSelected_3"), model.selection("FACE", "(Fillet_1_1/GF:Fillet&Fillet_1_1/FilletSelected_1)(Fillet_1_1/GF:Fillet&Fillet_1_1/FilletSelected_2)(Fillet_1_1/GF:Fillet&Fillet_1_1/FilletSelected_3)")])
+
+model.end()
--- /dev/null
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(21, 16, 6)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+model.do()
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+ImportResult_1 = model.addImportResult(Part_2_doc, [model.selection("SOLID", "Part_1/Extrusion_1_1")])
+model.end()
--- /dev/null
+.. |import_result_btn.icon| image:: images/import_result_btn.png
+
+Import Result
+=====
+
+The Import Result feature allows the user to import one or several results from another Part. If the result of the source-part is
+changed, the part and part result that contains the copy-results will be updated. The feature keeps the
+copy-shape, so, even the document was opened and the source-part was not activated (loaded), the part with copy-feature works well
+with this result-shape.
+
+It may be necessary for the user to load the other parts before using this feature otherwise the content of the **Results** folders will be empty.
+
+To create a Copy in the active part:
+
+#. select in the Main Menu *Features - > Import Result* item or
+#. click |import_result_btn.icon| **Import Result** button in the toolbar
+
+
+The following property panel will be opened:
+
+.. image:: images/ImportResult.png
+ :align: center
+
+.. centered::
+ **Import result operation**
+
+Here it is necessary to select one or several objects. It is only possible to import results from Parts placed before the
+current Part where the import is done. Only results from the **Results** folder of previously created parts may be selected.
+
+
+**Apply** button creates a copy.
+
+**Cancel** button cancels the operation.
+
+**TUI Command**:
+
+.. py:function:: model.addImportResult(Part_doc, results)
+
+ :param part: The current part object.
+ :param results: A list of results from another part.
+ :return: Result feature Import Result.
+
+Result
+""""""
+
+The Result of the operation will be copy of one or several results selected in another part located in the same place:
+
+.. image:: images/CreatedImportResult.png
+ :align: center
+
+.. centered::
+ **Import result created**
+
+**See Also** a sample TUI Script of :ref:`tui_create_import_result` operation.
.. py:function:: model.addUnion(Part_doc, objects)
:param part: The current part object.
- :param list: A list of objects.
+ :param objects: A list of objects.
:return: Result object.
Result
--- /dev/null
+<source>
+ <multi_selector id="objects"
+ label="Sources:"
+ tooltip="Select copied results"
+ shape_types="objects"
+ use_choice="false"
+ concealment="false"
+ allow_parts_content="true">
+ <validator id="FeaturesPlugin_ValidatorImportResults"/>
+ </multi_selector>
+</source>
helpfile="recoverFeature.html">
<source path="recover_widget.xml"/>
</feature>
+ <feature id="Copy"
+ title="Copy"
+ tooltip="Copies results or sub-results"
+ icon="icons/Features/copy.png"
+ helpfile="copyFeature.html">
+ <source path="copy_widget.xml"/>
+ </feature>
+ <feature id="ImportResult"
+ title="Import Result"
+ tooltip="Copies results from other parts"
+ icon="icons/Features/import_result.png"
+ helpfile="importResultFeature.html">
+ <source path="import_result_widget.xml"/>
+ </feature>
<feature id="RemoveResults" title="Remove results" tooltip="Internal feature for results removal" internal="1">
<multi_selector id="results" concealment="true"/>
</feature>
</group>
- <group id="Fillet">
+ <group id="Features">
<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"/>
icon="icons/Features/fusion_faces.png" auto_preview="true" helpfile="FeaturesPlugin/fusionFacesFeature.html">
<source path="fusion_faces_widget.xml"/>
</feature>
+ <feature id="Defeaturing" title="Defeaturing" tooltip="Perform removing faces from solid"
+ icon="icons/Features/defeaturing.png" auto_preview="true" helpfile="defeaturingFeature.html">
+ <source path="defeaturing_widget.xml"/>
+ </feature>
</group>
</workbench>
<workbench id="Part">
<source path="multirotation_widget.xml"/>
</feature>
</group>
+ </workbench>
+ <workbench id="Inspection">
<group id="Measurement">
<feature id="Measurement" title="Measurement" tooltip="Calculate properties of objects"
icon="icons/Features/measurement.png" helpfile="measurementFeature.html" abort_confirmation="false">
SET(PROJECT_HEADERS
GeomAPI.h
+ GeomAPI_BSpline.h
+ GeomAPI_BSpline2d.h
GeomAPI_Circ.h
GeomAPI_Circ2d.h
GeomAPI_Interface.h
)
SET(PROJECT_SOURCES
+ GeomAPI_BSpline.cpp
+ GeomAPI_BSpline2d.cpp
GeomAPI_Circ.cpp
GeomAPI_Circ2d.cpp
GeomAPI_Interface.cpp
%shared_ptr(GeomAPI_Ax2)
%shared_ptr(GeomAPI_Ax3)
%shared_ptr(GeomAPI_Box)
+%shared_ptr(GeomAPI_BSpline)
+%shared_ptr(GeomAPI_BSpline2d)
%shared_ptr(GeomAPI_Circ)
%shared_ptr(GeomAPI_Circ2d)
%shared_ptr(GeomAPI_Cone)
}
}
-%typemap(in) double & (double temp) {
- if (PyLong_Check($input)) {
- temp = PyLong_AsLong($input);
- $1 = &temp;
- }
+%typemap(in, numinputs=0) double & (double temp) {
+ $1 = &temp;
}
%typemap(argout) double & {
- $result = PyFloat_FromDouble(*$1);
+ $result = SWIG_Python_AppendOutput($result, PyFloat_FromDouble(*$1));
}
+// std::dynamic_pointer_cast
+template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
+%template(shapeToEdge) shared_ptr_cast<GeomAPI_Edge, GeomAPI_Shape>;
+
// all supported interfaces
%include "GeomAPI_Interface.h"
%include "GeomAPI_Ax2.h"
%include "GeomAPI_Ax3.h"
%include "GeomAPI_Box.h"
+%include "GeomAPI_BSpline.h"
+%include "GeomAPI_BSpline2d.h"
%include "GeomAPI_Circ.h"
%include "GeomAPI_Circ2d.h"
%include "GeomAPI_Cone.h"
--- /dev/null
+// Copyright (C) 2019-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 <GeomAPI_BSpline.h>
+#include <GeomAPI_Pnt.h>
+
+#include <Geom_BSplineCurve.hxx>
+
+#define MY_BSPLINE (*(implPtr<Handle_Geom_BSplineCurve>()))
+
+GeomAPI_BSpline::GeomAPI_BSpline(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())
+ throw Standard_ConstructionError("GeomAPI_BSpline: Curve is not a B-spline");
+ setImpl(new Handle_Geom_BSplineCurve(aBSpl));
+}
+
+int GeomAPI_BSpline::degree() const
+{
+ return MY_BSPLINE->Degree();
+}
+
+std::list<GeomPointPtr> GeomAPI_BSpline::poles() const
+{
+ const TColgp_Array1OfPnt& aBSplPoles = MY_BSPLINE->Poles();
+
+ std::list<GeomPointPtr> aPoles;
+ for (int anIndex = aBSplPoles.Lower(); anIndex <= aBSplPoles.Upper(); ++anIndex) {
+ const gp_Pnt& aPoint = aBSplPoles.Value(anIndex);
+ aPoles.push_back(GeomPointPtr(new GeomAPI_Pnt(aPoint.X(), aPoint.Y(), aPoint.Z())));
+ }
+ return aPoles;
+}
+
+std::list<double> GeomAPI_BSpline::weights() const
+{
+ std::list<double> aWeights;
+ const TColStd_Array1OfReal* aBSplWeights = MY_BSPLINE->Weights();
+ if (aBSplWeights)
+ aWeights.assign(aBSplWeights->begin(), aBSplWeights->end());
+ return aWeights;
+}
+
+std::list<double> GeomAPI_BSpline::knots() const
+{
+ const TColStd_Array1OfReal& aBSplKnots = MY_BSPLINE->Knots();
+ return std::list<double>(aBSplKnots.begin(), aBSplKnots.end());
+}
+
+std::list<int> GeomAPI_BSpline::mults() const
+{
+ const TColStd_Array1OfInteger& aBSplMults = MY_BSPLINE->Multiplicities();
+ return std::list<int>(aBSplMults.begin(), aBSplMults.end());
+}
+
+bool GeomAPI_BSpline::isPeriodic() const
+{
+ return MY_BSPLINE->IsPeriodic();
+}
--- /dev/null
+// Copyright (C) 2019-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 GeomAPI_BSpline_H_
+#define GeomAPI_BSpline_H_
+
+#include <GeomAPI_Interface.h>
+#include <GeomAPI_Curve.h>
+
+#include <list>
+#include <memory>
+
+class GeomAPI_Pnt;
+
+/**\class GeomAPI_BSpline
+ * \ingroup DataModel
+ * \brief B-spline in 3D
+ */
+class GeomAPI_BSpline : public GeomAPI_Interface
+{
+public:
+ /// Creation of B-spline defined by a curve
+ GEOMAPI_EXPORT GeomAPI_BSpline(const GeomCurvePtr& theCurve);
+
+ /// Degree of B-spline curve
+ GEOMAPI_EXPORT int degree() const;
+
+ /// Poles of B-spline curve
+ GEOMAPI_EXPORT std::list<std::shared_ptr<GeomAPI_Pnt> > poles() const;
+
+ /// Weights of B-spline poles
+ GEOMAPI_EXPORT std::list<double> weights() const;
+
+ /// Knots of B-spline curve
+ GEOMAPI_EXPORT std::list<double> knots() const;
+
+ /// Multiplicities of B-spline knots
+ GEOMAPI_EXPORT std::list<int> mults() 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;
+
+#endif
--- /dev/null
+// Copyright (C) 2019-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 <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <Geom2d_BSplineCurve.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
+#include <Precision.hxx>
+
+#define MY_BSPLINE (*(implPtr<Handle_Geom2d_BSplineCurve>()))
+
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const int theDegree,
+ const bool thePeriodic);
+
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const int theDegree,
+ const bool thePeriodic)
+{
+ if (theKnots.empty() || theMults.empty())
+ return newBSpline2d(thePoles, theWeights, theDegree, thePeriodic);
+
+ int anAuxPole = 0;
+ if (thePeriodic && thePoles.front()->distance(thePoles.back()) < Precision::Confusion())
+ anAuxPole = -1;
+
+ // collect arrays of poles, weights, knots and multiplicities
+ TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size() + anAuxPole);
+ TColStd_Array1OfReal aWeights(1, (int)theWeights.size() + anAuxPole);
+ TColStd_Array1OfReal aKnots(1, (int)theKnots.size());
+ TColStd_Array1OfInteger aMults(1, (int)theMults.size());
+
+ int anIndex = 1;
+ for (std::list<GeomPnt2dPtr>::const_iterator aPIt = thePoles.begin();
+ aPIt != thePoles.end() && anIndex <= aPoles.Upper(); ++aPIt, ++anIndex)
+ aPoles.SetValue(anIndex, gp_Pnt2d((*aPIt)->x(), (*aPIt)->y()));
+ anIndex = 1;
+ for (std::list<double>::const_iterator aWIt = theWeights.begin();
+ aWIt != theWeights.end() && anIndex <= aWeights.Upper(); ++aWIt, ++anIndex)
+ aWeights.SetValue(anIndex, *aWIt);
+ anIndex = 1;
+ for (std::list<double>::const_iterator aKIt = theKnots.begin();
+ aKIt != theKnots.end(); ++aKIt, ++anIndex)
+ aKnots.SetValue(anIndex, *aKIt);
+ anIndex = 1;
+ for (std::list<int>::const_iterator aMIt = theMults.begin();
+ aMIt != theMults.end(); ++aMIt, ++anIndex)
+ aMults.SetValue(anIndex, *aMIt);
+
+ Handle(Geom2d_BSplineCurve) aCurve =
+ new Geom2d_BSplineCurve(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
+ return new Handle_Geom2d_BSplineCurve(aCurve);
+}
+
+Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const int theDegree,
+ const bool thePeriodic)
+{
+ std::list<std::shared_ptr<GeomAPI_Pnt2d> > aPoles = thePoles;
+ std::list<double> aWeights = theWeights;
+ int aMult = theDegree + 1;
+ int aNbKnots = (int)thePoles.size() - theDegree + 1;
+ if (thePeriodic) {
+ if (aPoles.front()->distance(aPoles.back()) < Precision::Confusion()) {
+ aPoles.pop_back();
+ aWeights.pop_back();
+ }
+ aMult = 1;
+ aNbKnots = (int)aPoles.size() + 1;
+ }
+
+ if (aNbKnots < 2)
+ return new Handle_Geom2d_BSplineCurve();
+
+ static const double aStartParam = 0.0;
+ static const double aEndParam = 1.0;
+ double aStep = aEndParam / (aNbKnots - 1);
+ int anIndex = 1;
+ std::list<double> aKnots;
+ for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep)
+ aKnots.push_back(aKnot);
+ aKnots.push_back(aEndParam);
+
+ std::list<int> aMults(aNbKnots - 2, 1);
+ aMults.push_front(aMult);
+ aMults.push_back(aMult);
+
+ return newBSpline2d(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
+}
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const bool thePeriodic)
+{
+ int aDegree = 3;
+ if ((int)thePoles.size() <= aDegree)
+ aDegree = (int)thePoles.size() - 1;
+ if (aDegree <= 0)
+ return new Handle_Geom2d_BSplineCurve();
+ return newBSpline2d(thePoles, theWeights, aDegree, thePeriodic);
+}
+
+
+GeomAPI_BSpline2d::GeomAPI_BSpline2d(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const bool thePeriodic)
+ : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, thePeriodic))
+{
+ if (isNull())
+ throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve");
+}
+
+GeomAPI_BSpline2d::GeomAPI_BSpline2d(const int theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const bool thePeriodic)
+ : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, theKnots, theMults,
+ theDegree, thePeriodic))
+{
+ if (isNull())
+ throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve");
+}
+
+bool GeomAPI_BSpline2d::isNull() const
+{
+ return MY_BSPLINE.IsNull();
+}
+
+int GeomAPI_BSpline2d::degree() const
+{
+ return MY_BSPLINE->Degree();
+}
+
+std::list<double> GeomAPI_BSpline2d::knots() const
+{
+ const TColStd_Array1OfReal& aBSplKnots = MY_BSPLINE->Knots();
+ return std::list<double>(aBSplKnots.begin(), aBSplKnots.end());
+}
+
+std::list<int> GeomAPI_BSpline2d::mults() const
+{
+ const TColStd_Array1OfInteger& aBSplMults = MY_BSPLINE->Multiplicities();
+ return std::list<int>(aBSplMults.begin(), aBSplMults.end());
+}
+
+const bool GeomAPI_BSpline2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+ const double theTolerance,
+ double& theParameter) const
+{
+ return GeomLib_Tool::Parameter(MY_BSPLINE, thePoint->impl<gp_Pnt2d>(),
+ theTolerance, theParameter) == Standard_True;
+}
+
+void GeomAPI_BSpline2d::D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+ gp_Pnt2d aPnt;
+ MY_BSPLINE->D0(theU, aPnt);
+ thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y()));
+}
+
+void GeomAPI_BSpline2d::D1(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
+ std::shared_ptr<GeomAPI_XY>& theDerivative)
+{
+ gp_Pnt2d aPnt;
+ gp_Vec2d aVec;
+ MY_BSPLINE->D1(theU, aPnt, aVec);
+ thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y()));
+ theDerivative.reset(new GeomAPI_XY(aVec.X(), aVec.Y()));
+}
--- /dev/null
+// Copyright (C) 2019-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 GeomAPI_BSpline2d_H_
+#define GeomAPI_BSpline2d_H_
+
+#include <GeomAPI_Interface.h>
+
+#include <list>
+#include <memory>
+
+class GeomAPI_Pnt2d;
+class GeomAPI_XY;
+
+/** \class GeomAPI_BSpline2d
+ * \ingroup DataModel
+ * \brief B-spline curve in 2D
+ */
+class GeomAPI_BSpline2d : public GeomAPI_Interface
+{
+public:
+ /// Creation of B-spline curve defined by list of poles and weights
+ GEOMAPI_EXPORT GeomAPI_BSpline2d(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const bool thePeriodic = false);
+
+ /// Creation of B-spline curve defined by list of poles and weights
+ GEOMAPI_EXPORT GeomAPI_BSpline2d(const int theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots = std::list<double>(),
+ const std::list<int>& theMults = std::list<int>(),
+ const bool thePeriodic = false);
+
+ /// Returns true if curve is not initialized
+ GEOMAPI_EXPORT bool isNull() const;
+
+ /// Returns degree of the curve
+ GEOMAPI_EXPORT int degree() const;
+
+ /// Knots of the curve
+ GEOMAPI_EXPORT std::list<double> knots() const;
+
+ /// Multiplicities of the knots
+ GEOMAPI_EXPORT std::list<int> mults() const;
+
+ /// \brief Computes the parameter of a given point on a circle. The point must be
+ /// located either on the circle itself or relatively to the latter
+ /// at a distance less than the tolerance value. Return FALSE if the point
+ /// is beyond the tolerance limit or if computation fails.
+ /// Max Tolerance value is currently limited to 1.e-4
+ /// \param[in] thePoint point of origin.
+ /// \param[in] theTolerance tolerance of computation.
+ /// \param[out] theParameter resulting parameter.
+ GEOMAPI_EXPORT const bool parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+ const double theTolerance,
+ double& theParameter) const;
+
+ /// \brief Calculate point on B-spline curve accrding to the given parameter
+ GEOMAPI_EXPORT void D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+ /// \brief Calculate point and first derivative for B-spline curve accrding to the given parameter
+ GEOMAPI_EXPORT void D1(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
+ std::shared_ptr<GeomAPI_XY>& theDerivative);
+};
+
+#endif
#include <BRep_Tool.hxx>
#include <ElCLib.hxx>
#include <GCPnts_UniformAbscissa.hxx>
+#include <Geom_BSplineCurve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
return false;
}
+bool GeomAPI_Edge::isBSpline() const
+{
+ const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
+ double aFirst, aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+ if (aCurve.IsNull()) // degenerative edge
+ return false;
+ while (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
+ aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
+ return aCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve));
+}
+
std::shared_ptr<GeomAPI_Pnt> GeomAPI_Edge::firstPoint()
{
const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
return true;
}
-// LCOV_EXCL_START
+void GeomAPI_Edge::setRange(const double& theFirst, const double& theLast)
+{
+ TopoDS_Edge anEdge = impl<TopoDS_Edge>();
+ double aFirst, aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+ double aTolerance = BRep_Tool::Tolerance(anEdge);
+ if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
+ aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
+ BRep_Builder().UpdateEdge(anEdge, aCurve, aTolerance);
+ }
+ BRep_Builder().Range(anEdge, theFirst, theLast);
+}
+
void GeomAPI_Edge::getRange(double& theFirst, double& theLast) const
{
const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, theFirst, theLast);
}
+// LCOV_EXCL_START
bool GeomAPI_Edge::isInPlane(std::shared_ptr<GeomAPI_Pln> thePlane) const
{
double aFirst, aLast;
GEOMAPI_EXPORT
bool isEllipse() const;
+ /// Verifies that the edge is based on a B-spline curve
+ GEOMAPI_EXPORT
+ bool isBSpline() const;
+
/// Returns the first vertex coordinates of the edge
GEOMAPI_EXPORT
std::shared_ptr<GeomAPI_Pnt> firstPoint();
GEOMAPI_EXPORT
bool isEqual(const std::shared_ptr<GeomAPI_Shape> theEdge) const;
+ /// Change parametric range of the curve
+ GEOMAPI_EXPORT
+ void setRange(const double& theFirst, const double& theLast);
+
/// Returns range of parameter on the curve
GEOMAPI_EXPORT
void getRange(double& theFirst, double& theLast) const;
}
return isLess;
}
+
+int GeomAPI_Shape::Hash::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape) const
+{
+ const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+ return aShape.HashCode(IntegerLast());
+}
+
+bool GeomAPI_Shape::Equal::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
+ const std::shared_ptr<GeomAPI_Shape>& theShape2) const
+{
+ const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+ Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
+ Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
+
+ return aShape1.TShape() == aShape2.TShape() && aHash1 == aHash2;
+}
bool operator ()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
const std::shared_ptr<GeomAPI_Shape>& theShape2) const;
};
+
+ /// \brief Hash code for the shape
+ class Hash
+ {
+ public:
+ /// Return Hash value according to the address of the shape
+ GEOMAPI_EXPORT
+ int operator ()(const std::shared_ptr<GeomAPI_Shape>& theShape) const;
+ };
+
+ /// \brief Compare addresses of shapes
+ class Equal
+ {
+ public:
+ /// Return \c true if the address of the shapes are equal
+ GEOMAPI_EXPORT
+ bool operator ()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
+ const std::shared_ptr<GeomAPI_Shape>& theShape2) const;
+ };
};
//! Pointer on list of shapes
#include "GeomAPI_Ax2.h"
#include "GeomAPI_Ax3.h"
#include "GeomAPI_Box.h"
+ #include "GeomAPI_BSpline.h"
+ #include "GeomAPI_BSpline2d.h"
#include "GeomAPI_Circ.h"
#include "GeomAPI_Circ2d.h"
#include "GeomAPI_Cone.h"
#include <memory>
#include <string>
+ template<class T1, class T2>
+ std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject)
+ {
+ return std::dynamic_pointer_cast<T1>(theObject);
+ }
+
#endif /* SRC_GEOMAPI_GEOMAPI_SWIG_H_ */
GeomAlgoAPI_MapShapesAndAncestors.h
GeomAlgoAPI_Projection.h
GeomAlgoAPI_Chamfer.h
+ GeomAlgoAPI_Defeaturing.h
)
SET(PROJECT_SOURCES
GeomAlgoAPI_MapShapesAndAncestors.cpp
GeomAlgoAPI_Projection.cpp
GeomAlgoAPI_Chamfer.cpp
+ GeomAlgoAPI_Defeaturing.cpp
)
SET(PROJECT_LIBRARIES
--- /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_Defeaturing.h>
+#include <GeomAlgoAPI_DFLoader.h>
+
+#include <BRepAlgoAPI_Defeaturing.hxx>
+
+GeomAlgoAPI_Defeaturing::GeomAlgoAPI_Defeaturing(const GeomShapePtr& theBaseSolid,
+ const ListOfShape& theFacesToRemove)
+{
+ build(theBaseSolid, theFacesToRemove);
+}
+
+void GeomAlgoAPI_Defeaturing::build(const GeomShapePtr& theBaseSolid,
+ const ListOfShape& theFacesToRemove)
+{
+ if (!theBaseSolid || theFacesToRemove.empty())
+ return;
+
+ BRepAlgoAPI_Defeaturing* aDefeaturing = new BRepAlgoAPI_Defeaturing;
+ aDefeaturing->SetShape(theBaseSolid->impl<TopoDS_Shape>());
+ aDefeaturing->SetRunParallel(Standard_True);
+
+ // collect faces to remove
+ TopTools_ListOfShape aFaces;
+ for (ListOfShape::const_iterator anIt = theFacesToRemove.begin();
+ anIt != theFacesToRemove.end(); ++anIt)
+ aDefeaturing->AddFaceToRemove((*anIt)->impl<TopoDS_Shape>());
+
+ setImpl(aDefeaturing);
+ setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+ // build and get result
+ aDefeaturing->Build();
+ if (!aDefeaturing->IsDone() || aDefeaturing->HasErrors() || aDefeaturing->HasWarnings()) {
+ std::ostringstream errors;
+ aDefeaturing->DumpErrors(errors);
+ aDefeaturing->DumpWarnings(errors);
+ myError = errors.str();
+ return;
+ }
+
+ TopoDS_Shape aResult = GeomAlgoAPI_DFLoader::refineResult(aDefeaturing->Shape());
+
+ std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+ aShape->setImpl(new TopoDS_Shape(aResult));
+ setShape(aShape);
+ setDone(true);
+}
--- /dev/null
+// Copyright (C) 2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef GeomAlgoAPI_Defeaturing_H_
+#define GeomAlgoAPI_Defeaturing_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+#include <GeomAPI_Shape.h>
+
+/// \class GeomAlgoAPI_Defeaturing
+/// \ingroup DataAlgo
+/// \brief Perform Defeaturing algorithm
+class GeomAlgoAPI_Defeaturing : public GeomAlgoAPI_MakeShape
+{
+public:
+ /// Run Defeaturing operation on the solid for the given list of faces.
+ /// \param theBaseSolid a changing solid
+ /// \param theFacesToRemove list of faces to be removed
+ GEOMALGOAPI_EXPORT GeomAlgoAPI_Defeaturing(const GeomShapePtr& theBaseSolid,
+ const ListOfShape& theFacesToRemove);
+
+private:
+ /// Perform Defeaturing operation.
+ void build(const GeomShapePtr& theBaseSolid,
+ const ListOfShape& theFacesToRemove);
+};
+
+#endif
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAPI_Ax2.h>
+#include <GeomAPI_Ax3.h>
+#include <GeomAPI_BSpline2d.h>
#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Pnt2d.h>
#include <gp_Pln.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS.hxx>
#include <BRep_Tool.hxx>
+#include <Geom2d_BSplineCurve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
+#include <GeomLib.hxx>
#include <gp_Ax2.hxx>
#include <gp_Circ.hxx>
aRes->setImpl(new TopoDS_Shape(anEdge));
return aRes;
}
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(
+ const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::list<GeomPnt2dPtr>& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const int theDegree,
+ const bool thePeriodic)
+{
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+ new GeomAPI_BSpline2d(theDegree, thePoles, theWeights, theKnots, theMults, thePeriodic));
+ return bsplineOnPlane(thePlane, aBSplineCurve);
+}
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(
+ const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::shared_ptr<GeomAPI_BSpline2d>& theCurve)
+{
+ Handle(Geom_Curve) aCurve3D = GeomLib::To3d(thePlane->impl<gp_Ax3>().Ax2(),
+ theCurve->impl<Handle_Geom2d_BSplineCurve>());
+
+ BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve3D);
+ GeomEdgePtr aRes(new GeomAPI_Edge);
+ TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+ aRes->setImpl(new TopoDS_Shape(anEdge));
+ return aRes;
+}
#include <GeomAPI_Lin.h>
#include <GeomAPI_Circ.h>
#include <memory>
+#include <vector>
+
+class GeomAPI_Ax3;
+class GeomAPI_BSpline2d;
/**\class GeomAlgoAPI_EdgeBuilder
* \ingroup DataAlgo
const double theMinorRadius,
const std::shared_ptr<GeomAPI_Pnt>& theStart,
const std::shared_ptr<GeomAPI_Pnt>& theEnd);
+
+ /// Creates planar B-spline edge
+ static GeomEdgePtr bsplineOnPlane(const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const int theDegree,
+ const bool thePeriodic);
+
+ /// Creates planar B-spline edge
+ static GeomEdgePtr bsplineOnPlane(const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::shared_ptr<GeomAPI_BSpline2d>& theCurve);
};
#endif
#include <GeomAlgoAPI_DFLoader.h>
#include <GeomAlgoAPI_ShapeTools.h>
-#include <ShapeUpgrade_UnifySameDomain.hxx>
+#include <BRep_Tool.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Shape.hxx>
#include <Precision.hxx>
#include <TopoDS_Edge.hxx>
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
+#include <ShapeUpgrade_UnifySameDomain.hxx>
//==================================================================================================
GeomAlgoAPI_UnifySameDomain::GeomAlgoAPI_UnifySameDomain(const ListOfShape& theShapes)
}
// calculates maximum possible tolerance on edges of shape
-// (method from GEOM module BlockFix_UnionFaces.cxx)
static Standard_Real defineLinearTolerance(const TopoDS_Shape& theShape)
{
- Standard_Real aTol = Precision::Confusion();
+ Standard_Real aMaxTol = Precision::Confusion();
- Standard_Real MinSize = RealLast();
TopExp_Explorer Explo(theShape, TopAbs_EDGE);
for (; Explo.More(); Explo.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(Explo.Current());
- Bnd_Box aBox;
- BRepBndLib::Add(anEdge, aBox);
- Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
- aBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
- Standard_Real MaxSize = Max(Xmax - Xmin, Max(Ymax - Ymin, Zmax - Zmin));
- if (MaxSize < MinSize)
- MinSize = MaxSize;
+ aMaxTol = Max(aMaxTol, BRep_Tool::Tolerance(anEdge));
}
- if (!Precision::IsInfinite(MinSize))
- aTol = 0.1 * MinSize;
-
- return aTol;
+ return aMaxTol;
}
//==================================================================================================
GeomData_Point.h
GeomData_Dir.h
GeomData_Point2D.h
+ GeomData_Point2DArray.h
)
SET(PROJECT_SOURCES
GeomData_Point.cpp
GeomData_Dir.cpp
GeomData_Point2D.cpp
+ GeomData_Point2DArray.cpp
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// Copyright (C) 2019-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 "GeomData_Point2DArray.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Expression.h>
+#include <ModelAPI_Feature.h>
+
+#include <cassert>
+
+GeomData_Point2DArray::GeomData_Point2DArray(TDF_Label& theLabel)
+ : myLab(theLabel)
+{
+ reinit();
+}
+
+void GeomData_Point2DArray::reinit()
+{
+ // check the attribute could be already presented in this doc (after load document)
+ myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+}
+
+bool GeomData_Point2DArray::assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther)
+{
+ std::shared_ptr<GeomData_Point2DArray> anOther =
+ std::dynamic_pointer_cast<GeomData_Point2DArray>(theOther);
+ if (!anOther)
+ return false;
+
+ setSize(anOther->size());
+ myArray->ChangeArray(anOther->myArray->Array(), false);
+ owner()->data()->sendAttributeUpdated(this);
+
+ return true;
+}
+
+int GeomData_Point2DArray::size()
+{
+ if (myArray.IsNull() || !myArray->IsValid()) {
+ // this could be on undo and then redo creation of the attribute
+ // in result creation it may be uninitialized
+ myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+ }
+ // checking the validity because attribute (as a field) may be presented,
+ // but without label: it is undoed
+ return (myArray.IsNull() || !myArray->IsValid()) ? 0 : myArray->Length() / 2;
+}
+
+void GeomData_Point2DArray::setSize(const int theSize)
+{
+ int aValuesSize = 2 * theSize;
+ if (myArray.IsNull() || !myArray->IsValid()) { // create array if it is not done yet
+ if (aValuesSize != 0) { // if size is zero, nothing to do (null array means there is no array)
+ myArray = TDataStd_RealArray::Set(myLab, 0, aValuesSize - 1);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ else { // reset the old array
+ if (aValuesSize) {
+ if (aValuesSize != myArray->Length()) { // old data is kept in the new array
+ Handle(TColStd_HArray1OfReal) aNewArray = new TColStd_HArray1OfReal(0, aValuesSize - 1);
+ for (int anIndex = 0; anIndex < aValuesSize && anIndex <= myArray->Upper(); ++anIndex)
+ aNewArray->SetValue(anIndex, myArray->Value(anIndex));
+ myArray->ChangeArray(aNewArray);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ else { // size is zero => array must be erased
+ if (!myArray.IsNull()) {
+ myArray.Nullify();
+ myLab.ForgetAttribute(TDataStd_RealArray::GetID());
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex,
+ const double theX,
+ const double theY)
+{
+ if (myArray->Value(2 * theIndex) != theX || myArray->Value(2 * theIndex + 1) != theY) {
+ myArray->SetValue(2 * theIndex, theX);
+ myArray->SetValue(2 * theIndex + 1, theY);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex, const GeomPnt2dPtr& thePoint)
+{
+ setPnt(theIndex, thePoint->x(), thePoint->y());
+}
+
+GeomPnt2dPtr GeomData_Point2DArray::pnt(const int theIndex)
+{
+ GeomPnt2dPtr aPoint;
+ if (theIndex >= 0 && theIndex * 2 < myArray->Length())
+ aPoint.reset(new GeomAPI_Pnt2d(myArray->Value(2 * theIndex), myArray->Value(2 * theIndex + 1)));
+ return aPoint;
+}
--- /dev/null
+// Copyright (C) 2019-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 GeomData_Point2DArray_H_
+#define GeomData_Point2DArray_H_
+
+#include "GeomData.h"
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <TDataStd_RealArray.hxx>
+#include <TDF_Label.hxx>
+
+/** \class GeomData_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains an array of 2D points.
+ */
+class GeomData_Point2DArray : public GeomDataAPI_Point2DArray
+{
+ TDF_Label myLab; ///< the main label of the attribute
+ Handle_TDataStd_RealArray myArray; ///< array that keeps all coordinates of the points
+
+public:
+ /// Copy values from another array
+ /// \return \c true if the copy was successful
+ GEOMDATA_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther);
+
+ /// Returns the size of the array (zero means that it is empty)
+ GEOMDATA_EXPORT virtual int size();
+
+ /// Sets the new size of the array. The previous data is erased.
+ GEOMDATA_EXPORT virtual void setSize(const int theSize);
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+ const double theX, const double theY);
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+ /// Returns the value by the index
+ GEOMDATA_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex);
+
+protected:
+ /// Initializes attributes
+ GEOMDATA_EXPORT GeomData_Point2DArray(TDF_Label& theLabel);
+ /// Reinitializes the internal state of the attribute (may be needed on undo/redo, abort, etc)
+ virtual void reinit();
+
+ friend class Model_Data;
+};
+
+#endif
GeomDataAPI_Point.h
GeomDataAPI_Dir.h
GeomDataAPI_Point2D.h
+ GeomDataAPI_Point2DArray.h
)
SET(PROJECT_SOURCES
GeomDataAPI_Point.cpp
GeomDataAPI_Dir.cpp
GeomDataAPI_Point2D.cpp
+ GeomDataAPI_Point2DArray.cpp
)
SET(PROJECT_LIBRARIES
%shared_ptr(GeomDataAPI_Point)
%shared_ptr(GeomDataAPI_Dir)
%shared_ptr(GeomDataAPI_Point2D)
+%shared_ptr(GeomDataAPI_Point2DArray)
// all supported interfaces
%include "GeomDataAPI_Point.h"
%include "GeomDataAPI_Dir.h"
%include "GeomDataAPI_Point2D.h"
+%include "GeomDataAPI_Point2DArray.h"
template<class T> std::shared_ptr<T> castTo(std::shared_ptr<ModelAPI_Attribute> theObject);
%template(geomDataAPI_Point) castTo<GeomDataAPI_Point>;
%template(geomDataAPI_Dir) castTo<GeomDataAPI_Dir>;
%template(geomDataAPI_Point2D) castTo<GeomDataAPI_Point2D>;
+%template(geomDataAPI_Point2DArray) castTo<GeomDataAPI_Point2DArray>;
--- /dev/null
+// Copyright (C) 2019-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 <GeomDataAPI_Point2DArray.h>
+
+std::string GeomDataAPI_Point2DArray::attributeType()
+{
+ return typeId();
+}
+
+GeomDataAPI_Point2DArray::GeomDataAPI_Point2DArray()
+{
+}
+
+GeomDataAPI_Point2DArray::~GeomDataAPI_Point2DArray()
+{
+}
--- /dev/null
+// Copyright (C) 2019-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 GeomDataAPI_Point2DArray_H_
+#define GeomDataAPI_Point2DArray_H_
+
+#include <GeomDataAPI.h>
+#include <ModelAPI_Attribute.h>
+
+class GeomAPI_Pnt2d;
+
+/**\class GeomDataAPI_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains array of 2D point coordinates.
+ */
+
+class GeomDataAPI_Point2DArray : public ModelAPI_Attribute
+{
+public:
+ /// Copy values from another array
+ /// \return \c true if the copy was successful
+ GEOMDATAAPI_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther) = 0;
+
+ /// Returns the size of the array (zero means that it is empty)
+ GEOMDATAAPI_EXPORT virtual int size() = 0;
+
+ /// Sets the new size of the array. The previous data is erased.
+ GEOMDATAAPI_EXPORT virtual void setSize(const int theSize) = 0;
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+ const double theX, const double theY) = 0;
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) = 0;
+
+ /// Returns the value by the index
+ GEOMDATAAPI_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex) = 0;
+
+ /// Returns the type of this class of attributes
+ static std::string typeId()
+ {
+ return std::string("Point2DArray");
+ }
+
+ /// Returns the type of this class of attributes, not static method
+ GEOMDATAAPI_EXPORT virtual std::string attributeType();
+
+protected:
+ /// Objects are created for features automatically
+ GEOMDATAAPI_EXPORT GeomDataAPI_Point2DArray();
+ GEOMDATAAPI_EXPORT virtual ~GeomDataAPI_Point2DArray();
+};
+
+typedef std::shared_ptr<GeomDataAPI_Point2DArray> AttributePoint2DArrayPtr;
+
+#endif
#include "GeomDataAPI_Point.h"
#include "GeomDataAPI_Dir.h"
#include "GeomDataAPI_Point2D.h"
+ #include "GeomDataAPI_Point2DArray.h"
#include <memory>
#include <string>
void Model_AttributeRefAttrList::append(ObjectPtr theObject)
{
- std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
- myRef->Append(aData->label().Father()); // store label of the object
+ TDF_Label aLabel;
+ if (theObject) {
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
+ aLabel = aData->label().Father();
+ }
+
+ myRef->Append(aLabel); // store label of the object
myIDs->Append(""); // for the object store an empty string
// do it before the transaction finish to make just created/removed objects know dependencies
// and reference from composite feature is removed automatically
myIDs->Append(anIDIter.Value());
} else { // found, so need to update the dependencies
aOneisDeleted = true;
- ObjectPtr anObj = aDoc->objects()->object(aRefIter.Value());
+ ObjectPtr anObj;
+ if (!aRefIter.Value().IsNull())
+ anObj = aDoc->objects()->object(aRefIter.Value());
if (anObj.get()) {
REMOVE_BACK_REF(anObj);
}
Handle(TDataStd_AsciiString) anEntry;
if (myRef->Label().FindAttribute(TDataStd_AsciiString::GetID(), anEntry)) {
std::shared_ptr<Model_Document> aDR = std::dynamic_pointer_cast<Model_Document>(aRefDoc);
- TDF_Label aRefLab;
- TDF_Tool::Label(aDR->objects()->featuresLabel().Data(),
- anEntry->Get().ToCString(), aRefLab);
- if (!aRefLab.IsNull()) {
- return aDR->objects()->object(aRefLab);
+ if (aDR.get() && aDR->objects()) {
+ TDF_Label aRefLab;
+ TDF_Tool::Label(aDR->objects()->featuresLabel().Data(),
+ anEntry->Get().ToCString(), aRefLab);
+ if (!aRefLab.IsNull()) {
+ return aDR->objects()->object(aRefLab);
+ }
}
}
}
} else if (theContext->groupName() == ModelAPI_ResultGroup::group()) {
aSelLab.ForgetAllAttributes(true);
TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID);
- } else { // check the feature context: parent-Part of this feature should not be used
+ } else { // check the feature context: only construction features of PartSet could be selected
FeaturePtr aFeatureContext = std::dynamic_pointer_cast<ModelAPI_Feature>(theContext);
- if (aFeatureContext.get()) {
- if (owner()->document() != aFeatureContext->document()) {
+ if (aFeatureContext.get() && owner()->document() != aFeatureContext->document()) {
+ if (aFeatureContext->results().empty() ||
+ aFeatureContext->firstResult()->groupName() != ModelAPI_ResultConstruction::group()) {
aSelLab.ForgetAllAttributes(true);
myRef.setValue(ObjectPtr());
if (aToUnblock)
CenterType aCenterType = NOT_CENTER;
std::shared_ptr<GeomAPI_Shape> aSubSh = internalValue(aCenterType);
- ResultPtr aCont = context();
- if (!aCont.get() ||
- (aCont->groupName() == ModelAPI_ResultConstruction::group() && contextFeature().get())) {
+ FeaturePtr aContFeature = contextFeature();
+ if (aContFeature.get()) {
+ std::string aResName;
+ // checking part-owner
+ if (aContFeature->document() != owner()->document())
+ aResName += aContFeature->document()->kind() + "/";
// selection of a full feature
- FeaturePtr aFeatureCont = contextFeature();
- if (aFeatureCont.get()) {
- return kWHOLE_FEATURE + aFeatureCont->name();
+ if (aContFeature.get()) {
+ return aResName + kWHOLE_FEATURE + aContFeature->name();
}
// in case of selection of removed result
return "";
}
+ ResultPtr aCont = context();
+ if (!aCont.get()) {
+ return ""; // invalid case
+ }
TDF_Label aSelLab = selectionLabel();
if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value
return contextName(aCont);
if (aPartName == aRootDoc->kind()) {
aDoc = std::dynamic_pointer_cast<Model_Document>(aRootDoc);
aSubShapeName = aSubShapeName.substr(aPartEnd + 1);
- } else {
+ }
+ else {
ObjectPtr aFound =
owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
if (aFound.get()) { // found such part, so asking it for the name
continue;
std::shared_ptr<GeomAPI_Edge> aSelectedEdge(new GeomAPI_Edge(aSelected));
setValueCenter(aPart, aSelectedEdge, aCenterType);
- } else
+ }
+ else
setValue(aPart, aSelected);
TDataStd_Integer::Set(selectionLabel(), anIndex);
return;
}
+ } else { // for the ImportResult feature Objects widget this may be a result in other part
+ // result may be hidden (like, tranlsatiomn of part) in PartSet, so iterate Part-features
+ int aNum = aRootDoc->size(ModelAPI_Feature::group());
+ for (int a = 0; a < aNum; a++) {
+ FeaturePtr aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(
+ aRootDoc->object(ModelAPI_Feature::group(), a));
+ if (aFeat.get() && aFeat->data() && aFeat->data()->isValid() &&
+ aFeat->getKind() == "Part" && aFeat->results().size()) {
+ ResultPartPtr aPart =
+ std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFeat->firstResult());
+ if (aPart.get() && aPart->partDoc().get() && aPart->data()->name() == aPartName) {
+ aDoc = std::dynamic_pointer_cast<Model_Document>(aPart->partDoc());
+ aSubShapeName = aSubShapeName.substr(aPartEnd + 1);
+ }
+ }
+ }
}
}
}
void Model_AttributeSelection::concealedFeature(
- const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers,
- const ResultPtr theResultOfFeature)
+ const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
+ std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature)
{
std::set<FeaturePtr> alreadyProcessed;
alreadyProcessed.insert(theFeature);
if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
continue;
alreadyProcessed.insert(aRefFeat);
- if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+ if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id())
+ || (theCheckCopy &&
+ std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aRefFeat).get()))
{
// for extrusion cut in python script the nested sketch reference may be concealed before
// it is nested, so, check this composite feature is valid
TDF_Label theAccessLabel,
std::list<ResultPtr>& theResults, TopTools_ListOfShape& theValShapes)
{
- std::set<ResultPtr> aResults; // to avoid duplicates, new context, null if deleted
+ std::list<ResultPtr> aResults; // keep order, new context, null if deleted
+ std::set<ResultPtr> aResultsSet; // to avoid duplicates
// iterate context and shape, but also if it is sub-shape of main shape, check also it
TopTools_ListOfShape aContextList;
aContextList.Append(theContShape);
Handle(TNaming_NamedShape) aNewNS;
aModifIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNewNS);
if (aNewNS->Evolution() == TNaming_MODIFY || aNewNS->Evolution() == TNaming_GENERATED) {
- aResults.insert(aModifierObj);
+ if (aResultsSet.find(aModifierObj) == aResultsSet.end()) {
+ aResultsSet.insert(aModifierObj);
+ aResults.push_back(aModifierObj);
+ }
} else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is empty
- aResults.insert(ResultPtr());
+ aResults.push_back(ResultPtr());
} else { // not-processed modification => don't support it
continue;
}
}
}
// if there exist context composite and sub-result(s), leave only sub(s)
- for(std::set<ResultPtr>::iterator aResIter = aResults.begin(); aResIter != aResults.end();) {
+ for(std::list<ResultPtr>::iterator aResIter = aResults.begin(); aResIter != aResults.end();) {
ResultPtr aParent = ModelAPI_Tools::bodyOwner(*aResIter);
for(; aParent.get(); aParent = ModelAPI_Tools::bodyOwner(aParent))
- if (aResults.count(aParent))
+ if (aResultsSet.count(aParent))
break;
- if (aParent.get()) { // erase from set, so, restart iteration
- aResults.erase(aParent);
- aResIter = aResults.begin();
+ if (aParent.get()) {
+ aResultsSet.erase(aParent);
+ for(std::list<ResultPtr>::iterator anIt = aResults.begin(); anIt != aResults.end(); anIt++) {
+ if (*anIt == aParent) {
+ aResults.erase(anIt);
+ aResIter = aResults.begin(); // erase from set, so, restart iteration
+ break;
+ }
+ }
} else aResIter++;
}
+ bool aStaySame = false;
if (aResults.empty()) {
// check the context become concealed by operation which is earlier than this selection
FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
FeaturePtr aContextOwner = theDoc->feature(theContext);
std::list<FeaturePtr> aConcealers;
- concealedFeature(aContextOwner, aThisFeature, aConcealers, theContext);
+ concealedFeature(aContextOwner, aThisFeature, false, aConcealers, theContext);
std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
for(; aConcealer != aConcealers.end(); aConcealer++) {
std::list<ResultPtr> aRefResults;
continue;
if (aRefShape->impl<TopoDS_Shape>().IsSame(theContShape)) {
// add the new context result with the same shape
- aResults.insert(aRefBody);
+ aResults.push_back(aRefBody);
}
}
if (aResults.empty())
return true; // feature conceals result, return true, so the context will be removed
}
- if (aResults.empty())
- return false; // no modifications found, must stay the same
+ aStaySame = aResults.empty();
+ }
+ if (myParent && myParent->isMakeCopy()) {
+ // check there are copies before the new results, so, make a copy
+ std::list<ObjectPtr> aCopyContext;
+ std::list<GeomShapePtr> aCopyVals;
+ // features between the new and the old: check the "Move" interface to get a copy
+ FeaturePtr aRootOwner = theDoc->feature(theContext);
+ FeaturePtr anOwner = ModelAPI_Tools::compositeOwner(aRootOwner);
+ for(; anOwner.get(); anOwner = ModelAPI_Tools::compositeOwner(anOwner))
+ aRootOwner = anOwner;
+ FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+ // iterate all results to find a "Copy" features between the new and one and to add the
+ // copy-results also to results if this attribute refers to the copied shape
+ int anIndex = kUNDEFINED_FEATURE_INDEX;
+ for(FeaturePtr aFeat = theDoc->objects()->nextFeature(aRootOwner, anIndex); aFeat.get() &&
+ aFeat != aThisFeature; aFeat = theDoc->objects()->nextFeature(aFeat, anIndex)) {
+ std::shared_ptr<ModelAPI_FeatureCopyInterface> aCopier =
+ std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aFeat);
+ if (aCopier.get()) {
+ GeomShapePtr aValShape(new GeomAPI_Shape);
+ aValShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(
+ theValShape.IsNull() ? theContShape : theValShape));
+ aCopier->getCopies(theContext, aValShape, aCopyContext, aCopyVals);
+ }
+ }
+ // check for the further modifications of the copy contexts and values
+ std::list<ObjectPtr>::iterator aCopyContIter = aCopyContext.begin();
+ std::list<GeomShapePtr>::iterator aCopyValIter = aCopyVals.begin();
+ for(; aCopyContIter != aCopyContext.end(); aCopyContIter++, aCopyValIter++) {
+ ResultPtr aNewCont = std::dynamic_pointer_cast<ModelAPI_Result>(*aCopyContIter);
+ TopoDS_Shape aNewContShape = aNewCont->shape()->impl<TopoDS_Shape>();
+ GeomShapePtr aNewVal = *aCopyValIter;
+ TopoDS_Shape aNewValShape;
+ if (aNewVal.get() && !aNewVal->isNull())
+ aNewValShape = aNewVal->impl<TopoDS_Shape>();
+ std::list<ResultPtr> aNewRes;
+ TopTools_ListOfShape aNewUpdatedVal;
+ if (searchNewContext(theDoc, aNewContShape, aNewCont, aNewValShape,
+ theAccessLabel, aNewRes, aNewUpdatedVal)) {
+ // append new results instead of the current ones
+ std::list<ResultPtr>::iterator aNewIter = aNewRes.begin();
+ TopTools_ListIteratorOfListOfShape aNewUpdVal(aNewUpdatedVal);
+ for(; aNewIter != aNewRes.end(); aNewIter++, aNewUpdVal.Next()) {
+ theResults.push_back(*aNewIter);
+ theValShapes.Append(aNewUpdVal.Value());
+ }
+ } else { // the current result is good
+ theResults.push_back(aNewCont);
+ theValShapes.Append(aNewValShape);
+ }
+ }
+ if (aStaySame && !theResults.empty()) { // no changes except copy, so, keep the origin as first
+ theResults.push_front(theContext);
+ theValShapes.Prepend(theValShape);
+ return true;
+ }
}
+ if (aStaySame)
+ return false;
+
// iterate all results to find further modifications
- std::set<ResultPtr>::iterator aResIter = aResults.begin();
- for(; aResIter != aResults.end(); aResIter++) {
+ std::list<ResultPtr>::iterator aResIter = aResults.begin();
+ for(aResIter = aResults.begin(); aResIter != aResults.end(); aResIter++) {
if (aResIter->get() != NULL) {
+ ResultPtr aNewResObj = *aResIter;
// compute new values by two contexts: the old and the new
TopTools_ListOfShape aValShapes;
- computeValues(theContext, *aResIter, theValShape, aValShapes);
+ computeValues(theContext, aNewResObj, theValShape, aValShapes);
TopTools_ListIteratorOfListOfShape aNewVal(aValShapes);
for(; aNewVal.More(); aNewVal.Next()) {
std::list<ResultPtr> aNewRes;
TopTools_ListOfShape aNewUpdatedVal;
TopoDS_Shape aNewValSh = aNewVal.Value();
- TopoDS_Shape aNewContShape = (*aResIter)->shape()->impl<TopoDS_Shape>();
+ TopoDS_Shape aNewContShape = aNewResObj->shape()->impl<TopoDS_Shape>();
+
if (theValShape.IsNull() && aNewContShape.IsSame(aNewValSh))
aNewValSh.Nullify();
- if (searchNewContext(theDoc, aNewContShape, *aResIter, aNewValSh,
+ if (searchNewContext(theDoc, aNewContShape, aNewResObj, aNewValSh,
theAccessLabel, aNewRes, aNewUpdatedVal))
{
// append new results instead of the current ones
theValShapes.Append(aNewUpdVal.Value());
}
} else { // the current result is good
- theResults.push_back(*aResIter);
+ theResults.push_back(aNewResObj);
theValShapes.Append(aNewValSh);
}
}
if (aFeature.get()) {
FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
std::list<FeaturePtr> aConcealers;
- concealedFeature(aFeature, aThisFeature, aConcealers, ResultPtr());
+ bool aCopyPossible = myParent && myParent->isMakeCopy();
+ concealedFeature(aFeature, aThisFeature, aCopyPossible, aConcealers, ResultPtr());
if (aConcealers.empty())
return;
+ // if there are copies, but no direct modification, keep the original
+ bool aKeepOrigin = false;
+ if (aCopyPossible) {
+ std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+ for(aKeepOrigin = true; aConcealer != aConcealers.end(); aConcealer++)
+ if (!std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(*aConcealer).get()) {
+ aKeepOrigin = false;
+ break;
+ }
+ if (aKeepOrigin) {
+ aConcealers.push_front(aFeature);
+ }
+ }
bool aChanged = false;
std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
for(; aConcealer != aConcealers.end(); aConcealer++)
- if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
- setValue(*aConcealer, anEmptyShape);
- aChanged = true;
- }
- if (aConcealer == aConcealers.end()) {
- if (!aChanged) // remove this
- theRemove = true;
- } else { // append new
- for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
- if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+ if (aChanged) {
+ if (aKeepOrigin || !myParent->isInList(*aConcealer, anEmptyShape))
myParent->append(*aConcealer, anEmptyShape);
- }
- if (aChanged) // searching for the further modifications
+ } else {
+ if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+ setValue(*aConcealer, anEmptyShape);
+ aChanged = true;
+ } else if (aCopyPossible && *aConcealer == aFeature) {// keep origin in case of copy
+ aChanged = true;
+ }
+ }
+ if (!aChanged) // remove this
+ theRemove = true;
+ else if (!aKeepOrigin) // searching further modifications only if current changed
updateInHistory(theRemove);
}
}
if (!myParent || !myParent->isInList(aNewContext, aValueShape)) { // avoid duplicates
setValue(aNewContext, aValueShape);
aFirst = false;
+ } else if (aNewContext == aContext && myParent && myParent->isMakeCopy()) {
+ // this may be exactly the old one, not modified in case of copy
+ aFirst = false;
}
} else if (myParent) {
if (!myParent->isInList(aNewContext, aValueShape)) // avoid addition of duplicates
/// Returns features that conceals theFeature and located in history before theStop
/// theResultOfFeature if not null defines exact referenced result of a feature
void concealedFeature(
- const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers,
- const ResultPtr theResultOfFeature);
+ const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
+ std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature);
friend class Model_Data;
friend class Model_AttributeSelectionList;
}
}
+void Model_AttributeSelectionList::copyTo(AttributeSelectionListPtr theTarget) const
+{
+ std::shared_ptr<Model_AttributeSelectionList> aTarget =
+ std::dynamic_pointer_cast<Model_AttributeSelectionList>(theTarget);
+ if (aTarget) {
+ copyAttrs(myLab, aTarget->myLab);
+ aTarget->reinit();
+ }
+}
+
int Model_AttributeSelectionList::size()
{
return mySize->Get();
MODEL_EXPORT virtual void append(const std::string& theType, const std::string& theContextName,
const int theIndex);
+ /// Copy the selection list to the destination attribute
+ MODEL_EXPORT virtual void copyTo(AttributeSelectionListPtr theTarget) const;
+
/// Reset temporary stored values
virtual void removeTemporaryValues();
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomData_Point.h>
#include <GeomData_Point2D.h>
+#include <GeomData_Point2DArray.h>
#include <GeomData_Dir.h>
#include <Events_Loop.h>
#include <Events_InfoMessage.h>
}
anAttribute->myIsInitialized = anAllInitialized;
anAttr = anAttribute;
+ } else if (theAttrType == GeomData_Point2DArray::typeId()) {
+ anAttr = new GeomData_Point2DArray(anAttrLab);
}
+
if (anAttr) {
aResult = std::shared_ptr<ModelAPI_Attribute>(anAttr);
myAttrs[theID] = std::pair<AttributePtr, int>(aResult, anAttrIndex);
} while (aSub.get());
}
+ AttributeSelectionListPtr aMovedList;
+ if (theMoved->getKind() == "Group") {
+ aMovedList = theMoved->selectionList("group_list");
+ if (aMovedList.get())
+ aMovedList->setMakeCopy(true);
+ }
myObjs->moveFeature(theMoved, anAfterThisSub);
if (theSplit) { // split the group into sub-features
// must be after move to make enabled all features which are before theMoved
setCurrentFeature(theMoved, true);
}
-
- if (theSplit) { // split the group into sub-features
- theMoved->customAction("split");
- }
+ if (aMovedList.get())
+ aMovedList->setMakeCopy(false);
}
void Model_Document::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
if (theBelow)
continue;
- // if feature is in sub-component, skip it
- FeaturePtr aCurFeature = feature(aCurLabel);
- if (isSkippedFeature(aCurFeature))
- continue;
-
+ // issue #18733: check for the last feature in folder before checking the sub-feature,
+ // because the folder may end by the feature which is
+ // neither a sub-feature nor a feature in history.
if (!aLastFeatureInFolder.IsNull()) {
if (IsEqual(aCurLabel, aLastFeatureInFolder))
aLastFeatureInFolder.Nullify(); // the last feature in the folder is achieved
continue;
}
+ // if feature is in sub-component, skip it
+ FeaturePtr aCurFeature = feature(aCurLabel);
+ if (isSkippedFeature(aCurFeature))
+ continue;
+
const ObjectPtr& aFolderObj = folder(aCurLabel);
if (aFolderObj.get()) {
aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aFolderObj);
}
}
+void Model_ResultBody::loadFirstLevel(GeomShapePtr theShape, const std::string& theName)
+{
+ if (mySubs.size()) { // consists of subs
+ for (std::vector<ResultBodyPtr>::const_iterator aSubIter = mySubs.cbegin();
+ aSubIter != mySubs.cend();
+ ++aSubIter)
+ {
+ const ResultBodyPtr& aSub = *aSubIter;
+ aSub->loadFirstLevel(theShape, theName);
+ }
+ } else { // do for this directly
+ myBuilder->loadFirstLevel(theShape, theName);
+ }
+}
+
int Model_ResultBody::numberOfSubs(bool forTree) const
{
return int(mySubs.size());
const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
const std::string& theName = "") override;
+ /// load shapes of the first level (to be used during shape import)
+ MODEL_EXPORT virtual void loadFirstLevel(GeomShapePtr theShape, const std::string& theName);
/// Returns the number of sub-elements
MODEL_EXPORT virtual int numberOfSubs(bool forTree = false) const;
SessionPtr aMgr = ModelAPI_Session::get();
if (!aMgr->isOperation()) {
// open transaction even document is not created to set current docs in setActiveDocument
- aMgr->startOperation("Activation");
+ std::string aMsg = "Activation " + data()->name();
+ aMgr->startOperation(aMsg);
isNewTransaction = true;
}
if (!aDocRef->value().get()) { // create (or open) a document if it is not yet created
}
}
+
+void Model_ResultPart::loadPart()
+{
+ std::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = data()->document(DOC_REF());
+ if (!aDocRef->value().get()) { // create (or open) a document if it is not yet created
+ Handle(Model_Application) anApp = Model_Application::getApplication();
+ if (anApp->isLoadByDemand(data()->name(), aDocRef->docId())) {
+ anApp->loadDocument(data()->name(), aDocRef->docId()); // if it is just new part, load fails
+ }
+ else {
+ anApp->createDocument(aDocRef->docId());
+ }
+ }
+}
+
+
std::shared_ptr<ModelAPI_ResultPart> Model_ResultPart::original()
{
if (myTrsf.get() && baseRef().get()) { // the second condition is due to #2035
/// Returns the shape selected in the selection index
MODEL_EXPORT virtual std::shared_ptr<GeomAPI_Shape> selectionValue(const int theIndex);
+ /// Loading the part from file
+ MODEL_EXPORT virtual void loadPart();
+
protected:
/// makes a result on a temporary feature (an action)
Model_ResultPart();
return false;
}
+ // check this feature is not yet checked or processed
+ bool aIsModified = myModified.find(theFeature) != myModified.end();
+ if (!aIsModified && myIsFinish) { // get info about the modification for features without preview
+ if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) {
+ aIsModified = true;
+ std::set<std::shared_ptr<ModelAPI_Feature> > aNewSet;
+ // contains itself, so, we don't know which was the reason and the reason is any
+ aNewSet.insert(theFeature);
+ myModified[theFeature] = aNewSet;
+ }
+ }
+
if (myProcessed.find(theFeature) == myProcessed.end()) {
myProcessed[theFeature] = 0;
- } else {
+ } else if (aIsModified) {
int aCount = myProcessed[theFeature];
if (aCount > 100) {
// too many repetition of processing (in VS it may crash on 330 with stack overflow)
myProcessed[theFeature] = aCount + 1;
}
- // check this feature is not yet checked or processed
- bool aIsModified = myModified.find(theFeature) != myModified.end();
- if (!aIsModified && myIsFinish) { // get info about the modification for features without preview
- if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) {
- aIsModified = true;
- std::set<std::shared_ptr<ModelAPI_Feature> > aNewSet;
- // contains itself, so, we don't know which was the reason and the reason is any
- aNewSet.insert(theFeature);
- myModified[theFeature] = aNewSet;
- }
- }
-
#ifdef DEB_UPDATE
std::cout<<"* Process feature "<<theFeature->name()<<std::endl;
#endif
Test2901.py
Test2903.py
Test3020.py
+ Test3116.py
)
%template(PointList) std::list<std::shared_ptr<GeomAPI_Pnt> >;
%template(PointSet) std::set<std::shared_ptr<GeomAPI_Pnt> >;
-// Geometry casts
-%template(shapeToEdge) shared_ptr_cast<GeomAPI_Edge, GeomAPI_Shape>;
-
template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
%template(featureToPresentation) shared_ptr_cast<GeomAPI_IPresentable, ModelAPI_Feature>;
/// may be sub-objects, so, it is the same as all sub-shapes are selected (#3005). It is "false"
/// by default.
bool myIsWholeResultAllowed;
- public:
+ /// Flag that indicates that update in history must check the copy-features
+ /// and make a copy of selection for them.
+ bool myMakeCopy;
+public:
/// Adds the new reference to the end of the list
/// \param theContext object where the sub-shape was selected
/// \param theSubShape selected sub-shape (if null, the whole context is selected)
virtual void append(const std::string& theType, const std::string& theContextName,
const int theIndex) = 0;
+ /// Copy the selection list to the destination attribute
+ virtual void copyTo(std::shared_ptr<ModelAPI_AttributeSelectionList> theTarget) const = 0;
+
/// Reset temporary stored values
virtual void removeTemporaryValues() = 0;
myIsWholeResultAllowed = theFlag;
}
+ /// Returns true if a copy features must be used in update in history.
+ MODELAPI_EXPORT virtual const bool isMakeCopy() const {
+ return myMakeCopy;
+ }
+
+ /// Sets true if a copy features must be used in update in history.
+ MODELAPI_EXPORT virtual void setMakeCopy(const bool theFlag) {
+ myMakeCopy = theFlag;
+ }
+
protected:
/// Default constructor
MODELAPI_EXPORT ModelAPI_AttributeSelectionList() : ModelAPI_Attribute()
- {myIsWholeResultAllowed = false;}
+ {myIsWholeResultAllowed = false; myMakeCopy = false;}
};
myMovedAttribute = AttributePtr();
}
-void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute)
+void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute,
+ const int thePointIndex)
{
myMovedAttribute = theMovedAttribute;
myMovedObject = ObjectPtr();
+ myMovedPointIndex = thePointIndex;
}
void ModelAPI_ObjectMovedMessage::setOriginalPosition(double theX, double theY)
{
ObjectPtr myMovedObject;
AttributePtr myMovedAttribute;
+ int myMovedPointIndex;
std::shared_ptr<GeomAPI_Pnt2d> myOriginalPosition;
std::shared_ptr<GeomAPI_Pnt2d> myCurrentPosition;
/// Set object which is being moved (if the message already contains attribute it will be cleared)
MODELAPI_EXPORT void setMovedObject(const ObjectPtr& theMovedObject);
/// Set attribute which is being moved (if the message already contains object it will be cleared)
- MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute);
+ /// \param[in] theMovedAttribute moved attribute
+ /// \param[in] thePointIndex index of the point if the moved attribute is an array of points
+ MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute,
+ const int thePointIndex = -1);
/// Return moved object
ObjectPtr movedObject() const
/// Return moved attribute
AttributePtr movedAttribute() const
{ return myMovedAttribute; }
+ /// Return index of the moved point
+ int movedPointIndex() const
+ { return myMovedPointIndex; }
/// Set original mouse position
MODELAPI_EXPORT void setOriginalPosition(double theX, double theY);
//! Pointer on feature object
typedef std::shared_ptr<ModelAPI_Feature> FeaturePtr;
-#endif
+//! An interface for performing special copy actions. To give feature which is moved (a group)
+//! over this feature.
+class ModelAPI_FeatureCopyInterface {
+public:
+ /// An algorithm to update the moved feature by the separate Copy feature
+ /// \param theContext the original context object
+ /// \param theValue the original shape
+ /// \param theCopies resulting copy-context will be appended here
+ virtual void getCopies(ObjectPtr theContext, std::shared_ptr<GeomAPI_Shape> theValue,
+ std::list<ObjectPtr>& theCopyContext,
+ std::list<std::shared_ptr<GeomAPI_Shape> >& theCopyVals) = 0;
+};
+#endif
myBuilder->loadDeletedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theShapesToExclude);
}
-void ModelAPI_ResultBody::loadFirstLevel(GeomShapePtr theShape,
- const std::string& theName)
-{
- myBuilder->loadFirstLevel(theShape, theName);
-}
-
// LCOV_EXCL_START
bool ModelAPI_ResultBody::isConnectedTopology()
{
/// load shapes of the first level (to be used during shape import)
MODELAPI_EXPORT virtual void loadFirstLevel(GeomShapePtr theShape,
- const std::string& theName);
+ const std::string& theName) = 0;
/// Returns true is the topology is connected.
MODELAPI_EXPORT virtual bool isConnectedTopology() = 0;
/// Updates the shape-result of the part (called on Part feature execution)
virtual void updateShape() = 0;
+
+ /// Loading the part from file
+ virtual void loadPart() = 0;
};
//! Pointer on feature object
// check the referred object is a Body
// (for example, ExtrusionCut has a sketch as a first attribute which is concealing)
bool isBody = aRefIt->second.size() > 1 || (aRefIt->second.size() == 1 &&
+ aRefIt->second.front().get() &&
aRefIt->second.front()->groupName() == ModelAPI_ResultBody::group());
if (isBody && (isMainArg || aFoundRef == aReferences.end() ||
aData->isPrecedingAttribute(aRefIt->first, aFoundRef->first)))
#include <memory>
#include <string>
- template<class T1, class T2>
- std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject)
- {
- return std::dynamic_pointer_cast<T1>(theObject);
- }
-
#endif /* SRC_MODELAPI_MODELAPI_SWIG_H_ */
--- /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
+#
+
+# Cheching for selection of the whole feature (Sketch) in PartSet from the Part
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(16, 15, 3)
+model.do()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("COMPOUND", "PartSet/all-in-Sketch_1")], False)
+model.end()
+
+# check the result validity
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Edge_1.feature()))
+
+assert(model.checkPythonDump())
TestDeflectionDump.py
TestUndoRedo.py
Test2488.py
+ Test18451.py
)
}
}
+
+%typemap(in) const std::list<int> & (std::list<int> temp) {
+ int newmem = 0;
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ if (PyLong_Check(item)) {
+ temp.push_back((int)PyLong_AsLong(item));
+ } else {
+ PyErr_SetString(PyExc_TypeError, "argument must integet value.");
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+ $1 = &temp;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a tuple of integer values.");
+ return NULL;
+ }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<int>, const std::list<int>& {
+ int newmem = 0;
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ if (PyLong_Check(item)) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ break;
+ }
+ Py_DECREF(item);
+ }
+ } else {
+ $1 = 0;
+ }
+}
+
+
%typemap(in) const std::list<double> & (std::list<double> temp) {
- double * temp_attribute;
int newmem = 0;
if (PyTuple_Check($input)) {
for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
}
%typecheck(SWIG_TYPECHECK_POINTER) std::list<double>, const std::list<double>& {
- double * temp_object;
- std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
int newmem = 0;
if (PyTuple_Check($input)) {
for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
}
}
+
+%typemap(in) const std::list<ModelHighAPI_Double> & (std::list<ModelHighAPI_Double> temp) {
+ ModelHighAPI_Double * temp_double;
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ if (PyFloat_Check(item) || PyLong_Check(item)) {
+ temp.push_back(ModelHighAPI_Double(PyFloat_AsDouble(item)));
+ } else if (PyUnicode_Check(item)) {
+ temp.push_back(ModelHighAPI_Double(PyUnicode_AsUTF8(item)));
+ } else if ((SWIG_ConvertPtr(item, (void **)&temp_double, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) {
+ temp.push_back(*temp_double);
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Double, float, int or string.");
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+ $1 = &temp;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Double, float, int or string.");
+ return NULL;
+ }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<ModelHighAPI_Double>, const std::list<ModelHighAPI_Double> & {
+ if (PySequence_Check($input)) {
+ $1 = 1;
+ for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ $1 = ((PyFloat_Check(item) || PyLong_Check(item) || PyUnicode_Check(item)) && !PyBool_Check(item)) ? 1 : 0;
+ Py_DECREF(item);
+ }
+ } else {
+ $1 = 0;
+ }
+}
+
+
+%typemap(in) const std::list<ModelHighAPI_Integer> & (std::list<ModelHighAPI_Integer> temp) {
+ ModelHighAPI_Integer * temp_int;
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ if (PyLong_Check(item)) {
+ temp.push_back(ModelHighAPI_Integer(PyLong_AsLong(item)));
+ } else if (PyUnicode_Check(item)) {
+ temp.push_back(ModelHighAPI_Integer(PyUnicode_AsUTF8(item)));
+ } else if ((SWIG_ConvertPtr(item, (void **)&temp_int, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) {
+ temp.push_back(*temp_int);
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Integer, int or string.");
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+ $1 = &temp;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Integer, int or string.");
+ return NULL;
+ }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<ModelHighAPI_Integer>, const std::list<ModelHighAPI_Integer> & {
+ if (PySequence_Check($input)) {
+ $1 = 1;
+ for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ $1 = ((PyLong_Check(item) || PyUnicode_Check(item)) && !PyBool_Check(item)) ? 1 : 0;
+ Py_DECREF(item);
+ }
+ } else {
+ $1 = 0;
+ }
+}
+
+
// all supported interfaces
%include "ModelHighAPI_Double.h"
%include "ModelHighAPI_Dumper.h"
{
}
+double ModelHighAPI_Double::value() const
+{
+ // needed for array of double, which supports no text
+ return myDouble;
+}
+
//--------------------------------------------------------------------------------------
void ModelHighAPI_Double::fillAttribute(
const std::shared_ptr<ModelAPI_AttributeDouble> & theAttribute) const
const ModelHighAPI_Double & theY,
const ModelHighAPI_Double & theZ) const;
+ /// Value of the attribute
+ MODELHIGHAPI_EXPORT double value() const;
+
private:
enum VariantType { VT_DOUBLE, VT_STRING } myVariantType;
double myDouble;
#include <Config_PropManager.h>
#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Dir.h>
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_ShapeIterator.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_AttributeBoolean.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<GeomDataAPI_Point2DArray>& thePointArray)
+{
+ static const int aThreshold = 4;
+ static bool aDumpAsIs = false;
+ static std::string aSeparator = "";
+ // if number of elements in the list if greater than a threshold,
+ // dump it in a separate line with specific name
+ int aSize = thePointArray->size();
+ if (aDumpAsIs || aSize <= aThreshold) {
+ *myDumpStorage << "[";
+ GeomPnt2dPtr aPoint = thePointArray->pnt(0);
+ *myDumpStorage << "(" << aPoint->x() << ", " << aPoint->y() << ")";
+ for (int anIndex = 1; anIndex < aSize; ++anIndex) {
+ aPoint = thePointArray->pnt(anIndex);
+ *myDumpStorage << "," << aSeparator << " (" << aPoint->x() << ", " << aPoint->y() << ")";
+ }
+ *myDumpStorage << aSeparator << "]";
+ }
+ else {
+ // name of list
+ FeaturePtr anOwner = ModelAPI_Feature::feature(thePointArray->owner());
+ std::string aListName = name(anOwner) + "_" + thePointArray->id();
+ // reserve dumped buffer and store list "as is"
+ myDumpStorage->reserveBuffer();
+ aDumpAsIs = true;
+ aSeparator = std::string("\n") + std::string(aListName.size() + 3, ' ');
+ *this << aListName << " = " << thePointArray << "\n";
+ aDumpAsIs = false;
+ aSeparator = "";
+ // append reserved data to the end of the current buffer
+ myDumpStorage->restoreReservedBuffer();
+ *myDumpStorage << aListName;
+ }
+ return *this;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeBoolean>& theAttrBool)
{
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeIntArray>& theArray)
+{
+ *myDumpStorage << "[";
+ int aSize = theArray->size();
+ if (aSize > 0) {
+ *myDumpStorage << theArray->value(0);
+ for (int anIndex = 1; anIndex < aSize; ++anIndex)
+ *myDumpStorage << ", " << theArray->value(anIndex);
+ }
+ *myDumpStorage << "]";
+ return *this;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal)
{
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray>& theArray)
+{
+ *myDumpStorage << "[";
+ int aSize = theArray->size();
+ if (aSize > 0) {
+ *myDumpStorage << theArray->value(0);
+ for (int anIndex = 1; anIndex < aSize; ++anIndex)
+ *myDumpStorage << ", " << theArray->value(anIndex);
+ }
+ *myDumpStorage << "]";
+ return *this;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
{
class GeomDataAPI_Dir;
class GeomDataAPI_Point;
class GeomDataAPI_Point2D;
+class GeomDataAPI_Point2DArray;
class ModelAPI_Attribute;
class ModelAPI_AttributeBoolean;
class ModelAPI_AttributeDouble;
+class ModelAPI_AttributeDoubleArray;
+class ModelAPI_AttributeIntArray;
class ModelAPI_AttributeInteger;
class ModelAPI_AttributeRefAttr;
class ModelAPI_AttributeRefAttrList;
/// "X, Y"
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint);
+ /// Dump GeomDataAPI_Point2DArray as a list of 2D points
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const std::shared_ptr<GeomDataAPI_Point2DArray>& thePointArray);
/// Dump AttributeBoolean
MODELHIGHAPI_EXPORT
/// Dump AttributeInteger
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt);
+ /// Dump AttributeIntArray
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeIntArray>& theArray);
/// Dump AttributeDouble
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal);
+ /// Dump AttributeDoubleArray
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeDoubleArray>& theArray);
/// Dump AttributeString
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr);
for (int i = 0; i < theSize; ++i) {
if (i > 0)
theOutput << " ";
- theOutput << std::fixed << setprecision(thePrecision)
+ theOutput << std::fixed << std::setprecision(thePrecision)
<< (fabs(theArray[i]) < TOLERANCE ? 0.0 : theArray[i]);
}
}
} else if (aType == ModelAPI_AttributeInteger::typeId()) {
AttributeIntegerPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttr);
// do not dump a type of ConstraintAngle, because it can be changed due dumping
- if (anAttr->id() == "AngleType") {
+ if (anAttr->id() == "AngleType" || anAttr->id() == "AngleTypePrevious") {
return "";
} else if (anAttr->id() == "LocationType") {
return "__notinitialized__";
double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
dumpArray(aResult, aValues, 3);
} else if (aType == GeomDataAPI_Point2D::typeId()) {
- // do not dump flyout point for constraints as it may be changed unexpectedly
- if (theAttr->id() == "ConstraintFlyoutValuePnt")
+ // do not dump flyout point for constraints as it may be changed unexpectedly,
+ // also do not dump selection points controlled by GUI
+ if (theAttr->id() == "ConstraintFlyoutValuePnt" ||
+ theAttr->id() == "SelectedPointA" || theAttr->id() == "SelectedPointB")
return "__notinitialized__";
AttributePoint2DPtr anAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttr);
double aValues[2] = {anAttr->x(), anAttr->y()};
aResult<<"Volume: ";
// volumes of too huge shapes write in the scientific format
if (aVolume >= 1.e5)
- aResult<<std::scientific<<setprecision(7);
+ aResult<<std::scientific<<std::setprecision(7);
else
- aResult<<std::fixed<<setprecision(3);
+ aResult<<std::fixed<<std::setprecision(3);
aResult<<aVolume<<std::endl;
}
std::shared_ptr<GeomAPI_Pnt> aCenter = GeomAlgoAPI_ShapeTools::centreOfMass(theShape);
#include "ModelHighAPI_Interface.h"
//--------------------------------------------------------------------------------------
ModelHighAPI_RefAttr::ModelHighAPI_RefAttr()
-: myVariantType(VT_ATTRIBUTE)
+: myVariantType(VT_OBJECT)
{
}
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
//--------------------------------------------------------------------------------------
#include <ModelAPI_AttributeBoolean.h>
#include <ModelAPI_AttributeDocRef.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
theAttribute->setValue(anIndex, it->intValue()); // use only values, no text support in array
}
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::list<ModelHighAPI_Double> & theValue,
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray> & theAttribute)
+{
+ theAttribute->setSize(int(theValue.size()));
+
+ int anIndex = 0;
+ for (auto it = theValue.begin(); it != theValue.end(); ++it, ++anIndex)
+ theAttribute->setValue(anIndex, it->value()); // use only values, no text support in array
+}
+
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & theValue,
+ const std::shared_ptr<GeomDataAPI_Point2DArray> & theAttribute)
+{
+ theAttribute->setSize(int(theValue.size()));
+
+ int anIndex = 0;
+ for (auto it = theValue.begin(); it != theValue.end(); ++it, ++anIndex)
+ theAttribute->setPnt(anIndex, *it);
+}
+
+//--------------------------------------------------------------------------------------
void fillAttribute(const ModelHighAPI_Double & theX,
const ModelHighAPI_Double & theY,
const ModelHighAPI_Double & theZ,
theX.fillAttribute(theAttribute, theX, theY, theZ);
}
-
//==================================================================================================
GeomAPI_Shape::ShapeType shapeTypeByStr(std::string theShapeTypeStr)
{
class GeomDataAPI_Dir;
class GeomDataAPI_Point;
class GeomDataAPI_Point2D;
+class GeomDataAPI_Point2DArray;
//--------------------------------------------------------------------------------------
class ModelAPI_AttributeBoolean;
class ModelAPI_AttributeDouble;
+class ModelAPI_AttributeDoubleArray;
class ModelAPI_AttributeIntArray;
class ModelAPI_AttributeInteger;
class ModelAPI_AttributeRefAttr;
void fillAttribute(const std::list<ModelHighAPI_Integer> & theValue,
const std::shared_ptr<ModelAPI_AttributeIntArray> & theAttribute);
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::list<ModelHighAPI_Double> & theValue,
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray> & theAttribute);
+
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & theValue,
+ const std::shared_ptr<GeomDataAPI_Point2DArray> & theAttribute);
+
MODELHIGHAPI_EXPORT
void fillAttribute(const ModelHighAPI_Double & theX,
const ModelHighAPI_Double & theY,
--- /dev/null
+# Copyright (C) 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "ep", "0.5875")
+model.addParameter(Part_1_doc, "ep2", "0.35")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(-4.81482486096809e-34, 0.6, -0.08939999999999999, 0.6)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_2 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_2.result())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_3 = Sketch_1.addLine(-0.08939999999999999, 0.6, -0.08939999999999999, 0.46)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_3.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(-0.08939999999999999, 0.46, -0.2894, 0.46)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(-0.2894, 0.46, -0.2894, 0.36)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_5.result())
+SketchLine_6 = Sketch_1.addLine(-0.2894, 0.36, -0.08940000000000001, 0.36)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-0.08940000000000001, 0.36, -0.08940000000000001, -0.5600000000000001)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_7.result())
+SketchLine_8 = Sketch_1.addLine(-0.08852125812784814, -0.571165474137811, -0.07285119438446976, -0.5729508523825384)
+SketchLine_9 = Sketch_1.addLine(-0.07285119438446976, -0.5729508523825384, -0.0654, -0.6028359607518391)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_7.setName("SketchConstraintCoincidence_8")
+SketchLine_10 = Sketch_1.addLine(-0.0654, -0.6028359607518391, -0.0654, -1.285035960751839)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintCoincidence_8.setName("SketchConstraintCoincidence_9")
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-0.0654, -1.285035960751839, 0.3076, -1.285035960751839)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_11.result())
+SketchLine_12 = Sketch_1.addLine(0.3076, -1.285035960751839, 0.3076, -1.045635960751839)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_12.startPoint())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintVertical_5 = Sketch_1.setVertical(SketchLine_12.result())
+SketchLine_13 = Sketch_1.addLine(0.3076, -1.045635960751839, 0.007599999999999971, -1.045635960751839)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_12.endPoint(), SketchLine_13.startPoint())
+SketchConstraintCoincidence_11.setName("SketchConstraintCoincidence_12")
+SketchConstraintHorizontal_5 = Sketch_1.setHorizontal(SketchLine_13.result())
+SketchLine_14 = Sketch_1.addLine(0.007599999999999971, -1.045635960751839, 0.007599999999999971, -0.3926359607518392)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_13.endPoint(), SketchLine_14.startPoint())
+SketchConstraintCoincidence_12.setName("SketchConstraintCoincidence_13")
+SketchConstraintVertical_6 = Sketch_1.setVertical(SketchLine_14.result())
+SketchLine_15 = Sketch_1.addLine(0.007599999999999971, -0.3926359607518392, 0, -0.3307389278992326)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_14.endPoint(), SketchLine_15.startPoint())
+SketchConstraintCoincidence_13.setName("SketchConstraintCoincidence_14")
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchLine_15.endPoint(), SketchLine_2.result())
+SketchConstraintCoincidence_14.setName("SketchConstraintCoincidence_21")
+SketchLine_16 = Sketch_1.addLine(-4.235164485203422e-23, 0.6, 0, -0.3307389278992326)
+SketchLine_16.setName("SketchLine_20")
+SketchLine_16.result().setName("SketchLine_20")
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchLine_15.endPoint(), SketchLine_16.endPoint())
+SketchConstraintCoincidence_15.setName("SketchConstraintCoincidence_23")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 0.08939999999999999)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_3.result(), 0.14)
+SketchConstraintLength_2.setName("SketchConstraintLength_5")
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_4.result(), 0.2)
+SketchConstraintLength_3.setName("SketchConstraintLength_6")
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_5.result(), 0.1)
+SketchConstraintLength_4.setName("SketchConstraintLength_7")
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_3.result())
+SketchConstraintCoincidence_16.setName("SketchConstraintCoincidence_24")
+SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_7.result(), 0.92)
+SketchConstraintLength_5.setName("SketchConstraintLength_8")
+SketchConstraintLength_6 = Sketch_1.setLength(SketchLine_10.result(), 0.6822)
+SketchConstraintLength_6.setName("SketchConstraintLength_9")
+SketchConstraintLength_7 = Sketch_1.setLength(SketchLine_11.result(), 0.373)
+SketchConstraintLength_7.setName("SketchConstraintLength_10")
+SketchConstraintLength_8 = Sketch_1.setLength(SketchLine_12.result(), 0.2394)
+SketchConstraintLength_8.setName("SketchConstraintLength_11")
+SketchConstraintLength_9 = Sketch_1.setLength(SketchLine_13.result(), 0.3)
+SketchConstraintLength_9.setName("SketchConstraintLength_12")
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_10.startPoint(), SketchLine_7.result(), 0.024, True)
+SketchPoint_1 = Sketch_1.addPoint(-0.08852125812784814, -0.571165474137811)
+SketchLine_17 = Sketch_1.addLine(-0.08940000000000001, -0.5600000000000001, -0.08852125812784814, -0.571165474137811)
+SketchLine_17.setName("SketchLine_21")
+SketchLine_17.result().setName("SketchLine_21")
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_17.startPoint())
+SketchConstraintCoincidence_17.setName("SketchConstraintCoincidence_7")
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_18.setName("SketchConstraintCoincidence_26")
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchPoint_1.coordinates())
+SketchConstraintCoincidence_19.setName("SketchConstraintCoincidence_27")
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_20.setName("SketchConstraintCoincidence_28")
+SketchConstraintAngle_1 = Sketch_1.setAngleBackward(SketchLine_10.result(), SketchLine_9.result(), 166)
+SketchConstraintAngle_2 = Sketch_1.setAngleBackward(SketchLine_17.result(), SketchLine_8.result(), 101)
+SketchConstraintAngle_3 = Sketch_1.setAngleBackward(SketchLine_7.result(), SketchLine_17.result(), 175.5)
+SketchConstraintLength_10 = Sketch_1.setLength(SketchLine_17.result(), 0.0112)
+SketchConstraintLength_10.setName("SketchConstraintLength_13")
+SketchConstraintLength_11 = Sketch_1.setLength(SketchLine_9.result(), 0.0308)
+SketchConstraintLength_11.setName("SketchConstraintLength_14")
+SketchConstraintLength_12 = Sketch_1.setLength(SketchLine_14.result(), 0.653)
+SketchConstraintLength_12.setName("SketchConstraintLength_15")
+SketchConstraintAngle_4 = Sketch_1.setAngleBackward(SketchLine_14.result(), SketchLine_15.result(), 173)
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_18 = SketchProjection_2.createdFeature()
+SketchLine_18.setName("SketchLine_22")
+SketchLine_18.result().setName("SketchLine_22")
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_1.startPoint(), SketchLine_18.result(), 0.6, True)
+SketchLine_19 = Sketch_1.addLine(-0.08939999999999999, 0.46, -0.08940000000000001, 0.36)
+SketchLine_19.setName("SketchLine_23")
+SketchLine_19.result().setName("SketchLine_23")
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_19.startPoint())
+SketchConstraintCoincidence_21.setName("SketchConstraintCoincidence_29")
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_19.endPoint())
+SketchConstraintCoincidence_22.setName("SketchConstraintCoincidence_30")
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_16.startPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_23.setName("SketchConstraintCoincidence_25")
+model.do()
+Sketch_1.changeFacesOrder([[SketchLine_4.result(), SketchLine_5.result(), SketchLine_6.result(), SketchLine_19.result()],
+ [SketchLine_1.result(), SketchLine_3.result(), SketchLine_19.result(), SketchLine_7.result(), SketchLine_17.result(), SketchLine_8.result(), SketchLine_9.result(), SketchLine_10.result(), SketchLine_11.result(), SketchLine_12.result(), SketchLine_13.result(), SketchLine_14.result(), SketchLine_15.result(), SketchLine_16.result()]
+ ])
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_3f-SketchLine_23f-SketchLine_7f-SketchLine_21f-SketchLine_8f-SketchLine_9f-SketchLine_10f-SketchLine_11f-SketchLine_12f-SketchLine_13f-SketchLine_14f-SketchLine_15f-SketchLine_20r")], model.selection(), "ep", "ep")
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_23r")], model.selection(), "ep2", "ep2")
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchLine_20 = Sketch_2.addLine(-3.021110559767089e-34, 0.6, -0.5875, 0.5401656539390112)
+SketchLine_20.setName("SketchLine_24")
+SketchLine_20.result().setName("SketchLine_24")
+SketchProjection_3 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchLine_1_StartVertex"), False)
+SketchPoint_2 = SketchProjection_3.createdFeature()
+SketchConstraintCoincidence_24 = Sketch_2.setCoincident(SketchLine_20.startPoint(), SketchPoint_2.result())
+SketchConstraintCoincidence_24.setName("SketchConstraintCoincidence_31")
+SketchProjection_4 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_20][Extrusion_1_1/To_Face]"), False)
+SketchLine_21 = SketchProjection_4.createdFeature()
+SketchLine_21.setName("SketchLine_25")
+SketchLine_21.result().setName("SketchLine_25")
+SketchConstraintCoincidence_25 = Sketch_2.setCoincident(SketchLine_20.endPoint(), SketchLine_21.result())
+SketchConstraintCoincidence_25.setName("SketchConstraintCoincidence_32")
+SketchLine_22 = Sketch_2.addLine(-0.5875, 0.5401656539390112, -0.5875, 0.6)
+SketchLine_22.setName("SketchLine_26")
+SketchLine_22.result().setName("SketchLine_26")
+SketchConstraintCoincidence_26 = Sketch_2.setCoincident(SketchLine_20.endPoint(), SketchLine_22.startPoint())
+SketchConstraintCoincidence_26.setName("SketchConstraintCoincidence_33")
+SketchConstraintCoincidence_27 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_21).startPoint(), SketchLine_22.endPoint())
+SketchConstraintCoincidence_27.setName("SketchConstraintCoincidence_34")
+SketchProjection_5 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_20]"), True)
+SketchLine_23 = SketchProjection_5.createdFeature()
+SketchLine_23.setName("SketchLine_27")
+SketchLine_23.result().setName("SketchLine_27")
+SketchProjection_6 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_24 = SketchProjection_6.createdFeature()
+SketchLine_24.setName("SketchLine_28")
+SketchLine_24.result().setName("SketchLine_28")
+SketchConstraintMirror_1 = Sketch_2.addMirror(SketchLine_24.result(), [SketchLine_20.result(), SketchLine_22.result()])
+[SketchLine_25, SketchLine_26] = SketchConstraintMirror_1.mirrored()
+SketchLine_26.setName("SketchLine_30")
+SketchLine_26.result().setName("SketchLine_30")
+SketchLine_25.setName("SketchLine_29")
+SketchLine_25.result().setName("SketchLine_29")
+model.do()
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_2")], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_7"), 0, model.selection(), 0, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.standardPlane("XOZ"))
+SketchLine_27 = Sketch_3.addLine(-2.319541823598068e-23, 0.1790140882246268, 0.375, 0.1396)
+SketchLine_27.setName("SketchLine_31")
+SketchLine_27.result().setName("SketchLine_31")
+SketchProjection_7 = Sketch_3.addProjection(model.selection("EDGE", "Sketch_1/SketchLine_20"), False)
+SketchLine_28 = SketchProjection_7.createdFeature()
+SketchLine_28.setName("SketchLine_32")
+SketchLine_28.result().setName("SketchLine_32")
+SketchConstraintCoincidence_28 = Sketch_3.setCoincident(SketchLine_27.startPoint(), SketchLine_28.result())
+SketchConstraintCoincidence_28.setName("SketchConstraintCoincidence_35")
+SketchLine_29 = Sketch_3.addLine(0.375, 0.1396, 3.347, 0.1396)
+SketchLine_29.setName("SketchLine_33")
+SketchLine_29.result().setName("SketchLine_33")
+SketchConstraintCoincidence_29 = Sketch_3.setCoincident(SketchLine_27.endPoint(), SketchLine_29.startPoint())
+SketchConstraintCoincidence_29.setName("SketchConstraintCoincidence_36")
+SketchConstraintHorizontal_6 = Sketch_3.setHorizontal(SketchLine_29.result())
+SketchLine_30 = Sketch_3.addLine(3.347, 0.1396, 3.347, 0)
+SketchLine_30.setName("SketchLine_34")
+SketchLine_30.result().setName("SketchLine_34")
+SketchConstraintCoincidence_30 = Sketch_3.setCoincident(SketchLine_29.endPoint(), SketchLine_30.startPoint())
+SketchConstraintCoincidence_30.setName("SketchConstraintCoincidence_37")
+SketchProjection_8 = Sketch_3.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_31 = SketchProjection_8.createdFeature()
+SketchLine_31.setName("SketchLine_35")
+SketchLine_31.result().setName("SketchLine_35")
+SketchConstraintCoincidence_31 = Sketch_3.setCoincident(SketchLine_30.endPoint(), SketchLine_31.result())
+SketchConstraintCoincidence_31.setName("SketchConstraintCoincidence_38")
+SketchConstraintVertical_7 = Sketch_3.setVertical(SketchLine_30.result())
+SketchLine_32 = Sketch_3.addLine(3.347, 0, 0, 0)
+SketchLine_32.setName("SketchLine_36")
+SketchLine_32.result().setName("SketchLine_36")
+SketchConstraintCoincidence_32 = Sketch_3.setCoincident(SketchLine_30.endPoint(), SketchLine_32.startPoint())
+SketchConstraintCoincidence_32.setName("SketchConstraintCoincidence_39")
+SketchConstraintCoincidence_33 = Sketch_3.setCoincident(SketchAPI_Line(SketchLine_31).startPoint(), SketchLine_32.endPoint())
+SketchConstraintCoincidence_33.setName("SketchConstraintCoincidence_40")
+SketchLine_33 = Sketch_3.addLine(-2.319541823598068e-23, 0.1790140882246268, 0, 0)
+SketchLine_33.setName("SketchLine_37")
+SketchLine_33.result().setName("SketchLine_37")
+SketchConstraintCoincidence_34 = Sketch_3.setCoincident(SketchLine_27.startPoint(), SketchLine_33.startPoint())
+SketchConstraintCoincidence_34.setName("SketchConstraintCoincidence_41")
+SketchConstraintCoincidence_35 = Sketch_3.setCoincident(SketchAPI_Line(SketchLine_31).startPoint(), SketchLine_33.endPoint())
+SketchConstraintCoincidence_35.setName("SketchConstraintCoincidence_42")
+SketchConstraintLength_13 = Sketch_3.setLength(SketchLine_32.result(), 3.347)
+SketchConstraintLength_13.setName("SketchConstraintLength_16")
+SketchProjection_9 = Sketch_3.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_34 = SketchProjection_9.createdFeature()
+SketchLine_34.setName("SketchLine_38")
+SketchLine_34.result().setName("SketchLine_38")
+SketchConstraintDistance_3 = Sketch_3.setDistance(SketchLine_27.endPoint(), SketchLine_34.result(), 0.375, True)
+SketchConstraintDistance_4 = Sketch_3.setDistance(SketchLine_27.endPoint(), SketchLine_32.result(), 0.1396, True)
+SketchConstraintAngle_5 = Sketch_3.setAngle(SketchLine_29.result(), SketchLine_27.result(), 174)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("COMPOUND", "Sketch_3")], model.selection("EDGE", "PartSet/OX"), 360, 0)
+Fuse_1_objects_1 = [model.selection("SOLID", "Extrusion_2_1"), model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("SOLID", "Revolution_1_1")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, False)
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fuse_1_1/Modified_Face&Sketch_1/SketchLine_20][Revolution_1_1/Generated_Face&Sketch_3/SketchLine_31]")], 0.05)
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("XOZ"))
+SketchLine_35 = Sketch_4.addLine(3.347, 0.183, 3.347, -0.344869487384476)
+SketchLine_35.setName("SketchLine_39")
+SketchLine_35.result().setName("SketchLine_39")
+SketchConstraintVertical_8 = Sketch_4.setVertical(SketchLine_35.result())
+SketchProjection_10 = Sketch_4.addProjection(model.selection("VERTEX", "[Revolution_1_1/Generated_Face&Sketch_3/SketchLine_33][Revolution_1_1/Generated_Face&Sketch_3/SketchLine_34]"), False)
+SketchPoint_3 = SketchProjection_10.createdFeature()
+SketchConstraintCoincidence_36 = Sketch_4.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchLine_35.result())
+SketchConstraintCoincidence_36.setName("SketchConstraintCoincidence_43")
+SketchLine_36 = Sketch_4.addLine(3.347, 0.183, 3.744000000000001, 0.183)
+SketchLine_36.setName("SketchLine_40")
+SketchLine_36.result().setName("SketchLine_40")
+SketchConstraintCoincidence_37 = Sketch_4.setCoincident(SketchLine_35.startPoint(), SketchLine_36.startPoint())
+SketchConstraintCoincidence_37.setName("SketchConstraintCoincidence_44")
+SketchConstraintHorizontal_7 = Sketch_4.setHorizontal(SketchLine_36.result())
+SketchLine_37 = Sketch_4.addLine(3.744000000000001, 0.183, 3.744000000000001, -0.192)
+SketchLine_37.setName("SketchLine_41")
+SketchLine_37.result().setName("SketchLine_41")
+SketchConstraintCoincidence_38 = Sketch_4.setCoincident(SketchLine_36.endPoint(), SketchLine_37.startPoint())
+SketchConstraintCoincidence_38.setName("SketchConstraintCoincidence_45")
+SketchConstraintVertical_9 = Sketch_4.setVertical(SketchLine_37.result())
+SketchConstraintLength_14 = Sketch_4.setLength(SketchLine_36.result(), 0.397)
+SketchConstraintLength_14.setName("SketchConstraintLength_17")
+SketchConstraintLength_15 = Sketch_4.setLength(SketchLine_37.result(), 0.375)
+SketchConstraintLength_15.setName("SketchConstraintLength_18")
+SketchArc_1 = Sketch_4.addArc(3.665500000000001, -0.192, 3.744000000000001, -0.192, 3.700263973859845, -0.2623826407679625, True)
+SketchConstraintCoincidence_39 = Sketch_4.setCoincident(SketchLine_37.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_39.setName("SketchConstraintCoincidence_46")
+SketchConstraintTangent_1 = Sketch_4.setTangent(SketchLine_37.result(), SketchArc_1.results()[1])
+SketchArc_2 = Sketch_4.addArc(3.347, 0.452830512615524, 3.700263973859845, -0.2623826407679625, 3.347, -0.344869487384476, True)
+SketchConstraintCoincidence_40 = Sketch_4.setCoincident(SketchArc_1.endPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_40.setName("SketchConstraintCoincidence_47")
+SketchConstraintTangent_2 = Sketch_4.setTangent(SketchArc_1.results()[1], SketchArc_2.results()[1])
+SketchConstraintCoincidence_41 = Sketch_4.setCoincident(SketchArc_2.endPoint(), SketchLine_35.endPoint())
+SketchConstraintCoincidence_41.setName("SketchConstraintCoincidence_48")
+SketchConstraintRadius_1 = Sketch_4.setRadius(SketchArc_1.results()[1], 0.0785)
+SketchProjection_11 = Sketch_4.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_38 = SketchProjection_11.createdFeature()
+SketchLine_38.setName("SketchLine_42")
+SketchLine_38.result().setName("SketchLine_42")
+SketchConstraintDistance_5 = Sketch_4.setDistance(SketchLine_35.startPoint(), SketchLine_38.result(), 0.183, True)
+SketchConstraintCoincidence_42 = Sketch_4.setCoincident(SketchArc_2.center(), SketchLine_35.result())
+SketchConstraintCoincidence_42.setName("SketchConstraintCoincidence_49")
+SketchConstraintRadius_2 = Sketch_4.setRadius(SketchArc_2.results()[1], 0.7977)
+model.do()
+Revolution_2 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_4/Face-SketchLine_39r-SketchArc_2_2f-SketchArc_1_2f-SketchLine_41r-SketchLine_40r")], model.selection("EDGE", "Sketch_4/SketchLine_39"), 360, 0)
+Fuse_2 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Fillet_1_1"), model.selection("SOLID", "Revolution_2_1")], False)
+Sketch_5 = model.addSketch(Part_1_doc, model.selection("FACE", "Revolution_2_1/Generated_Face&Sketch_4/SketchLine_40"))
+SketchProjection_12 = Sketch_5.addProjection(model.selection("EDGE", "Sketch_4/SketchLine_40"), False)
+SketchLine_39 = SketchProjection_12.createdFeature()
+SketchLine_39.setName("SketchLine_43")
+SketchLine_39.result().setName("SketchLine_43")
+SketchCircle_1 = Sketch_5.addCircle(3.447, 0, 0.02725)
+SketchConstraintCoincidence_43 = Sketch_5.setCoincident(SketchLine_39.result(), SketchCircle_1.center())
+SketchConstraintCoincidence_43.setName("SketchConstraintCoincidence_50")
+SketchConstraintRadius_3 = Sketch_5.setRadius(SketchCircle_1.results()[1], 0.02725)
+SketchConstraintDistance_6 = Sketch_5.setDistance(SketchAPI_Line(SketchLine_39).startPoint(), SketchCircle_1.center(), 0.1, True)
+model.do()
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [model.selection("COMPOUND", "Sketch_5")], model.selection(), 0.1123, 0, [model.selection("SOLID", "Fuse_2_1")])
+Sketch_6 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_13 = Sketch_6.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_40 = SketchProjection_13.createdFeature()
+SketchLine_40.setName("SketchLine_44")
+SketchLine_40.result().setName("SketchLine_44")
+SketchCircle_2 = Sketch_6.addCircle(3.347, 0, 0.0535464)
+SketchConstraintRadius_4 = Sketch_6.setRadius(SketchCircle_2.results()[1], 0.0535464)
+SketchIntersectionPoint_1 = Sketch_6.addIntersectionPoint(model.selection("EDGE", "Sketch_4/SketchLine_39"), False)
+[SketchPoint_4] = SketchIntersectionPoint_1.intersectionPoints()
+SketchConstraintCoincidence_44 = Sketch_6.setCoincident(SketchCircle_2.center(), SketchAPI_Point(SketchPoint_4).coordinates())
+SketchConstraintCoincidence_44.setName("SketchConstraintCoincidence_51")
+model.do()
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_6/Face-SketchCircle_2_2f")], model.selection(), 0, 0.5586)
+Fuse_3 = model.addFuse(Part_1_doc, [model.selection("SOLID", "ExtrusionFuse_1_1"), model.selection("SOLID", "Extrusion_3_1")], False)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), 1.2912, False)
+Sketch_7 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_41 = Sketch_7.addLine(-0.80851, 0.003178, -0.80851, 0.253178)
+SketchLine_41.setName("SketchLine_45")
+SketchLine_41.result().setName("SketchLine_45")
+SketchConstraintVertical_10 = Sketch_7.setVertical(SketchLine_41.result())
+SketchLine_42 = Sketch_7.addLine(-0.80851, 0.253178, -0.80851, 0.003178)
+SketchLine_42.setName("SketchLine_46")
+SketchLine_42.result().setName("SketchLine_46")
+SketchConstraintCoincidence_45 = Sketch_7.setCoincident(SketchLine_41.endPoint(), SketchLine_42.startPoint())
+SketchConstraintCoincidence_45.setName("SketchConstraintCoincidence_52")
+SketchConstraintCoincidence_46 = Sketch_7.setCoincident(SketchLine_41.startPoint(), SketchLine_42.endPoint())
+SketchConstraintCoincidence_46.setName("SketchConstraintCoincidence_53")
+SketchProjection_14 = Sketch_7.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_43 = SketchProjection_14.createdFeature()
+SketchLine_43.setName("SketchLine_47")
+SketchLine_43.result().setName("SketchLine_47")
+SketchProjection_15 = Sketch_7.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_44 = SketchProjection_15.createdFeature()
+SketchLine_44.setName("SketchLine_48")
+SketchLine_44.result().setName("SketchLine_48")
+SketchConstraintDistance_7 = Sketch_7.setDistance(SketchLine_41.startPoint(), SketchLine_43.result(), 0.80851, True)
+SketchConstraintDistance_7.setName("SketchConstraintDistance_8")
+SketchConstraintLength_16 = Sketch_7.setLength(SketchLine_41.result(), 0.25)
+SketchConstraintLength_16.setName("SketchConstraintLength_19")
+SketchArc_3 = Sketch_7.addArc(-0.7325, 0.253178, -0.80851, 0.253178, -0.7325, 0.3291879999999999, True)
+SketchConstraintCoincidence_47 = Sketch_7.setCoincident(SketchLine_41.endPoint(), SketchArc_3.startPoint())
+SketchConstraintCoincidence_47.setName("SketchConstraintCoincidence_54")
+SketchConstraintTangent_3 = Sketch_7.setTangent(SketchLine_41.result(), SketchArc_3.results()[1])
+SketchLine_45 = Sketch_7.addLine(-0.7325, 0.253178, -0.7325, 0.3291879999999999)
+SketchLine_45.setName("SketchLine_49")
+SketchLine_45.result().setName("SketchLine_49")
+SketchLine_45.setAuxiliary(True)
+SketchConstraintCoincidence_48 = Sketch_7.setCoincident(SketchArc_3.center(), SketchLine_45.startPoint())
+SketchConstraintCoincidence_48.setName("SketchConstraintCoincidence_55")
+SketchConstraintCoincidence_49 = Sketch_7.setCoincident(SketchArc_3.endPoint(), SketchLine_45.endPoint())
+SketchConstraintCoincidence_49.setName("SketchConstraintCoincidence_56")
+SketchConstraintVertical_11 = Sketch_7.setVertical(SketchLine_45.result())
+SketchLine_46 = Sketch_7.addLine(-0.7325, 0.3291879999999999, -0.6591320000000001, 0.3291879999999999)
+SketchLine_46.setName("SketchLine_50")
+SketchLine_46.result().setName("SketchLine_50")
+SketchConstraintCoincidence_50 = Sketch_7.setCoincident(SketchArc_3.endPoint(), SketchLine_46.startPoint())
+SketchConstraintCoincidence_50.setName("SketchConstraintCoincidence_57")
+SketchConstraintHorizontal_8 = Sketch_7.setHorizontal(SketchLine_46.result())
+SketchConstraintLength_17 = Sketch_7.setLength(SketchLine_46.result(), 0.073368)
+SketchConstraintLength_17.setName("SketchConstraintLength_20")
+SketchLine_47 = Sketch_7.addLine(-0.4815101245041479, 0.278, 0, -1.355252715606881e-20)
+SketchLine_47.setName("SketchLine_51")
+SketchLine_47.result().setName("SketchLine_51")
+SketchLine_48 = Sketch_7.addLine(0, -1.355252715606881e-20, -0.3375518398718391, -1.355252715606881e-20)
+SketchLine_48.setName("SketchLine_52")
+SketchLine_48.result().setName("SketchLine_52")
+SketchLine_48.setAuxiliary(True)
+SketchConstraintCoincidence_51 = Sketch_7.setCoincident(SketchLine_47.endPoint(), SketchLine_48.startPoint())
+SketchConstraintCoincidence_51.setName("SketchConstraintCoincidence_58")
+SketchConstraintHorizontal_9 = Sketch_7.setHorizontal(SketchLine_48.result())
+SketchConstraintAngle_6 = Sketch_7.setAngle(SketchLine_47.result(), SketchLine_48.result(), 30)
+SketchConstraintCoincidence_52 = Sketch_7.setCoincident(SketchLine_47.endPoint(), SketchAPI_Line(SketchLine_44).startPoint())
+SketchConstraintCoincidence_52.setName("SketchConstraintCoincidence_59")
+SketchConstraintDistance_8 = Sketch_7.setDistance(SketchLine_47.startPoint(), SketchLine_44.result(), 0.278, True)
+SketchConstraintDistance_8.setName("SketchConstraintDistance_9")
+SketchConstraintDistance_9 = Sketch_7.setDistance(SketchLine_45.startPoint(), SketchLine_43.result(), 0.7325, True)
+SketchConstraintDistance_9.setName("SketchConstraintDistance_10")
+SketchArc_4 = Sketch_7.addArc(-0.6591320000000001, -0.004579113372898896, -0.6591320000000001, 0.3291879999999999, -0.4815101245041478, 0.278, True)
+SketchConstraintCoincidence_53 = Sketch_7.setCoincident(SketchLine_46.endPoint(), SketchArc_4.startPoint())
+SketchConstraintCoincidence_53.setName("SketchConstraintCoincidence_60")
+SketchConstraintTangent_4 = Sketch_7.setTangent(SketchLine_46.result(), SketchArc_4.results()[1])
+SketchConstraintCoincidence_54 = Sketch_7.setCoincident(SketchArc_4.endPoint(), SketchLine_47.startPoint())
+SketchConstraintCoincidence_54.setName("SketchConstraintCoincidence_61")
+SketchConstraintDistance_10 = Sketch_7.setDistance(SketchLine_41.startPoint(), SketchLine_48.result(), 0.003178, True)
+SketchConstraintDistance_10.setName("SketchConstraintDistance_13")
+model.do()
+Plane_5 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OZ"), model.selection("VERTEX", "Sketch_7/SketchLine_45_StartVertex"), True)
+Sketch_8 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_2"))
+SketchProjection_16 = Sketch_8.addProjection(model.selection("VERTEX", "Sketch_7/SketchLine_45_StartVertex"), False)
+SketchPoint_5 = SketchProjection_16.createdFeature()
+SketchCircle_3 = Sketch_8.addCircle(1.2912, -0.80851, 0.02655)
+SketchConstraintCoincidence_55 = Sketch_8.setCoincident(SketchPoint_5.result(), SketchCircle_3.center())
+SketchConstraintCoincidence_55.setName("SketchConstraintCoincidence_62")
+SketchConstraintRadius_5 = Sketch_8.setRadius(SketchCircle_3.results()[1], 0.02655)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_8/Face-SketchCircle_3_2f")])
+Wire_1_objects = [model.selection("EDGE", "Sketch_7/SketchLine_45"), model.selection("EDGE", "Sketch_7/SketchArc_3_2"), model.selection("EDGE", "Sketch_7/SketchLine_50"), model.selection("EDGE", "Sketch_7/SketchArc_4_2"), model.selection("EDGE", "Sketch_7/SketchLine_51")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects)
+Pipe_1 = model.addPipe(Part_1_doc, [model.selection("FACE", "Face_1_1")], model.selection("WIRE", "Wire_1_1"))
+Fuse_4 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Pipe_1_1"), model.selection("SOLID", "Fuse_3_1")], False)
+Plane_6 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), 1.1407, True)
+Sketch_9 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_3"))
+SketchLine_49 = Sketch_9.addLine(0.5219, -0.3643, 0.5219, -0.1143)
+SketchLine_49.setName("SketchLine_53")
+SketchLine_49.result().setName("SketchLine_53")
+SketchConstraintVertical_12 = Sketch_9.setVertical(SketchLine_49.result())
+SketchProjection_17 = Sketch_9.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_50 = SketchProjection_17.createdFeature()
+SketchLine_50.setName("SketchLine_54")
+SketchLine_50.result().setName("SketchLine_54")
+SketchProjection_18 = Sketch_9.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_51 = SketchProjection_18.createdFeature()
+SketchLine_51.setName("SketchLine_55")
+SketchLine_51.result().setName("SketchLine_55")
+SketchConstraintDistance_11 = Sketch_9.setDistance(SketchLine_49.endPoint(), SketchLine_50.result(), 0.5219, True)
+SketchConstraintDistance_11.setName("SketchConstraintDistance_11")
+SketchConstraintDistance_12 = Sketch_9.setDistance(SketchLine_49.startPoint(), SketchLine_51.result(), 0.3643, True)
+SketchConstraintDistance_12.setName("SketchConstraintDistance_12")
+SketchConstraintLength_18 = Sketch_9.setLength(SketchLine_49.result(), 0.25)
+SketchConstraintLength_18.setName("SketchConstraintLength_21")
+SketchArc_5 = Sketch_9.addArc(0.4075999999999999, -0.1143, 0.5219, -0.1143, 0.4075999999999999, 2.344010062074957e-33, False)
+SketchConstraintCoincidence_56 = Sketch_9.setCoincident(SketchLine_49.endPoint(), SketchArc_5.startPoint())
+SketchConstraintCoincidence_56.setName("SketchConstraintCoincidence_63")
+SketchConstraintTangent_5 = Sketch_9.setTangent(SketchLine_49.result(), SketchArc_5.results()[1])
+SketchLine_52 = Sketch_9.addLine(0.4075999999999999, 2.344010062074957e-33, 0, -1.207680510878222e-22)
+SketchLine_52.setName("SketchLine_56")
+SketchLine_52.result().setName("SketchLine_56")
+SketchConstraintCoincidence_57 = Sketch_9.setCoincident(SketchArc_5.endPoint(), SketchLine_52.startPoint())
+SketchConstraintCoincidence_57.setName("SketchConstraintCoincidence_64")
+SketchConstraintHorizontal_10 = Sketch_9.setHorizontal(SketchLine_52.result())
+SketchConstraintCoincidence_58 = Sketch_9.setCoincident(SketchLine_52.endPoint(), SketchAPI_Line(SketchLine_50).startPoint())
+SketchConstraintCoincidence_58.setName("SketchConstraintCoincidence_65")
+SketchLine_53 = Sketch_9.addLine(0.4075999999999999, 2.344010062074957e-33, 0.4075999999999999, -0.1143)
+SketchLine_53.setName("SketchLine_57")
+SketchLine_53.result().setName("SketchLine_57")
+SketchLine_53.setAuxiliary(True)
+SketchConstraintCoincidence_59 = Sketch_9.setCoincident(SketchArc_5.endPoint(), SketchLine_53.startPoint())
+SketchConstraintCoincidence_59.setName("SketchConstraintCoincidence_66")
+SketchConstraintCoincidence_60 = Sketch_9.setCoincident(SketchArc_5.center(), SketchLine_53.endPoint())
+SketchConstraintCoincidence_60.setName("SketchConstraintCoincidence_67")
+SketchConstraintVertical_13 = Sketch_9.setVertical(SketchLine_53.result())
+model.do()
+Plane_7 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OY"), model.selection("VERTEX", "Sketch_9/SketchLine_53_StartVertex"), True)
+Sketch_10 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_4"))
+SketchProjection_19 = Sketch_10.addProjection(model.selection("VERTEX", "Sketch_9/SketchLine_53_StartVertex"), False)
+SketchPoint_6 = SketchProjection_19.createdFeature()
+SketchCircle_4 = Sketch_10.addCircle(0.5219, 1.1407, 0.05355)
+SketchConstraintCoincidence_61 = Sketch_10.setCoincident(SketchPoint_6.result(), SketchCircle_4.center())
+SketchConstraintCoincidence_61.setName("SketchConstraintCoincidence_68")
+SketchConstraintRadius_6 = Sketch_10.setRadius(SketchCircle_4.results()[1], 0.05355)
+model.do()
+Face_2 = model.addFace(Part_1_doc, [model.selection("EDGE", "Sketch_10/SketchCircle_4_2")])
+Wire_2_objects = [model.selection("EDGE", "Sketch_9/SketchLine_53"), model.selection("EDGE", "Sketch_9/SketchArc_5_2"), model.selection("EDGE", "Sketch_9/SketchLine_56")]
+Wire_2 = model.addWire(Part_1_doc, Wire_2_objects)
+Pipe_2 = model.addPipe(Part_1_doc, [model.selection("FACE", "Face_2_1")], model.selection("WIRE", "Wire_2_1"))
+Fuse_5 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Pipe_2_1"), model.selection("SOLID", "Fuse_4_1")], False)
+Symmetry_1 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Fuse_5_1")], model.selection("FACE", "PartSet/YOZ"), False)
+Symmetry_2 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Symmetry_1_1")], model.selection("FACE", "PartSet/XOZ"), False)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Symmetry_2_1/MF:Symmetried&Pipe_2_1/From_Face_1")])
+Group_1.setName("Outlet_1")
+Group_1.result().setName("Outlet_1")
+Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Symmetry_2_1/MF:Symmetried&Pipe_1_1/From_Face_1")])
+Group_2.setName("Inlet_1")
+Group_2.result().setName("Inlet_1")
+Group_3 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Symmetry_2_1/MF:Symmetried&Extrusion_3_1/From_Face")])
+Group_3.setName("Outlet_2")
+Group_3.result().setName("Outlet_2")
+Group_4 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Symmetry_2_1/MF:Symmetried&ExtrusionFuse_1_1/To_Face")])
+Group_4.setName("Inlet_2")
+Group_4.result().setName("Inlet_2")
+Group_5 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Symmetry_2_1")])
+Group_5.setName("Group_faces")
+Group_5.result().setName("Group_faces")
+GroupSubstraction_1_objects_2 = [model.selection("COMPOUND", "Outlet_1"), model.selection("COMPOUND", "Inlet_1"), model.selection("COMPOUND", "Outlet_2"), model.selection("COMPOUND", "Inlet_2")]
+GroupSubstraction_1 = model.addGroupSubstraction(Part_1_doc, [model.selection("COMPOUND", "Group_faces")], GroupSubstraction_1_objects_2)
+GroupSubstraction_1.result().setName("Wall")
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Symmetry_2, 1)
+model.testNbSubResults(Symmetry_2, [0])
+model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.FACE, [44])
+model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.EDGE, [192])
+model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.VERTEX, [384])
+model.testResultsVolumes(Symmetry_2, [0.714262940088946862715602037])
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+
+# Check that the features are not in error
+for i in range(Part_1_doc.size("Features")):
+ feature = objectToFeature(Part_1_doc.object("Features", i))
+ name = feature.name()
+ error = feature.error()
+ assert(error == ''), "The feature {0} is in error: {1}".format(name, error)
+ assert(aFactory.validate(feature)), "The feature {0} is in error: {1}".format(name, error)
+
+assert(Part_1_doc.size("Groups") == 6)
+
+assert(model.checkPythonDump())
QWidget* ModuleBase_IWidgetCreator::createPanelByType(const std::string& theType,
QWidget* theParent,
- const FeaturePtr& theFeature)
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* theWidgetApi)
{
return 0;
}
/// \param theType a panel type
/// \param theParent a parent widget
/// \param theFeature a feature modified in the panel
+ /// \param theWidgetApi a low-level API for reading xml definitions of widget
/// \return created widget or null
virtual QWidget* createPanelByType(const std::string& theType,
QWidget* theParent,
- const FeaturePtr& theFeature);
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* theWidgetApi = 0);
/// Create page by its type
/// The default implementation is empty
myFeatureId = theData->featureId();
myIsInternal = theData->getBooleanAttribute(ATTR_INTERNAL, false);
+ myUseExternalParts = theData->getBooleanAttribute("allow_parts_content", false);
myIsModifiedInEdit = theData->getProperty(ATTR_MODIFIED_IN_EDIT);
/// \param theFeature a feature object
/// \param theToStoreValue a value about necessity to store the widget value to the feature
/// \param isUpdateFlushed a flag if update should be flushed on store value
- void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
- const bool isUpdateFlushed = true);
+ virtual void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
+ const bool isUpdateFlushed = true);
/// Editing mode depends on mode of current operation. This value is defined by it.
virtual void setEditingMode(bool isEditing) { myIsEditing = isEditing; }
virtual bool isReadOnly() const { return !isEnabled(); }
+ /// Returns true if the widget should have access to external parts
+ bool canUseExternalParts() const { return myUseExternalParts; }
+
signals:
/// The signal about widget values are to be changed
void beforeValuesChanged();
bool myFlushUpdateBlocked;
bool myUpdateVisualAttributes;
+
+ /// A flag which indicates that current widget should have access to external parts
+ bool myUseExternalParts;
};
#endif
// Add item
if (aProp->type() != Config_Prop::Disabled) {
SUIT_PreferenceMgr::PrefItemType aPrefType = SUIT_PreferenceMgr::Auto;
- if (aProp->type() == Config_Prop::Directory) {
+ switch (aProp->type()) {
+ case Config_Prop::Directory:
aPrefType = SUIT_PreferenceMgr::File;
- } else {
+ break;
+ case Config_Prop::Cursor:
+ aPrefType = SUIT_PreferenceMgr::Selector;
+ break;
+ default:
aPrefType = (SUIT_PreferenceMgr::PrefItemType) aProp->type();
}
+
int anId = thePref->addPreference(QObject::tr(aProp->title().c_str()), aTab, aPrefType,
QString::fromStdString(aProp->section()),
QString::fromStdString(aProp->name()));
- if(aProp->type() == Config_Prop::Directory) {
+
+ switch (aProp->type()) {
+ case Config_Prop::Directory:
thePref->setItemProperty("path_type", Qtx::PT_Directory, anId);
- }
- if (aPrefType == SUIT_PreferenceMgr::DblSpin) {
+ break;
+ case SUIT_PreferenceMgr::DblSpin:
if (aProp->min() != "") {
double aMin = QString(aProp->min().c_str()).toDouble();
thePref->setItemProperty("min", aMin, anId);
double aMax = QString(aProp->max().c_str()).toDouble();
thePref->setItemProperty("max", aMax, anId);
}
- }
- if (aPrefType == SUIT_PreferenceMgr::IntSpin) {
+ break;
+ case SUIT_PreferenceMgr::IntSpin:
if (aProp->min() != "") {
int aMin = QString(aProp->min().c_str()).toInt();
thePref->setItemProperty("min", aMin, anId);
int aMax = QString(aProp->max().c_str()).toInt();
thePref->setItemProperty("max", aMax, anId);
}
+ break;
+ case Config_Prop::Cursor:
+ {
+ QList<QVariant> aIndicesList;
+ QList<QVariant> aIconsList;
+ aIndicesList << 0 << 1 << 2;
+ aIconsList << QPixmap(":pictures/ArrowCursor.png") <<
+ QPixmap(":pictures/CrossCursor.png") <<
+ QPixmap(":pictures/HandCursor.png");
+
+ thePref->setItemProperty("indexes", aIndicesList, anId);
+ thePref->setItemProperty("icons", aIconsList, anId);
+ }
+ break;
}
}
}
//
#include "ModuleBase_ResultPrs.h"
+#include "ModuleBase_IViewer.h"
#include <GeomAPI_PlanarEdges.h>
// Set own free boundaries aspect in order to have free
// and unfree boundaries with different colors
Handle(Prs3d_Drawer) aDrawer = Attributes();
- Handle(Prs3d_LineAspect) aFreeBndAspect =
- new Prs3d_LineAspect(Quantity_NOC_GREEN, Aspect_TOL_SOLID, 1);
- aDrawer->SetFreeBoundaryAspect(aFreeBndAspect);
+ aDrawer->SetUnFreeBoundaryAspect(
+ new Prs3d_LineAspect(Quantity_NOC_YELLOW, Aspect_TOL_SOLID, 1));
+ aDrawer->SetFreeBoundaryAspect(new Prs3d_LineAspect(Quantity_NOC_GREEN, Aspect_TOL_SOLID, 1));
+ aDrawer->SetFaceBoundaryAspect(new Prs3d_LineAspect(Quantity_NOC_BLACK, Aspect_TOL_SOLID, 1));
+
+ aDrawer->VIsoAspect()->SetNumber(0);
+ aDrawer->UIsoAspect()->SetNumber(0);
if (aDrawer->HasOwnPointAspect())
aDrawer->PointAspect()->SetTypeOfMarker(Aspect_TOM_PLUS);
else
aDrawer->SetPointAspect(new Prs3d_PointAspect(Aspect_TOM_PLUS, Quantity_NOC_YELLOW, 1.));
+ aDrawer = DynamicHilightAttributes();
+ if (aDrawer.IsNull()) {
+ if (!ModuleBase_IViewer::DefaultHighlightDrawer.IsNull()) {
+ aDrawer = new Prs3d_Drawer(*ModuleBase_IViewer::DefaultHighlightDrawer);
+ aDrawer->VIsoAspect()->SetNumber(0);
+ aDrawer->UIsoAspect()->SetNumber(0);
+ SetDynamicHilightAttributes(aDrawer);
+ }
+ } else {
+ aDrawer->VIsoAspect()->SetNumber(0);
+ aDrawer->UIsoAspect()->SetNumber(0);
+ }
myHiddenSubShapesDrawer = new AIS_ColoredDrawer(myDrawer);
Handle(Prs3d_ShadingAspect) aShadingAspect = new Prs3d_ShadingAspect();
aShadingAspect->SetMaterial(Graphic3d_NOM_BRASS); //default value of context material
+ aShadingAspect->Aspect()->SetEdgeColor(Quantity_NOC_BLACK);
myHiddenSubShapesDrawer->SetShadingAspect(aShadingAspect);
ModuleBase_Tools::setPointBallHighlighting(this);
AttributeIntArrayPtr aColorAttr = myResult->data()->intArray(ModelAPI_Result::COLOR_ID());
bool aHasColor = aColorAttr.get() && aColorAttr->isInitialized();
+ Handle(Prs3d_Drawer) aDrawer = Attributes();
+ aDrawer->SetFaceBoundaryDraw(Standard_True);
+ aDrawer->FaceBoundaryAspect()->SetColor(Quantity_NOC_BLACK);
+
if (!aHasColor) {
- Handle(Prs3d_Drawer) aDrawer = Attributes();
- Handle(Prs3d_LineAspect) anAspect; // = aDrawer->LineAspect();
- //anAspect->SetColor(Quantity_NOC_YELLOW);
- //aDrawer->SetLineAspect(anAspect);
-
- // - unfree boundaries color
- anAspect = aDrawer->UnFreeBoundaryAspect();
- anAspect->SetColor(Quantity_NOC_YELLOW);
- aDrawer->SetUnFreeBoundaryAspect(anAspect);
- aDrawer->SetUnFreeBoundaryDraw(true);
-
- // - free boundaries color
- anAspect = aDrawer->FreeBoundaryAspect();
- anAspect->SetColor(Quantity_NOC_GREEN);
- aDrawer->SetFreeBoundaryAspect(anAspect);
- aDrawer->SetFreeBoundaryDraw(true);
-
- // - standalone edges color
- anAspect = aDrawer->WireAspect();
- anAspect->SetColor(Quantity_NOC_RED);
- aDrawer->SetWireAspect(anAspect);
+ aDrawer->UnFreeBoundaryAspect()->SetColor(Quantity_NOC_YELLOW);
+ aDrawer->FreeBoundaryAspect()->SetColor(Quantity_NOC_GREEN);
+ aDrawer->WireAspect()->SetColor(Quantity_NOC_RED);
+
+ aDrawer->SetUnFreeBoundaryDraw(Standard_True);
+ aDrawer->SetFreeBoundaryDraw(Standard_True);
+ aDrawer->SetWireDraw(Standard_True);
}
}
}
#include "ModuleBase_ViewerFilters.h"
#include "ModuleBase_IWorkshop.h"
#include "ModuleBase_IModule.h"
+#include "ModuleBase_Operation.h"
+#include "ModuleBase_IPropertyPanel.h"
+#include "ModuleBase_ModelWidget.h"
#include <ModelAPI_Session.h>
#include <ModelAPI_Document.h>
if (aObj) {
DocumentPtr aDoc = aObj->document();
SessionPtr aMgr = ModelAPI_Session::get();
- aValid = (aDoc == aMgr->activeDocument() || aDoc == aMgr->moduleDocument());
+
+ if (anOperation->propertyPanel()) {
+ ModuleBase_ModelWidget* aWidget = anOperation->propertyPanel()->activeWidget();
+ if (aWidget && aWidget->canUseExternalParts())
+ return Standard_True;
+ }
+ return (aDoc == aMgr->activeDocument() || aDoc == aMgr->moduleDocument());
}
else {
// This object is not controlled by the filter
QWidget* ModuleBase_WidgetCreatorFactory::createPanelByType(const std::string& theType,
QWidget* theParent,
- const FeaturePtr& theFeature)
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* myWidgetApi)
{
QWidget* aPanel = 0;
if (myPanelToCreator.contains(theType)) {
WidgetCreatorPtr aCreator = myPanelToCreator[theType];
- aPanel = aCreator->createPanelByType(theType, theParent, theFeature);
+ aPanel = aCreator->createPanelByType(theType, theParent, theFeature, myWidgetApi);
}
return aPanel;
}
/// \param theType a type
/// \param theParent a parent widget
/// \param theFeature a feature to fill the panel
+ /// \param theWidgetApi the widget configuration.
+ /// The attribute of the model widget is obtained from XML
/// \return a created panel or null
QWidget* createPanelByType(const std::string& theType, QWidget* theParent,
- const FeaturePtr& theFeature);
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* theWidgetApi = 0);
/// Returns true if there is a creator, which can make a page by the type
/// \param theType a type
std::string aPanelName = myWidgetApi->getProperty(PROPERTY_PANEL_ID);
if (!aPanelName.empty() && ModuleBase_WidgetCreatorFactory::get()->hasPanelWidget(aPanelName)) {
QWidget* aPanel = ModuleBase_WidgetCreatorFactory::get()->createPanelByType(aPanelName,
- thePage->pageWidget(), theFeature);
- thePage->addWidget(aPanel);
+ thePage->pageWidget(), theFeature, myWidgetApi);
+ ModuleBase_ModelWidget* aModelWdg = dynamic_cast<ModuleBase_ModelWidget*>(aPanel);
+ if (aModelWdg)
+ thePage->addModelWidget(aModelWdg);
+ else
+ thePage->addWidget(aPanel);
thePage->alignToTop();
}
}
aWidget->setVisible(false);
}
}
+ thePage->alignToTop();
}
- thePage->alignToTop();
}
void ModuleBase_WidgetFactory::getAttributeTitle(const std::string& theAttributeId,
theTitle =
QString::fromStdString(myWidgetApi->getProperty(CONTAINER_PAGE_NAME)).toStdString().c_str();
}
+ else
+ theTitle = theAttributeId;
}
void ModuleBase_WidgetFactory::getGreedAttribute(std::string& theAttributeId)
ModuleBase_WidgetSelector::deactivate();
if (myVisibleObjects.size())
- onShowOnly(false);
+ myShowOnlyBtn->setChecked(false);
myWorkshop->module()->deactivateCustomPrs(ModuleBase_IModule::CustomizeHighlightedObjects, true);
clearSelectedHistory();
}
aAttr->setText(aXText, aYText, aZText);
} else {
+ aAttr->setText("", "", "");
aAttr->setValue(myXSpin->value(), myYSpin->value(), myZSpin->value());
}
} else {
myYSpin->setValue(myDefaultValue[1]);
myZSpin->setValue(myDefaultValue[2]);
}
+ setValueState(Stored);
return true;
}
return false;
<translation>La sélection est vide</translation>
</message>
</context>
+<context>
+ <name>ModuleBase_WidgetUndoLabel</name>
+ <message>
+ <source>Undo</source>
+ <translation>Undo</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
<message>
<source>The following parts will be deleted: %1.
</source>
- <translation>Les pièces suivantes seront supprimées : %1.
-
-</translation>
+ <translation>Les pièces suivantes seront supprimées : %1.</translation>
</message>
<message>
<source>Replace</source>
PartSet_WidgetSketchLabel.h
PartSet_CenterPrs.h
PartSet_ExternalPointsMgr.h
- PartSet_TreeNodes.h
- PartSet_FieldStepPrs.h
+ PartSet_TreeNodes.h
+ PartSet_FieldStepPrs.h
+ PartSet_WidgetBSplinePoints.h
+ PartSet_BSplineWidget.h
)
SET(PROJECT_MOC_HEADERS
PartSet_WidgetShapeSelector.h
PartSet_WidgetSketchCreator.h
PartSet_WidgetSketchLabel.h
+ PartSet_WidgetBSplinePoints.h
PartSet_ExternalPointsMgr.h
+ PartSet_BSplineWidget.h
)
SET(PROJECT_SOURCES
PartSet_WidgetSketchLabel.cpp
PartSet_CenterPrs.cpp
PartSet_ExternalPointsMgr.cpp
- PartSet_TreeNodes.cpp
- PartSet_FieldStepPrs.cpp
+ PartSet_TreeNodes.cpp
+ PartSet_FieldStepPrs.cpp
+ PartSet_WidgetBSplinePoints.cpp
+ PartSet_BSplineWidget.cpp
)
SET(PROJECT_RESOURCES
--- /dev/null
+// Copyright (C) 2019-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 <PartSet_BSplineWidget.h>
+
+#include <SketchPlugin_BSpline.h>
+
+#include <ModuleBase_Tools.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <QFormLayout>
+#include <QGroupBox>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QScrollArea>
+#include <QToolButton>
+
+
+PartSet_BSplineWidget::PartSet_BSplineWidget(
+ QWidget* theParent,
+ const Config_WidgetAPI* theData)
+ : ModuleBase_ModelWidget(theParent, theData)
+{
+ QVBoxLayout* aMainLayout = new QVBoxLayout(this);
+ aMainLayout->setContentsMargins(0, 0, 0, 0);
+
+ // GroupBox to keep widgets for B-spline poles and weights
+ myPolesGroupBox = new QGroupBox(tr("Poles and weights"), this);
+ aMainLayout->addWidget(myPolesGroupBox);
+
+ QVBoxLayout* aLayout = new QVBoxLayout(myPolesGroupBox);
+ ModuleBase_Tools::adjustMargins(aLayout);
+
+ myScrollArea = new QScrollArea(myPolesGroupBox);
+ myScrollArea->setWidgetResizable(true);
+ myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myScrollArea->setFrameStyle(QFrame::NoFrame);
+ aLayout->addWidget(myScrollArea);
+
+ QWidget* aContainer = new QWidget(myScrollArea);
+ QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
+ aBoxLay->setContentsMargins(0, 0, 0, 0);
+
+ // layout of GroupBox
+ myPolesWgt = new QWidget(aContainer);
+ QGridLayout* aGroupLayout = new QGridLayout(myPolesWgt);
+ aGroupLayout->setColumnStretch(1, 1);
+ ModuleBase_Tools::adjustMargins(aGroupLayout);
+
+ restoreValueCustom();
+ aBoxLay->addWidget(myPolesWgt);
+ aBoxLay->addStretch(1);
+ myScrollArea->setWidget(aContainer);
+}
+
+void PartSet_BSplineWidget::setFeature(const FeaturePtr& theFeature,
+ const bool theToStoreValue,
+ const bool isUpdateFlushed)
+{
+ ModuleBase_ModelWidget::setFeature(theFeature, theToStoreValue, isUpdateFlushed);
+ restoreValueCustom();
+}
+
+void PartSet_BSplineWidget::deactivate()
+{
+ ModuleBase_ModelWidget::deactivate();
+ storeValueCustom();
+}
+
+
+QList<QWidget*> PartSet_BSplineWidget::getControls() const
+{
+ QList<QWidget*> aControls;
+ aControls.append(myScrollArea);
+ return aControls;
+}
+
+void PartSet_BSplineWidget::storePolesAndWeights() const
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+
+ std::list<BSplinePoleWidgets>::const_iterator anIt = myPoles.begin();
+ for (int anIndex = 0; anIt != myPoles.end(); ++anIndex, ++anIt) {
+ aWeightsArray->setValue(anIndex, anIt->myWeight->value());
+ }
+}
+
+bool PartSet_BSplineWidget::storeValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ if (!aData || !aData->isValid()) // can be on abort of sketcher element
+ return false;
+
+ AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+
+ bool isBlocked = blockSignals(true);
+ storePolesAndWeights();
+ ModuleBase_Tools::flushUpdated(myFeature);
+ blockSignals(isBlocked);
+
+ updateObject(myFeature);
+ return true;
+}
+
+bool PartSet_BSplineWidget::restoreValueCustom()
+{
+ if (!myFeature)
+ return false;
+
+ DataPtr aData = myFeature->data();
+
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(SketchPlugin_BSpline::POLES_ID()));
+ AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+
+ while (myPoles.size() < aPoles->size())
+ addPoleWidget();
+
+ std::list<BSplinePoleWidgets>::iterator anIt = myPoles.begin();
+ for (int anIndex = 0; anIt != myPoles.end(); ++anIt, ++anIndex) {
+ GeomPnt2dPtr aPoint = aPoles->pnt(anIndex);
+ anIt->myX->setValue(aPoint->x());
+ anIt->myY->setValue(aPoint->y());
+ bool isBlocked = anIt->myWeight->blockSignals(true);
+ anIt->myWeight->setValue(aWeights->value(anIndex));
+ anIt->myWeight->blockSignals(isBlocked);
+ }
+
+ return true;
+}
+
+void PartSet_BSplineWidget::addPoleWidget()
+{
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myPolesWgt->layout());
+ int aNbPoles = (int)myPoles.size();
+ QString aPoleStr = tr("Pole %1").arg(aNbPoles + 1);
+
+ myPoles.push_back(BSplinePoleWidgets());
+ BSplinePoleWidgets& aPole = myPoles.back();
+ aGroupLay->addWidget(createPoleWidget(aPole, aPoleStr, myPolesWgt), aNbPoles, 1);
+}
+
+QGroupBox* PartSet_BSplineWidget::createPoleWidget(BSplinePoleWidgets& thePole,
+ const QString& theName, QWidget* theParent)
+{
+ QGroupBox* aPoleGroupBox = new QGroupBox(theName, theParent);
+ QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+ aPoleLay->setSpacing(0);
+ ModuleBase_Tools::zeroMargins(aPoleLay);
+
+ thePole.myX = new ModuleBase_LabelValue(aPoleGroupBox, tr("X"));
+ aPoleLay->addWidget(thePole.myX, 0, 0, 1, 3);
+ thePole.myY = new ModuleBase_LabelValue(aPoleGroupBox, tr("Y"));
+ aPoleLay->addWidget(thePole.myY, 1, 0, 1, 3);
+ thePole.myWeight = new ModuleBase_ParamSpinBox(aPoleGroupBox);
+ thePole.myWeight->setMinimum(0.0);
+
+ aPoleLay->addWidget(new QLabel(tr("Weight :"), aPoleGroupBox), 2, 0);
+ aPoleLay->addWidget(thePole.myWeight, 2, 1);
+ // we should listen textChanged signal as valueChanged do not send when text is modified
+ connect(thePole.myWeight, SIGNAL(textChanged(const QString&)),
+ this, SIGNAL(valuesChanged()));
+
+ thePole.myAddBtn = new QToolButton(aPoleGroupBox);
+ thePole.myAddBtn->setIcon(QIcon(":pictures/add.png"));
+ thePole.myAddBtn->setToolTip(tr("Add a new pole after the current"));
+ aPoleLay->addWidget(thePole.myAddBtn, 2, 2);
+ connect(thePole.myAddBtn, SIGNAL(clicked(bool)), SLOT(onAddPole()));
+
+ return aPoleGroupBox;
+}
+
+
+void PartSet_BSplineWidget::onAddPole()
+{
+ QObject* aObj = sender();
+ std::list<BSplinePoleWidgets>::const_iterator aIt;
+ int aId = 0;
+ bool aFound = false;
+ for (aIt = myPoles.cbegin(); aIt != myPoles.cend(); aIt++, aId++) {
+ if ((*aIt).myAddBtn == aObj) {
+ aFound = true;
+ break;
+ }
+ }
+ if (aFound) {
+ // add a new pole after found Id
+ std::ostringstream anActionName;
+ anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << aId;
+ if (feature()->customAction(anActionName.str()))
+ updateObject(feature());
+
+ restoreValueCustom();
+ }
+}
--- /dev/null
+// Copyright (C) 2019-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 PartSet_BSplineWidget_H
+#define PartSet_BSplineWidget_H
+
+
+#include <PartSet.h>
+
+#include <ModelAPI_Feature.h>
+
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_ModelWidget.h>
+#include <ModuleBase_ParamSpinBox.h>
+
+class QGroupBox;
+class QScrollArea;
+class QToolButton;
+
+/** \brief Represent a content of the property panel to show/modify parameters of B-spline curve.
+ * \ingroup GUI
+ */
+class PartSet_BSplineWidget : public ModuleBase_ModelWidget
+{
+Q_OBJECT
+public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ PartSet_BSplineWidget(QWidget* theParent,
+ const Config_WidgetAPI* theData);
+
+ virtual ~PartSet_BSplineWidget() {}
+
+ /// The methiod called when widget is deactivated
+ virtual void deactivate();
+
+ /// Returns list of widget controls
+ /// \return a control list
+ virtual QList<QWidget*> getControls() const;
+
+ /// Set feature which is processing by active operation
+ /// \param theFeature a feature object
+ /// \param theToStoreValue a value about necessity to store the widget value to the feature
+ /// \param isUpdateFlushed a flag if update should be flushed on store value
+ virtual void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
+ const bool isUpdateFlushed = true);
+
+protected:
+ /// Saves the internal parameters to the given feature
+ /// \return True in success
+ virtual bool storeValueCustom();
+
+ /// Restore value from attribute data to the widget's control
+ virtual bool restoreValueCustom();
+
+ /// Create group of widgets related to coordinates of pole and its weight
+ void addPoleWidget();
+
+ /// Update attributes of B-spline feature
+ void storePolesAndWeights() const;
+
+private slots:
+ void onAddPole();
+
+private:
+ struct BSplinePoleWidgets {
+ ModuleBase_LabelValue* myX;
+ ModuleBase_LabelValue* myY;
+ ModuleBase_ParamSpinBox* myWeight;
+ QToolButton* myAddBtn;
+ };
+
+ QGroupBox* createPoleWidget(BSplinePoleWidgets& thePole,
+ const QString& theName,
+ QWidget* theParent);
+
+ QWidget* myPolesWgt; ///< widget to show poles and weights of B-spline curve
+ QGroupBox* myPolesGroupBox;
+ QScrollArea* myScrollArea;
+ std::list<BSplinePoleWidgets> myPoles; ///< list of B-spline poles and their weights
+};
+
+#endif
\ No newline at end of file
#include <ModuleBase_Operation.h>
#include <ModuleBase_OperationFeature.h>
#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_IViewer.h>
#include <ModuleBase_Tools.h>
#include <XGUI_ModuleConnector.h>
#include <XGUI_DataModel.h>
#include <XGUI_OperationMgr.h>
#include <XGUI_ObjectsBrowser.h>
+#include <XGUI_ViewerProxy.h>
#include <Events_Loop.h>
#include <ModelAPI_Events.h>
#include <QAction>
#include <QMenu>
#include <QEvent>
+#include <QApplication>
#include <TopoDS.hxx>
#include <BRep_Tool.hxx>
aAction = ModuleBase_Tools::createAction(QIcon(":icons/edit.png"), tr("Edit..."), aParent,
this, SLOT(onEdit(bool)));
myActions["EDIT_CMD"] = aAction;
+
+ aAction = ModuleBase_Tools::createAction(QIcon(":icons/activate.png"), tr("Load all parts"),
+ aParent, this, SLOT(onActivateAllParts()));
+ myActions["ACTIVATE_ALL_PARTS_CMD"] = aAction;
}
}
}
+void PartSet_MenuMgr::onActivateAllParts()
+{
+ SessionPtr aMgr = ModelAPI_Session::get();
+ if (aMgr->isOperation())
+ return;
+
+ DocumentPtr aDoc = aMgr->moduleDocument();
+ int aNbParts = aDoc->size(ModelAPI_ResultPart::group());
+ bool isActivated = false;
+ QList<ResultPartPtr> aPartsToLoad;
+ for (int i = 0; i < aNbParts; i++) {
+ ObjectPtr aObj = aDoc->object(ModelAPI_ResultPart::group(), i);
+ ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
+ if (!aPartRes->partDoc().get())
+ aPartsToLoad.append(aPartRes);
+ }
+ if (!aPartsToLoad.isEmpty()) {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ aMgr->startOperation("All Parts loading");
+ foreach(ResultPartPtr aPartRes, aPartsToLoad) {
+ aPartRes->loadPart();
+ }
+ aMgr->finishOperation();
+
+ XGUI_Workshop* aWorkshop = myModule->getWorkshop();
+ XGUI_ObjectsBrowser* aObjBrowser = aWorkshop->objectBrowser();
+ aObjBrowser->update();
+ aWorkshop->viewer()->update();
+ aWorkshop->updateCommandStatus();
+ QApplication::restoreOverrideCursor();
+ }
+}
+
void PartSet_MenuMgr::onActivatePartSet(bool)
{
if (myModule->workshop()->currentOperation())
aMgr->finishOperation();
myModule->workshop()->updateCommandStatus();
+ myModule->workshop()->viewer()->update();
}
void PartSet_MenuMgr::grantedOperationIds(ModuleBase_Operation* theOperation,
/// A slot called on edit of feature
void onEdit(bool);
+ /// Activates all not loaded parts
+ void onActivateAllParts();
+
protected:
/// Redefinition of virtual method
/// \param theObj an object
#include "PartSet_Validators.h"
#include "PartSet_Tools.h"
#include "PartSet_PreviewPlanes.h"
+#include "PartSet_WidgetBSplinePoints.h"
#include "PartSet_WidgetPoint2d.h"
#include "PartSet_WidgetPoint2DFlyout.h"
#include "PartSet_WidgetShapeSelector.h"
#include "PartSet_OverconstraintListener.h"
#include "PartSet_TreeNodes.h"
#include "PartSet_FieldStepPrs.h"
+#include "PartSet_BSplineWidget.h"
#include "PartSet_Filters.h"
#include "PartSet_FilterInfinite.h"
}
// It is switched off because of
// Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
- //else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
- // mySketchMgr->startNestedSketch(theOperation);
- //}
+ else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
+ mySketchMgr->startNestedSketch(theOperation);
+ }
}
//******************************************************
return aProcessed;
}
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- AttributePtr anAttribute = PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape,
- mySketchMgr->activeSketch());
- if (anAttribute.get()) {
+ std::pair<AttributePtr, int> anAttribute =
+ PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape, mySketchMgr->activeSketch());
+ if (anAttribute.first.get()) {
ModuleBase_WidgetFactory aFactory(theXmlRepr.toStdString(), workshop());
- const std::string anAttributeId = anAttribute->id();
+ const std::string anAttributeId = anAttribute.first->id();
aFactory.createWidget(aPropertyPanel->contentWidget(), anAttributeId);
theWidgets = aFactory.getModelWidgets();
aPointSelectorWgt->setSketcher(mySketchMgr->activeSketch());
aWgt = aPointSelectorWgt;
}
+ else if (theType == "sketch-bspline_selector") {
+ PartSet_WidgetBSplinePoints* aBSplineWgt =
+ new PartSet_WidgetBSplinePoints(theParent, aWorkshop, theWidgetApi);
+ aBSplineWgt->setSketch(mySketchMgr->activeSketch());
+ aWgt = aBSplineWgt;
+ }
else if (theType == WDG_DOUBLEVALUE_EDITOR) {
aWgt = new PartSet_WidgetEditor(theParent, aWorkshop, theWidgetApi);
} else if (theType == "export_file_selector") {
aWgt = new PartSet_WidgetFileSelector(theParent, aWorkshop, theWidgetApi);
} else if (theType == "sketch_launcher") {
aWgt = new PartSet_WidgetSketchCreator(theParent, this, theWidgetApi);
- } else if (theType == "module_choice") {
+ }
+ else if (theType == "module_choice") {
aWgt = new ModuleBase_WidgetChoice(theParent, theWidgetApi);
connect(aWgt, SIGNAL(itemSelected(ModuleBase_ModelWidget*, int)),
- this, SLOT(onChoiceChanged(ModuleBase_ModelWidget*, int)));
+ this, SLOT(onChoiceChanged(ModuleBase_ModelWidget*, int)));
+ } else if (theType == "bspline-panel") {
+ PartSet_BSplineWidget* aPanel = new PartSet_BSplineWidget(theParent, theWidgetApi);
+ //aPanel->setFeature(theFeature);
+ aWgt = aPanel;
}
return aWgt;
}
QMenu aMenu;
aMenu.addAction(aActivatePartAction);
+
+#ifndef HAVE_SALOME
+ if (aMgr->activeDocument() == aMgr->moduleDocument()) {
+ DocumentPtr aDoc = aMgr->moduleDocument();
+ int aNbParts = aDoc->size(ModelAPI_ResultPart::group());
+ bool aHaveToActivate = false;
+ for (int i = 0; i < aNbParts; i++) {
+ ObjectPtr aObj = aDoc->object(ModelAPI_ResultPart::group(), i);
+ ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
+ if (!aPartRes->partDoc().get()) {
+ aHaveToActivate = true;
+ break;
+ }
+ }
+ if (aHaveToActivate) {
+ QAction* aActivateAllPartAction = myMenuMgr->action("ACTIVATE_ALL_PARTS_CMD");
+ aMenu.addAction(aActivateAllPartAction);
+ }
+ }
+#endif
+
aMenu.exec(aHeader->mapToGlobal(thePnt));
}
XGUI_Displayer* aDisplayer = aWorkshop->displayer();
QObjectPtrList aObjects = aDisplayer->displayedObjects();
bool aHidden;
- bool aUpdateViewer = false;
foreach(ObjectPtr aObj, aObjects) {
aHidden = !aObj->data() || !aObj->data()->isValid() ||
aObj->isDisabled() || (!aObj->isDisplayed());
if (!aHidden) {
aDisplayer->redisplay(aObj, false);
- aUpdateViewer = true;
}
}
- if (aUpdateViewer)
- aDisplayer->updateViewer();
+ aDisplayer->updateViewer();
// Update tree items if they are expanded
if (needUpdate) {
aTreeView->viewport()->update(aTreeView->viewport()->rect());
if (aGeomShape.get()) {
TopoDS_Shape aTDSShape = aGeomShape->impl<TopoDS_Shape>();
- return PartSet_Tools::findAttributeBy2dPoint(theObject, aTDSShape,
- mySketchMgr->activeSketch());
+ std::pair<AttributePtr, int> anAttrAndIndex =
+ PartSet_Tools::findAttributeBy2dPoint(theObject, aTDSShape, mySketchMgr->activeSketch());
+ return anAttrAndIndex.first;
}
return anAttribute;
}
#include <ModuleBase_ViewerFilters.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomAPI_Shape.h>
void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,
const FeaturePtr& theFeature, const FeaturePtr& theSketch,
const ResultPtr& theResult,
- std::set<AttributePtr>& theSelectedAttributes,
+ std::map<AttributePtr, int>& theSelectedAttributes,
std::set<ResultPtr>& theSelectedResults,
TopTools_MapOfShape& theShapes)
{
theShapes.Add(aShape);
TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
if (aShapeType == TopAbs_VERTEX) {
- AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,
- aShape, theSketch);
- if (aPntAttr.get() != NULL)
- theSelectedAttributes.insert(aPntAttr);
+ std::pair<AttributePtr, int> aPntAttrIndex =
+ PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
+ if (aPntAttrIndex.first.get() != NULL)
+ theSelectedAttributes[aPntAttrIndex.first] = aPntAttrIndex.second;
}
else if (aShapeType == TopAbs_EDGE &&
theSelectedResults.find(theResult) == theSelectedResults.end()) {
// It is switched off because of
// Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
- // if (canChangeCursor(getCurrentOperation())) {
- // QCursor* aCurrentCursor = QApplication::overrideCursor();
- // if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
- // QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
+ if (canChangeCursor(getCurrentOperation())) {
+ QCursor* aCurrentCursor = QApplication::overrideCursor();
+ if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
+ QApplication::setOverrideCursor(PartSet_Tools::getOperationCursor());
//#ifdef DEBUG_CURSOR
// qDebug("onEnterViewPort() : Qt::CrossCursor");
//#endif
- // }
- // }
+ }
+ }
if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
return;
return;
#endif
-// if (canChangeCursor(getCurrentOperation())) {
-// QApplication::restoreOverrideCursor();
+ if (canChangeCursor(getCurrentOperation())) {
+ QApplication::restoreOverrideCursor();
//#ifdef DEBUG_CURSOR
// qDebug("onLeaveViewPort() : None");
//#endif
-// }
+ }
if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
return;
}
*/
+bool PartSet_SketcherMgr::isDragModeCreation() const
+{
+ ModuleBase_Operation* aOp = getCurrentOperation();
+ if (!aOp)
+ return false;
+ bool aUserPref = Config_PropManager::boolean(SKETCH_TAB_NAME, "create_by_dragging");
+ if (!aUserPref)
+ return false;
+ QString aId = aOp->id();
+ // Acceptable features;
+ QStringList aList;
+ aList << "SketchLine" << "SketchMacroCircle" << "SketchMacroArc" <<
+ "SketchMacroEllipse" << "SketchMacroEllipticArc" << "SketchRectangle";
+ return aList.contains(aId);
+}
+
+static bool MyModeByDrag = false;
+static bool MyMultiselectionState = true;
+
void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
{
+ MyModeByDrag = isDragModeCreation();
+
// Clear dragging mode
myIsDragging = false;
+ myMousePoint.setX(theEvent->x());
+ myMousePoint.setY(theEvent->y());
+
if (myModule->sketchReentranceMgr()->processMousePressed(theWnd, theEvent))
return;
//get2dPoint(theWnd, theEvent, myClickedPoint);
return;
// Ignore creation sketch operation
- if ((!isSketcher) && (!isEditing))
+ if ((!isSketcher) && (!isEditing)) {
+ if (MyModeByDrag) {
+ ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
+ PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
+ if (aProcessor) {
+ MyMultiselectionState = aViewer->isMultiSelectionEnabled();
+ aViewer->enableMultiselection(false);
+ myIsDragging = true;
+ ModuleBase_ISelection* aSelection = aWorkshop->selection();
+ QList<ModuleBase_ViewerPrsPtr> aPreSelected = aSelection->getHighlighted();
+ if (!aPreSelected.empty())
+ aProcessor->setPreSelection(aPreSelected.first(), theWnd, theEvent);
+ else
+ aProcessor->mouseReleased(theWnd, theEvent);
+ }
+ }
return;
-
+ }
bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
storeSelection(aHasShift ? ST_SelectAndHighlightType : ST_HighlightType, myCurrentSelection);
}
}
}
- else
- isRelaunchEditing = !myCurrentSelection.contains(aSPFeature);
-
+ else {
+ if (myCurrentSelection.size() > 1)
+ isRelaunchEditing = !myCurrentSelection.contains(aSPFeature);
+ }
if (isRelaunchEditing)
aFOperation->commit();
if (!myIsMouseOverViewProcessed) {
return;
}
- //if (!aViewer->canDragByMouse())
- // return;
+
ModuleBase_OperationFeature* aOp =
dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
+ bool isEditing = false;
if (aOp) {
- bool aStartNoDragOperation = !aViewer->canDragByMouse() && aOp->isEditOperation();
+ isEditing = aOp->isEditOperation();
+ bool aStartNoDragOperation = !aViewer->canDragByMouse() && isEditing;
if (aStartNoDragOperation || myNoDragMoving) {
// Process edit operation without dragging
if (myCurrentSelection.size() > 0)
}
}
-
ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
- if (aProcessor)
- aProcessor->mouseReleased(theWnd, theEvent);
+ if (aProcessor) {
+ ModuleBase_ISelection* aSelection = aWorkshop->selection();
+ QList<ModuleBase_ViewerPrsPtr> aPreSelected = aSelection->getHighlighted();
+ if (MyModeByDrag && !aPreSelected.empty() && !isEditing)
+ aProcessor->setPreSelection(aPreSelected.first(), theWnd, theEvent);
+ else
+ aProcessor->mouseReleased(theWnd, theEvent);
+ }
+ if (MyModeByDrag && aOp) {
+ QString aOpId = aOp->id();
+ if (aOpId == "Sketch")
+ return;
+ QPoint aPnt(theEvent->x(), theEvent->y());
+ anActiveWidget = getActiveWidget();
+ if ((aPnt == myMousePoint) && anActiveWidget) {
+ aOp->abort();
+ return;
+ }
+ bool aCanRestart = !anActiveWidget && !isEditing;
+ if (aCanRestart) {
+ module()->launchOperation(aOpId, true);
+ }
+ }
}
void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
qDebug(QString("%1").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
}
#endif
+
if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
return;
for (; anIt != aLast; anIt++) {
FeaturePtr aFeature = anIt.key();
- std::set<AttributePtr> anAttributes = anIt.value().myAttributes;
+ std::map<AttributePtr, int> anAttributes = anIt.value().myAttributes;
// Process selection by attribute: the priority to the attribute
if (!anAttributes.empty()) {
- std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
+ std::map<AttributePtr, int>::const_iterator anAttIt = anAttributes.begin(),
anAttLast = anAttributes.end();
for (; anAttIt != anAttLast; anAttIt++) {
- AttributePtr anAttr = *anAttIt;
+ AttributePtr anAttr = anAttIt->first;
if (anAttr.get() == NULL)
continue;
std::string aAttrId = anAttr->id();
DataPtr aData = aFeature->data();
if (aData->isValid()) {
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
- if (aPoint.get() != NULL) {
+ AttributePtr aPoint = aData->attribute(aAttrId);
+ if (aPoint->attributeType() == GeomDataAPI_Point2D::typeId() ||
+ aPoint->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
bool isImmutable = aPoint->setImmutable(true);
std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
<ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
- aMessage->setMovedAttribute(aPoint);
+ aMessage->setMovedAttribute(aPoint, anAttIt->second);
aMessage->setOriginalPosition(anOriginalPosition);
aMessage->setCurrentPosition(aCurrentPosition);
Events_Loop::loop()->send(aMessage);
workshop()->viewer()->set2dMode(false);
}
-//void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
-//{
-// if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
-// QCursor* aCurrentCursor = QApplication::overrideCursor();
-// if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
-// QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
+void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
+{
+ if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
+ QCursor* aCurrentCursor = QApplication::overrideCursor();
+ if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
+ QApplication::setOverrideCursor(PartSet_Tools::getOperationCursor());
//#ifdef DEBUG_CURSOR
// qDebug("startNestedSketch() : Qt::CrossCursor");
//#endif
-// }
-// }
-//}
+ }
+ }
+}
void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
{
myIsMouseOverViewProcessed = true;
operationMgr()->onValidateOperation();
// when sketch nested operation is stopped the cursor should be restored unconditionally
- //if (canChangeCursor(theOperation)) {
- //QApplication::restoreOverrideCursor();
+ if (canChangeCursor(theOperation)) {
+ QApplication::restoreOverrideCursor();
#ifdef DEBUG_CURSOR
qDebug("stopNestedSketch() : None");
#endif
- //}
+ }
/// improvement to deselect automatically all eventual selected objects, when
// returning to the neutral point of the Sketcher
bool isClearSelectionPossible = true;
FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
SelectionInfo anInfo = anIt.value();
- std::set<AttributePtr> aSelectedAttributes = anInfo.myAttributes;
+ std::map<AttributePtr, int> aSelectedAttributes = anInfo.myAttributes;
std::set<ResultPtr> aSelectedResults = anInfo.myResults;
ModuleBase_IViewer* aViewer = theWorkshop->viewer();
const TopoDS_Shape& aShape = anOwner->Shape();
TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
if (aShapeType == TopAbs_VERTEX) {
- AttributePtr aPntAttr =
+ std::pair<AttributePtr, int> aPntAttrIndex =
PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
- if (aPntAttr.get() != NULL &&
- aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end())
+ if (aPntAttrIndex.first.get() != NULL &&
+ aSelectedAttributes.find(aPntAttrIndex.first) != aSelectedAttributes.end())
theOwnersToSelect.Add(anOwner);
else if (isSameShape && anInfo.myLocalSelectedShapes.Contains(aShape)) {
theOwnersToSelect.Add(anOwner);
if (aPrevState != theState) {
/// call all sketch features redisplay, the expression state will be corrected in customize
/// of distance presentation
- SketcherPrs_Tools::
- sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
+ SketcherPrs_Tools::ParameterStyle aStyle = myIsConstraintsShown[PartSet_Tools::Expressions]
+ ? SketcherPrs_Tools::ParameterText : SketcherPrs_Tools::ParameterValue;
+ SketcherPrs_Tools::setParameterStyle(aStyle);
Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
}
if (aShapeType != 6/*an edge*/ && aShapeType != 7/*a vertex*/ && aShapeType != 0/*compound*/)
return;
+ int aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
if (isExternal(aFeature)) {
- thePrs->setWidth(1);
+ thePrs->setWidth(isIncludeToResult(aFeature)? aWidth : 1);
return;
}
std::string aKind = aFeature->getKind();
thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY());
}
else {
- int aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
thePrs->setWidth(aWidth);
thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE());
}
#include <QObject>
#include <QList>
#include <QMap>
+#include <QPoint>
#include <set>
/// Struct to define selection model information to store/restore selection
struct SelectionInfo
{
- std::set<AttributePtr> myAttributes; /// the selected attributes
+ /// the selected attributes and indices of points if array
+ std::map<AttributePtr, int> myAttributes;
std::set<ResultPtr> myResults; /// the selected results
TopoDS_Shape myFirstResultShape; /// the first shape of feature result
TopTools_MapOfShape myLocalSelectedShapes; /// shapes of local selection
/// Starts sketch operation, connects to the opeation property panel
/// \param theOperation a committed operation
- //void startNestedSketch(ModuleBase_Operation* theOperation);
+ void startNestedSketch(ModuleBase_Operation* theOperation);
/// Stop sketch operation, disconnects from the opeation property panel
/// \param theOperation a stopped operation
*/
virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+ /// Returns true if current mode of objects creation is by drag mouse
+ bool isDragModeCreation() const;
+
public slots:
/// Process sketch plane selected event
QMap<ResultPtr, Handle(AIS_Shape)> myPointsHighlight;
bool myNoDragMoving;
+
+ QPoint myMousePoint;
};
ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
(myWorkshop->currentOperation());
+ if (module()->sketchMgr()->isDragModeCreation()) {
+ if (aFOperation && myIsAutoConstraints)
+ addConstraints(aFOperation->feature());
+ return;
+ }
if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
return;
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomAPI_Pln.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Pnt.h>
// attribute, returns the shape
PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(theWorkshop->module());
PartSet_SketcherMgr* aSketchMgr = aModule->sketchMgr();
- AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(anAttributeFeature,
- aBRepShape, aSketchMgr->activeSketch());
- if (aPntAttr.get() != NULL && aPntAttr == theAttribute) {
+ std::pair<AttributePtr, int> aPntAttrIndex = PartSet_Tools::findAttributeBy2dPoint(
+ anAttributeFeature, aBRepShape, aSketchMgr->activeSketch());
+ if (aPntAttrIndex.first.get() != NULL && aPntAttrIndex.first == theAttribute) {
aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
aShape->setImpl(new TopoDS_Shape(aBRepShape));
break;
return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY));
}
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(const Handle(V3d_View)& theView,
+ const TopoDS_Shape& theShape,
+ const FeaturePtr& theSketch)
+{
+ GeomPnt2dPtr aPoint2D;
+ if (!theShape.IsNull() && theShape.ShapeType() == TopAbs_VERTEX) {
+ const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
+ if (!aVertex.IsNull()) {
+ // the case when the point is taken from the existing vertex
+ gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
+ double aX, aY;
+ PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, aY);
+ aPoint2D.reset(new GeomAPI_Pnt2d(aX, aY));
+ }
+ }
+ return aPoint2D;
+}
+
FeaturePtr findFirstCoincidenceByData(const DataPtr& theData,
std::shared_ptr<GeomAPI_Pnt2d> thePoint)
{
return aPnt;
}
-AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
- const TopoDS_Shape theShape,
- FeaturePtr theSketch)
+class PointWrapper
+{
+public:
+ PointWrapper(AttributePtr theAttribute)
+ : myPoint(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute)),
+ myArray(std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute))
+ {}
+
+ int size() const { return myPoint.get() ? 1 : (myArray.get() ? myArray->size() : 0); }
+
+ GeomPointPtr point(int theIndex, FeaturePtr theSketch)
+ {
+ GeomPnt2dPtr aP2d;
+ if (myPoint.get())
+ aP2d = myPoint->pnt();
+ else if (myArray.get())
+ aP2d = myArray->pnt(theIndex);
+
+ GeomPointPtr aP3d;
+ if (aP2d.get())
+ aP3d = PartSet_Tools::convertTo3D(aP2d->x(), aP2d->y(), theSketch);
+ return aP3d;
+ }
+
+ bool isArray() const { return myArray.get(); }
+
+private:
+ AttributePoint2DPtr myPoint;
+ AttributePoint2DArrayPtr myArray;
+};
+
+std::pair<AttributePtr, int> PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
+ const TopoDS_Shape theShape,
+ FeaturePtr theSketch)
{
AttributePtr anAttribute;
+ int aPointIndex = -1;
FeaturePtr aFeature = ModelAPI_Feature::feature(theObj);
if (aFeature) {
if (theShape.ShapeType() == TopAbs_VERTEX) {
// find the given point in the feature attributes
std::list<AttributePtr> anAttiributes =
aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr> anArrays =
+ aFeature->data()->attributes(GeomDataAPI_Point2DArray::typeId());
+ anAttiributes.insert(anAttiributes.end(), anArrays.begin(), anArrays.end());
+
std::list<AttributePtr>::const_iterator anIt = anAttiributes.begin(),
aLast = anAttiributes.end();
double aMinDistance = 1.e-6; // searching for point with minimal distance and < 1.e-6
for (; anIt != aLast && !anAttribute; anIt++) {
- std::shared_ptr<GeomDataAPI_Point2D> aCurPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
- if (!aCurPoint->isInitialized())
- continue;
-
- std::shared_ptr<GeomAPI_Pnt> aPnt =
- convertTo3D(aCurPoint->x(), aCurPoint->y(), theSketch);
- if (aPnt) {
- double aDistance = aPnt->distance(aValue);
- if (aDistance < aMinDistance) {
- anAttribute = aCurPoint;
- aMinDistance = aPnt->distance(aValue);
+ PointWrapper aWrapper(*anIt);
+ for (int anIndex = 0, aSize = aWrapper.size(); anIndex < aSize; ++anIndex) {
+ std::shared_ptr<GeomAPI_Pnt> aPnt = aWrapper.point(anIndex, theSketch);
+ if (aPnt) {
+ double aDistance = aPnt->distance(aValue);
+ if (aDistance < aMinDistance) {
+ anAttribute = *anIt;
+ if (aWrapper.isArray())
+ aPointIndex = anIndex;
+ aMinDistance = aPnt->distance(aValue);
+ }
}
}
}
}
}
}
- return anAttribute;
+ return std::pair<AttributePtr, int>(anAttribute, aPointIndex);
}
void PartSet_Tools::sendSubFeaturesEvent(const CompositeFeaturePtr& theComposite,
{
return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
}
+
+QCursor PartSet_Tools::getOperationCursor()
+{
+ int aId = Config_PropManager::integer(SKETCH_TAB_NAME, "operation_cursor");
+ switch (aId) {
+ case 0:
+ return QCursor(Qt::ArrowCursor);
+ case 1:
+ return QCursor(Qt::CrossCursor);
+ case 2:
+ return QCursor(Qt::PointingHandCursor);
+ }
+ return QCursor();
+}
#include <QPoint>
#include <QList>
+#include <QCursor>
#include <ModelAPI_CompositeFeature.h>
#include <ModelAPI_Object.h>
* \param theObj - an object
* \param theShape - a Shape
* \param theSketch - a Sketch to get a plane of converting to 2d
+ * \return Found attribute and index of point if the attribute is an array
*/
- static AttributePtr findAttributeBy2dPoint(ObjectPtr theObj, const TopoDS_Shape theShape,
- FeaturePtr theSketch);
+ static std::pair<AttributePtr, int> findAttributeBy2dPoint(ObjectPtr theObj,
+ const TopoDS_Shape theShape,
+ FeaturePtr theSketch);
/**
* Finds an attribute value in attribute reference attribute value
/**
* Convertes parameters into a geom point
- * \theEvent a Qt event to find mouse position
+ * \param theEvent a Qt event to find mouse position
* \param theWindow view window to define eye of view
* \param theSketch to convert 3D point coordinates into coorditates of the sketch plane
*/
ModuleBase_IViewWindow* theWindow,
const FeaturePtr& theSketch);
+ /** Returns point 2d from selected shape
+ * \param theView a view window
+ * \param theShape a vertex shape
+ * \param theX an output value of X coordinate
+ * \param theY an output value of Y coordinate
+ */
+ static std::shared_ptr<GeomAPI_Pnt2d> getPnt2d(const Handle(V3d_View)& theView,
+ const TopoDS_Shape& theShape,
+ const FeaturePtr& theSketch);
+
/**
* Gets all references to the feature, take coincidence constraint features, get point 2d attributes
* and compare the point value to be equal with the given. Returns the first feature, which has
* Returns default transparency value
*/
static double getDefaultTransparency();
+
+ /**
+ * Returns cursor according to (SKETCH_TAB_NAME, "operation_cursor") property value
+ */
+ static QCursor getOperationCursor();
};
#endif
--- /dev/null
+// Copyright (C) 2019-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 <PartSet_WidgetBSplinePoints.h>
+
+#include <PartSet_CenterPrs.h>
+#include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_Module.h>
+#include <PartSet_SketcherReentrantMgr.h>
+#include <PartSet_WidgetPoint2d.h>
+
+#include <XGUI_Tools.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_IViewer.h>
+#include <ModuleBase_IViewWindow.h>
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_WidgetValidator.h>
+#include <ModuleBase_WidgetValidated.h>
+
+#include <Config_Keywords.h>
+#include <Config_WidgetAPI.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_CompositeFeature.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_IPresentable.h>
+
+#include <SketchPlugin_Feature.h>
+
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QMouseEvent>
+#include <QGraphicsEffect>
+#include <QScrollArea>
+
+static const double MaxCoordinate = 1e12;
+
+static bool IsPointCreated = false;
+
+
+PartSet_WidgetBSplinePoints::PartSet_WidgetBSplinePoints(QWidget* theParent,
+ ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData)
+: ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
+ myValueIsCashed(false), myIsFeatureVisibleInCash(true),
+ myXValueInCash(0), myYValueInCash(0),
+ myPointIndex(0), myFinished(false)
+{
+ myRefAttribute = theData->getProperty("reference_attribute");
+ QVBoxLayout* aMainLayout = new QVBoxLayout(this);
+ ModuleBase_Tools::zeroMargins(aMainLayout);
+
+ // the control should accept the focus, so the boolean flag is corrected to be true
+ myIsObligatory = true;
+ QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
+ myBox = new QGroupBox(aPageName, theParent);
+ myBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myBox->setFlat(false);
+ aMainLayout->addWidget(myBox);
+
+ bool aAcceptVariables = theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
+
+ // B-spline weights attribute
+ myWeightsAttr = theData->getProperty("weights");
+
+ QVBoxLayout* aLayout = new QVBoxLayout(myBox);
+ ModuleBase_Tools::adjustMargins(aLayout);
+
+ myScrollArea = new QScrollArea(myBox);
+ myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myScrollArea->setWidgetResizable(true);
+ myScrollArea->setFrameStyle(QFrame::NoFrame);
+ aLayout->addWidget(myScrollArea);
+
+ QWidget* aContainer = new QWidget(myScrollArea);
+ QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
+ aBoxLay->setContentsMargins(0, 0, 0, 0);
+
+ myGroupBox = new QWidget(aContainer);
+ QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
+ ModuleBase_Tools::adjustMargins(aGroupLay);
+ aGroupLay->setSpacing(4);
+ aGroupLay->setColumnStretch(1, 1);
+ createNextPoint();
+ aBoxLay->addWidget(myGroupBox);
+ aBoxLay->addStretch(1);
+
+ myScrollArea->setWidget(aContainer);
+
+ myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
+ myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
+ theData->getProperty("can_create_external"), true);
+}
+
+void PartSet_WidgetBSplinePoints::createNextPoint()
+{
+ storeCurentValue();
+
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+ int row = (int)myXSpin.size();
+
+ QString aPoleStr = tr("Pole %1");
+ aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
+
+ QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
+ QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+ ModuleBase_Tools::adjustMargins(aPoleLay);
+ aPoleLay->setSpacing(2);
+ aPoleLay->setColumnStretch(1, 1);
+
+ myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
+ aPoleLay->addWidget(myXSpin.back(), 0, 1);
+ myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
+ aPoleLay->addWidget(myYSpin.back(), 1, 1);
+
+ aGroupLay->addWidget(aPoleGroupBox, row, 1);
+ IsPointCreated = true;
+}
+
+void PartSet_WidgetBSplinePoints::removeLastPoint()
+{
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+ QWidget* aXSpin = myXSpin.back();
+ QWidget* aYSpin = myYSpin.back();
+ QWidget* aBox = myXSpin.back()->parentWidget();
+ myYSpin.pop_back();
+ myXSpin.pop_back();
+
+ aGroupLay->removeWidget(aXSpin);
+ aGroupLay->removeWidget(aYSpin);
+ aGroupLay->removeWidget(aBox);
+
+ aBox->deleteLater();
+
+ // update B-spline feature attributes
+ storeValueCustom();
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ bool aValid = true;
+
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+ if (aModule->sketchReentranceMgr()->isInternalEditActive())
+ return true; // when internal edit is started a new feature is created. I has not results, AIS
+
+ // the selection is not possible if the current feature has no presentation for the current
+ // attribute not in AIS not in results. If so, no object in current feature where make
+ // coincidence, so selection is not necessary
+ GeomShapePtr anAISShape;
+ GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
+ if (aPrs.get()) {
+ AISObjectPtr anAIS;
+ anAIS = aPrs->getAISObject(anAIS);
+ if (anAIS.get()) {
+ anAISShape = anAIS->getShape();
+ }
+ }
+ const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
+ if (!anAISShape.get() && aResults.empty())
+ return true;
+
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (aRefAttrList)
+ return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
+ return true;
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionForAttribute_(
+ const ModuleBase_ViewerPrsPtr& theValue,
+ const AttributePtr& theAttribute)
+{
+ bool aValid = false;
+
+ // stores the current values of the widget attribute
+ bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
+
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, true,
+ isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+ myWidgetValidator->storeAttributeValue(aRefAttrList);
+
+ // saves the owner value to the widget attribute
+ aValid = setSelectionCustom(theValue);
+ if (aValid)
+ // checks the attribute validity
+ aValid = myWidgetValidator->isValidAttribute(theAttribute);
+
+ // restores the current values of the widget attribute
+ myWidgetValidator->restoreAttributeValue(aRefAttrList, aValid);
+ myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
+
+ ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, false,
+ isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+ return aValid;
+}
+
+bool PartSet_WidgetBSplinePoints::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ bool isDone = false;
+ GeomShapePtr aShape = theValue->shape();
+ if (aShape.get() && !aShape->isNull()) {
+ Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
+ const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ fillRefAttribute(aPnt, theValue);
+ isDone = true;
+ }
+ else if (aTDShape.ShapeType() == TopAbs_EDGE) {
+ fillRefAttribute(theValue);
+ isDone = true;
+ }
+ }
+ return isDone;
+}
+
+static void fillLabels(std::vector<ModuleBase_LabelValue*>& theLabels, const double theValue)
+{
+ for (std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+ anIt != theLabels.end(); ++anIt)
+ (*anIt)->setValue(theValue);
+}
+
+bool PartSet_WidgetBSplinePoints::resetCustom()
+{
+ bool aDone = false;
+ if (!isUseReset() || isComputedDefault())
+ aDone = false;
+ else {
+ if (myValueIsCashed) {
+ // if the restored value should be hidden, aDone = true to set
+ // reset state for the widget in the parent
+ aDone = restoreCurentValue();
+ emit objectUpdated();
+ }
+ else {
+ // it is important to block the spin box control in order to do not through out the
+ // locking of the validating state.
+ fillLabels(myXSpin, 0.0);
+ fillLabels(myYSpin, 0.0);
+
+ storeValueCustom();
+ aDone = true;
+ }
+ }
+ return aDone;
+}
+
+PartSet_WidgetBSplinePoints::~PartSet_WidgetBSplinePoints()
+{
+ delete myExternalObjectMgr;
+}
+
+bool PartSet_WidgetBSplinePoints::setPoint(double theX, double theY)
+{
+ if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
+ return false;
+
+ myXSpin.back()->setValue(theX);
+ myYSpin.back()->setValue(theY);
+
+ storeValue();
+ return true;
+}
+
+void PartSet_WidgetBSplinePoints::storePolesAndWeights() const
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ int aSize = (int)myXSpin.size();
+ aPointArray->setSize(aSize);
+ aWeightsArray->setSize(aSize);
+
+ std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+ for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
+ aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
+
+ double aWeight = Config_PropManager::real(SKETCH_TAB_NAME, "spline_weight");
+ for (int anIndex = 0; anIndex < aSize; ++anIndex)
+ aWeightsArray->setValue(anIndex, aWeight);
+}
+
+bool PartSet_WidgetBSplinePoints::storeValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ if (!aData || !aData->isValid()) // can be on abort of sketcher element
+ return false;
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ PartSet_WidgetBSplinePoints* that = (PartSet_WidgetBSplinePoints*) this;
+ bool isBlocked = that->blockSignals(true);
+ bool isImmutable = aPointArray->setImmutable(true);
+
+ if (myFeature->isMacro()) {
+ // Moving points of macro-features has been processed directly (without solver)
+ storePolesAndWeights();
+ updateObject(myFeature);
+
+ } else {
+ if (!aPointArray->isInitialized()) {
+ storePolesAndWeights();
+ }
+
+ std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
+ new ModelAPI_ObjectMovedMessage(this));
+ aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
+ aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
+ aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
+ Events_Loop::loop()->send(aMessage);
+ }
+
+ aPointArray->setImmutable(isImmutable);
+ that->blockSignals(isBlocked);
+
+ return true;
+}
+
+bool PartSet_WidgetBSplinePoints::restoreValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ if (aPointArray->isInitialized()) {
+ while (myXSpin.size() < aPointArray->size())
+ createNextPoint();
+
+ std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
+ for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
+ ++anIndex, ++aXIt, ++aYIt) {
+ GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
+ (*aXIt)->setValue(aPoint->x());
+ (*aYIt)->setValue(aPoint->y());
+ }
+ }
+ else {
+ if (myXSpin.empty())
+ createNextPoint();
+
+ myXSpin.back()->setValue(0.0);
+ myYSpin.back()->setValue(0.0);
+ }
+
+ return true;
+}
+
+static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
+ std::vector<double>& theValues)
+{
+ theValues.clear();
+ theValues.reserve(theLabels.size());
+ for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
+ anIt != theLabels.end(); ++anIt)
+ theValues.push_back((*anIt)->value());
+}
+
+void PartSet_WidgetBSplinePoints::storeCurentValue()
+{
+ myValueIsCashed = true;
+ myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
+ XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
+
+ storeArray(myXSpin, myXValueInCash);
+ storeArray(myYSpin, myYValueInCash);
+}
+
+static void restoreArray(std::vector<double>& theCacheValues,
+ std::vector<ModuleBase_LabelValue*>& theLabels)
+{
+ std::vector<double>::iterator aCIt = theCacheValues.begin();
+ std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+ for (; anIt != theLabels.end(); ++anIt) {
+ if (aCIt != theCacheValues.end())
+ (*anIt)->setValue(*aCIt++);
+ else
+ (*anIt)->setValue(0.0);
+ }
+ theCacheValues.clear();
+}
+
+bool PartSet_WidgetBSplinePoints::restoreCurentValue()
+{
+ bool aRestoredAndHidden = true;
+
+ bool isVisible = myIsFeatureVisibleInCash;
+
+ myValueIsCashed = false;
+ myIsFeatureVisibleInCash = true;
+ // fill the control widgets by the cashed value
+ restoreArray(myXValueInCash, myXSpin);
+ restoreArray(myYValueInCash, myYSpin);
+
+ // store value to the model
+ storeValueCustom();
+ if (isVisible) {
+ setValueState(Stored);
+ aRestoredAndHidden = false;
+ }
+ else
+ aRestoredAndHidden = true;
+
+ return aRestoredAndHidden;
+}
+
+QList<QWidget*> PartSet_WidgetBSplinePoints::getControls() const
+{
+ QList<QWidget*> aControls;
+ aControls.append(myScrollArea);
+ return aControls;
+}
+
+void PartSet_WidgetBSplinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
+{
+ theModuleSelectionModes = -1;
+ theModes << TopAbs_VERTEX;
+ theModes << TopAbs_EDGE;
+}
+
+void PartSet_WidgetBSplinePoints::deactivate()
+{
+ // the value of the control should be stored to model if it was not
+ // initialized yet. It is important when we leave this control by Tab key.
+ // It should not be performed by the widget activation as the preview
+ // is visualized with default value. Line point is moved to origin.
+ AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
+ if (anAttribute && !anAttribute->isInitialized())
+ storeValue();
+
+ ModuleBase_ModelWidget::deactivate();
+}
+
+void PartSet_WidgetBSplinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow,
+ QMouseEvent* theEvent)
+{
+ // the contex menu release by the right button should not be processed by this widget
+ if (theEvent->button() != Qt::LeftButton)
+ return;
+
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ Handle(V3d_View) aView = theWindow->v3dView();
+
+ QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
+ ModuleBase_ViewerPrsPtr aFirstValue =
+ aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
+ if (!aFirstValue.get() && myPreSelected.get()) {
+ aFirstValue = myPreSelected;
+ }
+
+ TopoDS_Shape aSelectedShape;
+ ObjectPtr aSelectedObject;
+
+ // if we have selection and use it
+ if (aFirstValue.get() && isValidSelectionCustom(aFirstValue) &&
+ aFirstValue->shape().get()) { // Trihedron Axis may be selected, but shape is empty
+ GeomShapePtr aGeomShape = aFirstValue->shape();
+ aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
+ aSelectedObject = aFirstValue->object();
+
+ FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
+ std::shared_ptr<SketchPlugin_Feature> aSPFeature;
+ if (aSelectedFeature.get())
+ aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
+
+ bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
+ if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
+ ObjectPtr aFixedObject =
+ PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
+ if (aFixedObject)
+ aSelectedObject = aFixedObject;
+ else if (!isSketchExternalFeature) {
+ FeaturePtr aCreatedFeature;
+ aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
+ aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
+ }
+ }
+ }
+ // The selection could be a center of an external circular object
+ else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
+ Handle(PartSet_CenterPrs) aAIS =
+ Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
+ if (!aAIS.IsNull()) {
+ gp_Pnt aPntComp = aAIS->Component()->Pnt();
+ GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
+ aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
+
+ aSelectedObject =
+ PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
+ if (!aSelectedObject.get())
+ {
+ FeaturePtr aCreatedFeature;
+ aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
+ aAIS->centerType(), mySketch, false, aCreatedFeature);
+ }
+ }
+ }
+
+ GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
+ if (!aSelectedPoint) {
+ aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+ setValueState(Stored); // in case of edge selection, Apply state should also be updated
+ }
+ if (aSelectedObject)
+ fillRefAttribute(aSelectedObject);
+ else
+ fillRefAttribute(aSelectedPoint, aFirstValue);
+
+ // next pole of B-spline
+ createNextPoint();
+}
+
+void PartSet_WidgetBSplinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow,
+ QMouseEvent* theEvent)
+{
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+
+ if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
+ return;
+
+ gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+
+ double aX = 0, aY = 0;
+ PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
+ if (myState != ModifiedInViewer)
+ storeCurentValue();
+ // we need to block the value state change
+ bool isBlocked = blockValueState(true);
+ setPoint(aX, aY);
+ blockValueState(isBlocked);
+ setValueState(ModifiedInViewer);
+
+ if (IsPointCreated) {
+ QPoint aPnt = myGroupBox->geometry().bottomLeft();
+ myScrollArea->ensureVisible(aPnt.x(), aPnt.y());
+ IsPointCreated = false;
+ }
+}
+
+bool PartSet_WidgetBSplinePoints::processEscape()
+{
+ bool isProcessed = !isEditingMode();
+ if (isProcessed) {
+ // remove widgets corrsponding to the last pole/weight of B-spline
+ removeLastPoint();
+ myFinished = true;
+
+ emit focusOutWidget(this);
+ }
+ return isProcessed;
+}
+
+bool PartSet_WidgetBSplinePoints::useSelectedShapes() const
+{
+ return true;
+}
+
+AttributeRefAttrListPtr PartSet_WidgetBSplinePoints::attributeRefAttrList() const
+{
+ if (myRefAttribute.empty())
+ return AttributeRefAttrListPtr();
+
+ AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
+ if (!anAttributeRef.get())
+ return AttributeRefAttrListPtr();
+
+ return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(anAttributeRef);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(GeomPnt2dPtr theClickedPoint,
+ const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
+{
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (!aRefAttrList.get())
+ return;
+
+ FeaturePtr aFeature = feature();
+ std::string anAttribute = attributeID();
+
+ if (aFeature.get()) {
+ AttributePoint2DPtr aClickedFeaturePoint =
+ PartSet_WidgetPoint2D::findFirstEqualPointInSketch(mySketch, aFeature, theClickedPoint);
+ if (aClickedFeaturePoint.get())
+ aRefAttrList->append(aClickedFeaturePoint);
+ else
+ fillRefAttribute(theValue);
+ }
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ ObjectPtr anObject;
+ if (theValue)
+ anObject = getGeomSelection(theValue);
+ fillRefAttribute(anObject);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ObjectPtr& theObject)
+{
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (aRefAttrList.get())
+ aRefAttrList->append(theObject);
+}
+
+ObjectPtr PartSet_WidgetBSplinePoints::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ ObjectPtr anObject;
+ GeomShapePtr aShape;
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ anObject = aSelection->getResult(theValue);
+ aShape = aSelection->getShape(theValue);
+ myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
+
+ return anObject;
+}
--- /dev/null
+// Copyright (C) 2019-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 PartSet_WidgetBSplinePoints_H
+#define PartSet_WidgetBSplinePoints_H
+
+#include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
+#include <ModuleBase_ModelWidget.h>
+
+#include <QObject>
+
+class GeomAPI_Pnt2d;
+class ModelAPI_CompositeFeature;
+class ModuleBase_LabelValue;
+class PartSet_ExternalObjectsMgr;
+class QGroupBox;
+class QScrollArea;
+
+/**\class PartSet_WidgetBSplinePoints
+ * \ingroup Modules
+ * \brief Implementation of model widget to provide widget to input a list of 2D poles
+ * of B-spline curve in association with weights
+ * In XML can be defined as following:
+ * \code
+ * <sketch-bspline_selector id="poles" weights="weights"/>
+ * \endcode
+ */
+class PARTSET_EXPORT PartSet_WidgetBSplinePoints : public ModuleBase_ModelWidget,
+ public PartSet_MouseProcessor
+{
+Q_OBJECT
+public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theWorkshop a current workshop
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ PartSet_WidgetBSplinePoints(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData);
+ /// Destructor
+ virtual ~PartSet_WidgetBSplinePoints();
+
+ /// Fills given container with selection modes if the widget has it
+ /// \param [out] theModuleSelectionModes module additional modes, -1 means all default modes
+ /// \param theModes [out] a container of modes
+ virtual void selectionModes(int& theModuleSelectionModes, QIntList& theModes);
+
+ /// Checks if the selection presentation is valid in widget
+ /// \param theValue a selected presentation in the view
+ /// \return a boolean value
+ virtual bool isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+ /// Checks all attribute validators returns valid. It tries on the given selection
+ /// to current attribute by setting the value inside and calling validators. After this,
+ /// the previous attribute value is restored.The valid/invalid value is cashed.
+ /// \param theValue a selected presentation in the view
+ /// \param theAttribute the attribute
+ /// \return a boolean value
+ bool isValidSelectionForAttribute_(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue,
+ const std::shared_ptr<ModelAPI_Attribute>& theAttribute);
+
+ /// Fills the attribute with the value of the selected owner
+ /// \param thePrs a selected owner
+ bool setSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+ /// Returns list of widget controls
+ /// \return a control list
+ virtual QList<QWidget*> getControls() const;
+
+ /// The methiod called when widget is deactivated
+ virtual void deactivate();
+
+ /// \returns the sketch instance
+ std::shared_ptr<ModelAPI_CompositeFeature> sketch() const { return mySketch; }
+
+ /// Set sketch instance
+ void setSketch(std::shared_ptr<ModelAPI_CompositeFeature> theSketch) { mySketch = theSketch; }
+
+ /// Fill the widget values by given point
+ /// \param theX the X coordinate
+ /// \param theY the Y coordinate
+ /// \returns True in case of success
+ bool setPoint(double theX, double theY);
+
+ /// Returns true if the event is processed.
+ virtual bool processEscape();
+
+ /// Returns true if the attribute can be changed using the selected shapes in the viewer
+ /// and creating a coincidence constraint to them. This control use them.
+ virtual bool useSelectedShapes() const;
+
+ /// Processing the mouse move event in the viewer
+ /// \param theWindow a view window
+ /// \param theEvent a mouse event
+ virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+ /// Processing the mouse release event in the viewer
+ /// \param theWindow a view window
+ /// \param theEvent a mouse event
+ virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+protected:
+ /// Saves the internal parameters to the given feature
+ /// \return True in success
+ virtual bool storeValueCustom();
+
+ /// Restore value from attribute data to the widget's control
+ virtual bool restoreValueCustom();
+
+ /// Store current value in cashed value
+ void storeCurentValue();
+
+ /// Restore cashed value in the model attribute
+ /// \return boolean state if the restored feature shoud be hidden
+ bool restoreCurentValue();
+
+ /// Fills the widget with default values
+ /// \return true if the widget current value is reset
+ virtual bool resetCustom();
+
+private:
+ /// Create labels for the next B-spline point
+ void createNextPoint();
+ /// Remove labels for the last B-spline point
+ void removeLastPoint();
+
+ /// Save B-spline poles and weights to corresponding attributes
+ void storePolesAndWeights() const;
+
+ /// Returns attribute reference if the key is defined in XML definition of this control
+ /// \return found attribute or null
+ std::shared_ptr<ModelAPI_AttributeRefAttrList> attributeRefAttrList() const;
+
+ void fillRefAttribute(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ void fillRefAttribute(std::shared_ptr<GeomAPI_Pnt2d> theClickedPoint,
+ const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ void fillRefAttribute(const ObjectPtr& theObject);
+
+ ObjectPtr getGeomSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+protected:
+ ModuleBase_IWorkshop* myWorkshop; ///< workshop
+
+private:
+ QGroupBox* myBox;
+ QWidget* myGroupBox; ///< the parent group box for all intenal widgets
+ QScrollArea* myScrollArea;
+ std::vector<ModuleBase_LabelValue*> myXSpin; ///< the label for the X coordinate
+ std::vector<ModuleBase_LabelValue*> myYSpin; ///< the label for the Y coordinate
+ PartSet_ExternalObjectsMgr* myExternalObjectMgr; ///< reference to external objects manager
+
+ /// value used as selection in mouse release method
+ std::shared_ptr<ModuleBase_ViewerPrs> myPreSelected;
+
+ /// it is important during restart operation
+ CompositeFeaturePtr mySketch;
+
+ std::string myRefAttribute; /// if not empty, coincidences are not set but attribute is filled
+
+ bool myValueIsCashed; /// boolean state if the value is cashed during value state change
+ bool myIsFeatureVisibleInCash; /// boolean value if the feature was visible when cash if filled
+ std::vector<double> myXValueInCash; /// the cashed X value during value state change
+ std::vector<double> myYValueInCash; /// the cashed Y value during value state change
+ std::vector<double> myWeightInCash; /// the cached Weight value during valude state change
+
+ std::string myWeightsAttr;
+
+ int myPointIndex; /// index of the changing point
+
+ bool myFinished; /// \c true if building the B-spline is finished (escape pressed)
+};
+
+#endif
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
+#include "PartSet_WidgetFeaturePointSelector.h"
+#include "PartSet_Tools.h"
+#include "PartSet_ExternalObjectsMgr.h"
+
#include <Config_WidgetAPI.h>
#include <Events_Loop.h>
#include <ModuleBase_IWorkshop.h>
#include <ModuleBase_IModule.h>
-#include "PartSet_WidgetFeaturePointSelector.h"
-#include "PartSet_Tools.h"
-
#include <SketchPlugin_Point.h>
#include <XGUI_Tools.h>
: ModuleBase_WidgetShapeSelector(theParent, theWorkshop, theData)
{
std::string anAttributes = theData->getProperty("selection_attributes");
- QStringList anAttributesList = QString(anAttributes.c_str()).split(' ', QString::SkipEmptyParts);
+ QStringList anAttributesList =
+ QString(anAttributes.c_str()).split(' ', QString::SkipEmptyParts);
myHasPreview = anAttributesList.size() >= 4;
myPreviewObjectAttribute = anAttributesList[2].toStdString();
myPreviewPointAttribute = anAttributesList[3].toStdString();
}
+ myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
+ theData->getProperty("can_create_external"), true);
}
PartSet_WidgetFeaturePointSelector::~PartSet_WidgetFeaturePointSelector()
{
+ delete myExternalObjectMgr;
}
//********************************************************************
//return true;
}
-//********************************************************************
-void PartSet_WidgetFeaturePointSelector::updateSelectionModesAndFilters(bool toActivate)
-{
-#ifdef HIGHLIGHT_STAYS_PROBLEM
- Handle(AIS_InteractiveContext) aContext =
- XGUI_Tools::workshop(myWorkshop)->viewer()->AISContext();
- Quantity_Color aColor;
- Handle(Prs3d_Drawer) aHStyle = aContext->HighlightStyle();
- Handle(Prs3d_Drawer) aSStyle = aContext->SelectionStyle();
- if (toActivate) {
- std::vector<int> aColors;
- aColors = Config_PropManager::color("Visualization", "sketch_entity_color");
- aColor = Quantity_Color(aColors[0] / 255., aColors[1] / 255., aColors[2] / 255.,
- Quantity_TOC_RGB);
- myHighlightColor = aHStyle->Color();
- mySelectionColor = aSStyle->Color();
- }
- else {
- aColor = myHighlightColor;
- }
- aHStyle->SetColor(aColor);
- aContext->SetHighlightStyle(aHStyle);
-
- aSStyle->SetColor(aColor);
- aContext->SetSelectionStyle(aSStyle);
-
-#endif
-
- ModuleBase_WidgetShapeSelector::updateSelectionModesAndFilters(toActivate);
-}
-
//********************************************************************
void PartSet_WidgetFeaturePointSelector::activateCustom()
{
ModuleBase_ViewerPrsPtr aPrs = !aHighlighted.empty() ? aHighlighted.first()
: ModuleBase_ViewerPrsPtr();
- fillFeature(aPrs, theWindow, theEvent);
+ myPreviewPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+ if (myHasPreview) {
+ if (aPrs.get() && aPrs->object().get())
+ myPreviewObject = aPrs->object();
+ else
+ myPreviewObject = ObjectPtr();
+ fillFeature();
+ updateObject(feature());
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+ }
}
//********************************************************************
if (theEvent->button() != Qt::LeftButton)
return;
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ QList<ModuleBase_ViewerPrsPtr> aSelected =
+ aSelection->getSelected(ModuleBase_ISelection::Viewer);
+
+ ModuleBase_ViewerPrsPtr aPrs =
+ !aSelected.empty() ? aSelected.first() : ModuleBase_ViewerPrsPtr();
+ if (aPrs.get() && aPrs->object().get()) {
+ myPreviewObject = aSelection->getResult(aPrs);
+ GeomShapePtr aShape = aSelection->getShape(aPrs);
+ myExternalObjectMgr->getGeomSelection(aPrs, myPreviewObject, aShape,
+ myWorkshop, sketch(), true);
+ }
+ myPreviewPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+
ObjectPtr aPreviewObject;
GeomPnt2dPtr aPreviewPoint;
if (myHasPreview) {
if (!aPreviewObject.get())
return;
+ // Do not use non-sketcher objects
+ if (!sketch()->isSub(aPreviewObject))
+ return;
+
// set parameters of preview into parameters of selection in the feature
std::shared_ptr<GeomDataAPI_Point2D> aPointSelectedAttr =
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
}
//********************************************************************
-bool PartSet_WidgetFeaturePointSelector::fillFeature(
- const std::shared_ptr<ModuleBase_ViewerPrs>& theSelectedPrs,
- ModuleBase_IViewWindow* theWindow,
- QMouseEvent* theEvent)
+bool PartSet_WidgetFeaturePointSelector::fillFeature()
{
- bool aFilled = false;
- if (theSelectedPrs.get() && theSelectedPrs->object().get())
- myPreviewObject = theSelectedPrs->object();
- myPreviewPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
-
if (myHasPreview) {
std::shared_ptr<ModelAPI_AttributeReference> aRef =
std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
feature()->data()->attribute(myPreviewObjectAttribute));
aRef->setValue(myPreviewObject);
-
- std::shared_ptr<GeomDataAPI_Point2D> anAttributePoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- feature()->data()->attribute(myPreviewPointAttribute));
- anAttributePoint->setValue(myPreviewPoint);
+ if (myPreviewPoint.get()) {
+ std::shared_ptr<GeomDataAPI_Point2D> anAttributePoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ feature()->data()->attribute(myPreviewPointAttribute));
+ anAttributePoint->setValue(myPreviewPoint);
+ }
+ }
+ else {
+ // Do not use non-sketcher objects
+ if (!sketch()->isSub(myPreviewObject))
+ return false;
+
+ // set parameters of preview into parameters of selection in the feature
+ if (myPreviewPoint.get()) {
+ std::shared_ptr<GeomDataAPI_Point2D> aPointSelectedAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ feature()->data()->attribute(mySelectedPointAttribute));
+ aPointSelectedAttr->setValue(myPreviewPoint);
+ }
+ AttributeReferencePtr aRefSelectedAttr = feature()->reference(mySelectedObjectAttribute);
+ if (aRefSelectedAttr)
+ aRefSelectedAttr->setValue(myPreviewObject);
+ else {
+ AttributeRefAttrPtr aRefAttrSelectedAttr = feature()->refattr(mySelectedObjectAttribute);
+ if (aRefAttrSelectedAttr)
+ aRefAttrSelectedAttr->setObject(myPreviewObject);
+ }
}
// redisplay AIS presentation in viewer
#ifndef HIGHLIGHT_STAYS_PROBLEM
// an attempt to clear highlighted item in the viewer: but of OCCT
XGUI_Tools::workshop(myWorkshop)->displayer()->clearSelected(true);
#endif
- updateObject(feature());
- Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
-
- aFilled = true;
-
- return aFilled;
+ return true;
}
//********************************************************************
}
//********************************************************************
-bool PartSet_WidgetFeaturePointSelector::setSelection(
- QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues,
- const bool theToValidate)
+bool PartSet_WidgetFeaturePointSelector::setSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
{
- // false is returned to do not emit focus out widget by selected sub-shape
- return false;
+ if (!thePrs.get() || !thePrs->object().get())
+ return false;
+
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ myPreviewObject = aSelection->getResult(thePrs);
+ GeomShapePtr aShape = aSelection->getShape(thePrs);
+ myExternalObjectMgr->getGeomSelection(thePrs, myPreviewObject, aShape, myWorkshop,
+ sketch(), true);
+ return fillFeature();
}
+//********************************************************************
void PartSet_WidgetFeaturePointSelector::setPreSelection(
- const std::shared_ptr<ModuleBase_ViewerPrs>& thePreSelected,
+ const ModuleBase_ViewerPrsPtr& thePreSelected,
ModuleBase_IViewWindow* theWnd,
QMouseEvent* theEvent)
{
// sub-segments in the viewer, secondly preselection of restart operation is processed by
// special reentrant message sent by the feature
}
+
+//********************************************************************
+void PartSet_WidgetFeaturePointSelector::getGeomSelection(const ModuleBase_ViewerPrsPtr& thePrs,
+ ObjectPtr& theObject, GeomShapePtr& theShape)
+{
+ ModuleBase_WidgetShapeSelector::getGeomSelection(thePrs, theObject, theShape);
+
+ myExternalObjectMgr->getGeomSelection(thePrs, theObject, theShape,
+ myWorkshop, sketch(), myIsInValidate);
+ myPreviewObject = theObject;
+}
+
+//********************************************************************
+void PartSet_WidgetFeaturePointSelector::restoreAttributeValue(const AttributePtr& theAttribute,
+ const bool theValid)
+{
+ ModuleBase_WidgetShapeSelector::restoreAttributeValue(theAttribute, theValid);
+ myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
+ myPreviewObject = ObjectPtr();
+}
#include <ModelAPI_CompositeFeature.h>
#include <ModuleBase_WidgetShapeSelector.h>
+#include <ModuleBase_ViewerPrs.h>
#include "PartSet.h"
#include "PartSet_MouseProcessor.h"
class Config_WidgetAPI;
class ModuleBase_IViewWindow;
class ModuleBase_ViewerPrs;
+class PartSet_ExternalObjectsMgr;
class GeomAPI_Pnt;
class GeomAPI_Pnt2d;
/// \return a boolean value
virtual bool isValidSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
- /// Activate or deactivate selection and selection filters
- /// \return true if the selection filter of the widget is activated in viewer context
- virtual void updateSelectionModesAndFilters(bool toActivate);
-
/// Set sketcher
/// \param theSketch a sketcher object
void setSketcher(CompositeFeaturePtr theSketch) { mySketch = theSketch; }
/// \param theEvent a mouse event
virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
- /// Set the given wrapped value to the current widget
- /// This value should be processed in the widget according to the needs
- /// The method is called by the current operation to process the operation preselection.
- /// It is redefined to fill attributes responsible for the sub selection
- /// \param theValues the wrapped selection values
- /// \param theToValidate a flag on validation of the values
- virtual bool setSelection(QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues,
- const bool theToValidate);
+
+ /// Fills the attribute with the value of the selected owner
+ /// \param thePrs a selected owner
+ virtual bool setSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs);
/// Fill preselection used in mouseReleased
- virtual void setPreSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& thePreSelected,
+ virtual void setPreSelection(const ModuleBase_ViewerPrsPtr& thePreSelected,
ModuleBase_IViewWindow* theWnd,
QMouseEvent* theEvent);
protected:
/// a shape. If the attribute do not uses the shape, it is empty
virtual QList<std::shared_ptr<ModuleBase_ViewerPrs>> getAttributeSelection() const;
-protected:
/// The methiod called when widget is activated
virtual void activateCustom();
+ /// Return an object and geom shape by the viewer presentation
+ /// \param thePrs a selection
+ /// \param theObject an output object
+ /// \param theShape a shape of the selection
+ virtual void getGeomSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs,
+ ObjectPtr& theObject, GeomShapePtr& theShape);
+
+ /// Creates a backup of the current values of the attribute
+ /// It should be realized in the specific widget because of different
+ /// parameters of the current attribute
+ /// \param theAttribute an attribute
+ /// \param theValid a boolean flag, if restore happens for valid parameters
+ void restoreAttributeValue(const AttributePtr& theAttribute, const bool theValid);
+
protected:
- bool fillFeature(const std::shared_ptr<ModuleBase_ViewerPrs>& theSelectedPrs,
- ModuleBase_IViewWindow* theWnd,
- QMouseEvent* theEvent);
+ bool fillFeature();
/// Pointer to a sketch
CompositeFeaturePtr mySketch;
bool myHasPreview;
std::shared_ptr<ModelAPI_Object> myPreviewObject;
std::shared_ptr<GeomAPI_Pnt2d> myPreviewPoint;
+ PartSet_ExternalObjectsMgr* myExternalObjectMgr; ///< reference to external objects manager
};
#endif
\ No newline at end of file
GeomShapePtr aShape = theValue->shape();
if (aShape.get() && !aShape->isNull()) {
Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
- double aX = 0, aY = 0;
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- if (getPoint2d(aView, aTDShape, aX, aY)) {
- fillRefAttribute(aX, aY, theValue);
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ fillRefAttribute(aPnt->x(), aPnt->y(), theValue);
isDone = true;
}
else if (aTDShape.ShapeType() == TopAbs_EDGE) {
GeomShapePtr aShape = aValue->shape();
if (aShape.get() && !aShape->isNull()) {
Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
- double aX = 0, aY = 0;
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- if (getPoint2d(aView, aTDShape, aX, aY)) {
- isDone = setPoint(aX, aY);
- setConstraintToPoint(aX, aY, aValue);
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ isDone = setPoint(aPnt->x(), aPnt->y());
+ setConstraintToPoint(aPnt->x(), aPnt->y(), aValue);
}
}
}
ModuleBase_ModelWidget::deactivate();
}
-bool PartSet_WidgetPoint2D::getPoint2d(const Handle(V3d_View)& theView,
- const TopoDS_Shape& theShape,
- double& theX, double& theY) const
-{
- if (!theShape.IsNull()) {
- if (theShape.ShapeType() == TopAbs_VERTEX) {
- const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
- if (!aVertex.IsNull()) {
- // A case when point is taken from existing vertex
- gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
- PartSet_Tools::convertTo2D(aPoint, mySketch, theView, theX, theY);
- return true;
- }
- }
- }
- return false;
-}
-
bool PartSet_WidgetPoint2D::setConstraintToPoint(double theClickedX, double theClickedY,
const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
{
}
}
if (anExternal) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
double aX = 0, aY = 0;
- if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+ if (aPnt) {
+ aX = aPnt->x();
+ aY = aPnt->y();
+ }
+ if (aPnt && isFeatureContainsPoint(myFeature, aX, aY)) {
// do not create a constraint to the point, which already used by the feature
// if the feature contains the point, focus is not switched
setPoint(aX, aY);
}
else {
- if (getPoint2d(aView, aShape, aX, aY))
+ if (aPnt)
setPoint(aX, aY);
else {
if (aShape.ShapeType() == TopAbs_EDGE) {
if (!anOrphanPoint)
emit vertexSelected(); // it stops the reentrant operation
+ myPreSelected.reset();
emit focusOutWidget(this);
}
}
if (!anExternal) {
- double aX = 0, aY = 0;
bool isProcessed = false;
- if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+ if (aPnt && isFeatureContainsPoint(myFeature, aPnt->x(), aPnt->y())) {
// when the point is selected, the coordinates of the point should be set into the attribute
// if the feature contains the point, focus is not switched
- setPoint(aX, aY);
+ setPoint(aPnt->x(), aPnt->y());
}
else {
+ double aX = 0, aY = 0;
bool anOrphanPoint = isOrphanPoint(aSelectedFeature, mySketch, aX, aY);
// do not set a coincidence constraint in the attribute if the feature contains a point
// with the same coordinates. It is important for line creation in order to do not set
// the same constraints for the same points, oterwise the result line has zero length.
bool isAuxiliaryFeature = false;
- if (getPoint2d(aView, aShape, aX, aY)) {
+ if (aPnt) {
+ aX = aPnt->x();
+ aY = aPnt->y();
setPoint(aX, aY);
setConstraintToPoint(aX, aY, aFirstValue);
}
updateObject(feature());
if (!anOrphanPoint && !anExternal && !isAuxiliaryFeature)
emit vertexSelected();
+ myPreSelected.reset();
emit focusOutWidget(this);
}
}
// external objects e.g. selection of trihedron axis when input end arc point
updateObject(feature());
- double aX = 0, aY = 0;
- if (getPoint2d(aView, aShape, aX, aY)) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+ if (aPnt) {
// do not create a constraint to the point, which already used by the feature
// if the feature contains the point, focus is not switched
- setPoint(aX, aY);
+ setPoint(aPnt->x(), aPnt->y());
}
emit vertexSelected(); // it stops the reentrant operation
+ myPreSelected.reset();
emit focusOutWidget(this);
}
}
if (!setPoint(aX, aY) || isFeatureContainsPoint(myFeature, aX, aY))
return;
+ myPreSelected.reset();
emit focusOutWidget(this);
}
}
{
myPreSelected = thePreSelected;
mouseReleased(theWnd, theEvent);
- myPreSelected = ModuleBase_ViewerPrsPtr();
}
void PartSet_WidgetPoint2D::getGeomSelection_(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue,
virtual void initializeValueByActivate();
private:
- /// Returns point 2d from selected vertex
- /// \param theView a view window
- /// \param theShape a vertex shape
- /// \param theX an output value of X coordinate
- /// \param theY an output value of Y coordinate
- bool getPoint2d(const Handle(V3d_View)& theView, const TopoDS_Shape& theShape,
- double& theX, double& theY) const;
-
/// Creates constrains of the clicked point
/// \param theClickedX the horizontal coordnate of the point
/// \param theClickedY the vertical coordnate of the point
/// \return true if succed
bool setConstraintToObject(const ObjectPtr& theObject);
+public:
/// Returns if the feature is an orphan point, circle or an arc. Returns true if it
/// has no a coincident to other lines. It processes point, circle and arc features
/// In circle an arc features, only centers are processed, for other points, it returns
const FeaturePtr& theSkipFeature,
const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+private:
/// Returns attribute reference if the key is defined in XML definition of this control
/// \return found attribute or null
std::shared_ptr<ModelAPI_AttributeRefAttr> attributeRefAttr() const;
GeomShapePtr anEmptyShape;
aSelAttr->setValue(anEmptyResult, anEmptyShape);
}
+ std::shared_ptr<GeomDataAPI_Point> anOrigin = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+ aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+ anOrigin->reset();
+ std::shared_ptr<GeomDataAPI_Dir> aNormal = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ aData->attribute(SketchPlugin_Sketch::NORM_ID()));
+ aNormal->reset();
+ std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
+ aDirX->reset();
}
bool PartSet_WidgetSketchLabel::setSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
void PartSet_WidgetSketchLabel::onShowPanel()
{
- if (mySizeOfViewWidget->isVisible()) {
+ //if (mySizeOfViewWidget->isVisible()) {
+ if (myStackWidget->currentIndex() == 0) {
DocumentPtr aDoc = feature()->document();
DocumentPtr aModDoc = ModelAPI_Session::get()->moduleDocument();
if (aModDoc == aDoc) {
myPartSetMessage->move(mapToGlobal(geometry().bottomLeft()));
myPartSetMessage->show();
}
- QPoint aPnt = mySizeOfView->mapToGlobal(mySizeOfView->geometry().center());
- mySizeMessage->move(aPnt);
- mySizeMessage->show();
+ if (mySizeOfViewWidget->isVisible()) {
+ QPoint aPnt = mySizeOfView->mapToGlobal(mySizeOfView->geometry().center());
+ mySizeMessage->move(aPnt);
+ mySizeMessage->show();
+ }
}
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="fr_FR">
+<context>
+ <name>PartSet_BSplineWidget</name>
+ <message>
+ <source>Poles and weights</source>
+ <translation>Poteaux et poids</translation>
+ </message>
+ <message>
+ <source>B-spline poles and weights</source>
+ <translation type="vanished">Poteaux et poids B-spline</translation>
+ </message>
+ <message>
+ <source>Pole %1</source>
+ <translation>Pôle %1</translation>
+ </message>
+ <message>
+ <source>Weight :</source>
+ <translation>Poids :</translation>
+ </message>
+ <message>
+ <source>Add a new pole after the current</source>
+ <translation>Ajouter un nouveau pôle après le courant</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+</context>
<context>
<name>PartSet_MenuMgr</name>
<message>
<source>Detach %1</source>
<translation>Détachez %1</translation>
</message>
+ <message>
+ <source>Load all parts</source>
+ <translation>Charger toutes les parties</translation>
+ </message>
+</context>
+<context>
+ <name>PartSet_WidgetBSplinePoints</name>
+ <message>
+ <source>Pole %1</source>
+ <translation>Pôle %1</translation>
+ </message>
+ <message>
+ <source>Create control polygon</source>
+ <translation type="vanished"> Créer un polygone de contrôle</translation>
+ </message>
+ <message>
+ <source>Specify if the control polygon should be created</source>
+ <translation type="vanished">Spécifiez si le polygone de contrôle doit être créé</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
</context>
<context>
<name>PartSet_WidgetPoint2D</name>
</message>
<message>
<source>Show remaining DoFs</source>
- <translation type="unfinished"></translation>
+ <translation>Afficher le reste DoFs</translation>
+ </message>
+ <message>
+ <source>The Sketch is created in PartSet.
+It will be necessary to create a Part in order to use this sketch for body creation</source>
+ <translation>L'esquisse est créée dans PartSet.
+Il sera nécessaire de créer une pièce afin d'utiliser cette esquisse pour la création du corps</translation>
+ </message>
+ <message>
+ <source>A size of Sketch view can be defined here.</source>
+ <translation>Une taille de vue Esquisse peut être définie ici.</translation>
</message>
</context>
<context>
from FeaturesAPI import addFusionFaces
from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle
from FeaturesAPI import addRemoveResults
+from FeaturesAPI import addCopy, addImportResult
+from FeaturesAPI import addDefeaturing
#include <QMenu>
#include <QToolBar>
-#define SALOME_PATCH_FOR_CTRL_WHEEL
+#if OCC_VERSION_HEX < 0x070400
+ #define SALOME_PATCH_FOR_CTRL_WHEEL
+#endif
extern "C" {
SHAPERGUI_EXPORT CAM_Module* createModule()
}
int aMenu = createMenu(tr("Inspection"), -1, -1, 30);
- int aSubMenu = createMenu(tr("Information"), aMenu);
+ int aSubMenu = createMenu(tr("Information"), aMenu, -1, -1, 0);
int aId = getNextCommandId();
myActionsList.append(aId);
myWhatIsAction->setData("INSPECTION_CMD");
createMenu(aId, aSubMenu, 0);
- QString aToolName = tr("Inspection tool");
+ QString aToolName = tr("Inspection");
int aTool = createTool(aToolName);
int aToolId = createTool(myWhatIsAction, aTool);
registerCommandToolbar(aToolName, aId);
#include <QMouseEvent>
#include <QContextMenuEvent>
-#define SALOME_PATCH_FOR_CTRL_WHEEL
+#if OCC_VERSION_HEX < 0x070400
+ #define SALOME_PATCH_FOR_CTRL_WHEEL
+#endif
SHAPERGUI_SalomeView::SHAPERGUI_SalomeView(OCCViewer_Viewer* theViewer)
: ModuleBase_IViewWindow(), myCurrentView(0)
aView3d->SetProj(theX, theY, theZ);
aView3d->SetTwist( theTwist );
aView3d->FitAll(0.01, false);
- aView3d->SetZSize(0.);
+ //aView3d->SetZSize(0.);
if (aView3d->Depth() < 0.1)
aView3d->DepthFitAll();
}
</message>
<message>
<source>Inspection tool</source>
- <translation>Outil d'inspection</translation>
+ <translation type="vanished">Outil d'inspection</translation>
</message>
<message>
<source>Edit toolbars of the module</source>
</message>
<message>
<source> (%1 commands)</source>
- <translation type="unfinished"></translation>
+ <translation> (%1 commandes)</translation>
</message>
</context>
</TS>
bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
{
bool aFoundAnyShape = false;
- TNaming_SameShapeIterator aLabIter(theValue, theAccess);
- for(; aLabIter.More(); aLabIter.Next()) {
- Handle(TNaming_NamedShape) aNS;
- if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
- if (aMustBeAtFinal && aNS != theFinal)
- continue; // looking for old at the same final label only
- TNaming_Evolution anEvolution = aNS->Evolution();
- if (anEvolution == TNaming_PRIMITIVE) {
- // check that this is not in the results already
- const TDF_Label aResult = aNS->Label();
- TDF_LabelList::Iterator aResIter(theResult);
- for(; aResIter.More(); aResIter.Next()) {
- if (aResIter.Value().IsEqual(aResult))
- break;
+ if (TNaming_Tool::HasLabel(theAccess, theValue)) {
+ TNaming_SameShapeIterator aLabIter(theValue, theAccess);
+ for(; aLabIter.More(); aLabIter.Next()) {
+ Handle(TNaming_NamedShape) aNS;
+ if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+ if (aMustBeAtFinal && aNS != theFinal)
+ continue; // looking for old at the same final label only
+ TNaming_Evolution anEvolution = aNS->Evolution();
+ if (anEvolution == TNaming_PRIMITIVE) {
+ // check that this is not in the results already
+ const TDF_Label aResult = aNS->Label();
+ TDF_LabelList::Iterator aResIter(theResult);
+ for(; aResIter.More(); aResIter.Next()) {
+ if (aResIter.Value().IsEqual(aResult))
+ break;
+ }
+ if (!aResIter.More()) // not found, so add this new
+ theResult.Append(aResult);
+ aFoundAnyShape = true;
}
- if (!aResIter.More()) // not found, so add this new
- theResult.Append(aResult);
- aFoundAnyShape = true;
- }
- if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
- for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
- if (aThisIter.NewShape().IsSame(theValue)) {
- // continue recursively, null NS means that any NS are ok
- findBases(theAccess, theFinal, aThisIter.OldShape(),
- false, theAdditionalDocument, theResult);
- aFoundAnyShape = true;
+ if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
+ for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
+ if (aThisIter.NewShape().IsSame(theValue)) {
+ // continue recursively, null NS means that any NS are ok
+ findBases(theAccess, theFinal, aThisIter.OldShape(),
+ false, theAdditionalDocument, theResult);
+ aFoundAnyShape = true;
+ }
}
}
}
SET(PROJECT_HEADERS
SketchAPI.h
SketchAPI_Arc.h
+ SketchAPI_BSpline.h
SketchAPI_Circle.h
SketchAPI_Constraint.h
SketchAPI_ConstraintAngle.h
SET(PROJECT_SOURCES
SketchAPI_Arc.cpp
+ SketchAPI_BSpline.cpp
SketchAPI_Circle.cpp
SketchAPI_Constraint.cpp
SketchAPI_ConstraintAngle.cpp
%include "doxyhelp.i"
// import other modules
+%import "GeomAPI.i"
%import "ModelAPI.i"
%import "ModelHighAPI.i"
%include "std_shared_ptr.i"
// function with named parameters
+%feature("kwargs") SketchAPI_BSpline::controlPoles;
+%feature("kwargs") SketchAPI_BSpline::controlPolygon;
%feature("kwargs") SketchAPI_Ellipse::construction;
%feature("kwargs") SketchAPI_EllipticArc::construction;
+%feature("kwargs") SketchAPI_Sketch::addSpline;
+%feature("kwargs") SketchAPI_Sketch::setAngle;
// shared pointers
%shared_ptr(SketchAPI_Arc)
%shared_ptr(SketchAPI_MacroEllipse)
%shared_ptr(SketchAPI_EllipticArc)
%shared_ptr(SketchAPI_MacroEllipticArc)
+%shared_ptr(SketchAPI_BSpline)
+%shared_ptr(SketchAPI_BSplinePeriodic)
%shared_ptr(SketchAPI_Constraint)
%shared_ptr(SketchAPI_ConstraintAngle)
%shared_ptr(SketchAPI_IntersectionPoint)
%template(InterfaceList) std::list<std::shared_ptr<ModelHighAPI_Interface> >;
%template(EntityList) std::list<std::shared_ptr<SketchAPI_SketchEntity> >;
%template(SketchPointList) std::list<std::shared_ptr<SketchAPI_Point> >;
+%template(GeomPnt2dList) std::list<std::shared_ptr<GeomAPI_Pnt2d> >;
// std::pair -> []
%template(PointRefAttrPair) std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>;
// fix compilarion error: 'res*' was not declared in this scope
%typemap(freearg) const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & {}
+
+%typemap(in) const std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> > & (std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> > temp) {
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+
+ std::list<PyObject*> temp_inputlist;
+ if (PySequence_Check(item)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size(item); ++i) {
+ PyObject * tmpItem = PySequence_GetItem(item, i);
+ temp_inputlist.push_back(tmpItem);
+ }
+ } else {
+ temp_inputlist.push_back(item);
+ }
+
+ std::shared_ptr<ModelAPI_Attribute> * temp_attribute = 0;
+ std::shared_ptr<ModelAPI_Object> * temp_object = 0;
+ std::shared_ptr<ModelHighAPI_Interface> * temp_interface = 0;
+ ModelHighAPI_Selection* temp_selection = 0;
+ std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>* temp_pair = 0;
+ std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+ ModelHighAPI_RefAttr temp_refattr;
+ int newmem = 0;
+ int clearmem = 0;
+
+ for (std::list<PyObject*>::iterator it = temp_inputlist.begin(); it != temp_inputlist.end(); ++it) {
+ PyObject* item = *it;
+
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_selection) {
+ temp_refattr = ModelHighAPI_RefAttr(std::shared_ptr<ModelAPI_Object>(temp_selection->resultSubShapePair().first));
+ if (newmem & SWIG_CAST_NEW_MEMORY) {
+ delete temp_selection;
+ }
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_attribute) {
+ temp_refattr = ModelHighAPI_RefAttr(*temp_attribute);
+ if (newmem & SWIG_CAST_NEW_MEMORY) {
+ delete temp_attribute;
+ }
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_object) {
+ temp_refattr = ModelHighAPI_RefAttr(*temp_object);
+ if (newmem & SWIG_CAST_NEW_MEMORY) {
+ delete temp_object;
+ }
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_interface) {
+ temp_refattr = ModelHighAPI_RefAttr(*temp_interface);
+ if (newmem & SWIG_CAST_NEW_MEMORY) {
+ delete temp_interface;
+ }
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_pair) {
+ temp_point = &temp_pair->first;
+ temp_refattr = temp_pair->second;
+ if (newmem & SWIG_CAST_NEW_MEMORY) {
+ delete temp_pair;
+ }
+ }
+ } else
+ if (PyTuple_Check(item)) {
+ if (PyTuple_Size(item) == 2) {
+ double x = (double)PyFloat_AsDouble(PySequence_GetItem(item, 0));
+ double y = (double)PyFloat_AsDouble(PySequence_GetItem(item, 1));
+ temp_point = new std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
+ clearmem = 1;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
+ return NULL;
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr<GeomAPI_Pnt2d> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ // fall through
+ } else
+ if (PyNumber_Check(item)) {
+ PyObject* item1 = *(++it);
+ if (PyNumber_Check(item1)) {
+ double x = (double)PyFloat_AsDouble(item);
+ double y = (double)PyFloat_AsDouble(item1);
+ temp_point = new std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
+ clearmem = 1;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
+ return NULL;
+ }
+ }
+ }
+
+ if (temp_point || !temp_refattr.isEmpty()) {
+ if (temp_point) {
+ temp.push_back(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>(*temp_point, temp_refattr));
+ } else {
+ temp.push_back(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>(std::shared_ptr<GeomAPI_Pnt2d>(), temp_refattr));
+ }
+ if (temp_point && ((newmem & SWIG_CAST_NEW_MEMORY) || clearmem)) {
+ delete temp_point;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+ $1 = &temp;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a tuple of lists.");
+ return NULL;
+ }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> >, const std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> >& {
+ int newmem = 0;
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+
+ std::list<PyObject*> temp_inputlist;
+ if (PySequence_Check(item)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size(item); ++i) {
+ PyObject * tmpItem = PySequence_GetItem(item, i);
+ temp_inputlist.push_back(tmpItem);
+ }
+ } else {
+ temp_inputlist.push_back(item);
+ }
+
+ std::shared_ptr<ModelAPI_Attribute> * temp_attribute = 0;
+ std::shared_ptr<ModelAPI_Object> * temp_object = 0;
+ std::shared_ptr<ModelHighAPI_Interface> * temp_interface = 0;
+ ModelHighAPI_Selection* temp_selection = 0;
+ std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>* temp_pair = 0;
+ std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+ ModelHighAPI_RefAttr temp_refattr;
+
+ $1 = 1;
+ for (std::list<PyObject*>::iterator it = temp_inputlist.begin(); it != temp_inputlist.end() && $1; ++it) {
+ PyObject* item = *it;
+
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_selection) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_attribute) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_object) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_interface) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_pair) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else
+ if (PyTuple_Check(item)) {
+ if (PyTuple_Size(item) == 2) {
+ if (PyNumber_Check(PySequence_GetItem(item, 0)) && PyNumber_Check(PySequence_GetItem(item, 1))) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else {
+ $1 = 0;
+ }
+ } else
+ if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr<GeomAPI_Pnt2d> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+ if (temp_point) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ } else
+ if (PyNumber_Check(item)) {
+ $1 = 1;
+ } else {
+ $1 = 0;
+ }
+ }
+ Py_DECREF(item);
+ }
+ } else {
+ $1 = 0;
+ }
+}
+
+// fix compilarion error: 'res*' was not declared in this scope
+%typemap(freearg) const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & {}
+
+
// all supported interfaces (the order is very important according dependencies: base class first)
%include "SketchAPI_SketchEntity.h"
%include "SketchAPI_Point.h"
%include "SketchAPI_MacroEllipse.h"
%include "SketchAPI_EllipticArc.h"
%include "SketchAPI_MacroEllipticArc.h"
+%include "SketchAPI_BSpline.h"
%include "SketchAPI_Projection.h"
%include "SketchAPI_Mirror.h"
%include "SketchAPI_Translation.h"
--- /dev/null
+// Copyright (C) 2019-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 "SketchAPI_BSpline.h"
+
+#include <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Integer.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <cmath>
+
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature> & theFeature)
+ : SketchAPI_SketchEntity(theFeature)
+{
+ initialize();
+}
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ bool theInitialize)
+ : SketchAPI_SketchEntity(theFeature)
+{
+ if (theInitialize)
+ initialize();
+}
+
+SketchAPI_BSpline::~SketchAPI_BSpline()
+{
+}
+
+void SketchAPI_BSpline::setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree,
+ const std::list<GeomPnt2dPtr>& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights)
+{
+ std::list<ModelHighAPI_Double> aWeights;
+ if (theWeights.size() <= 1) {
+ // prepare array of equal weights
+ aWeights.assign(thePoles.size(),
+ theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front());
+ }
+ else
+ aWeights = theWeights;
+
+ ModelHighAPI_Integer aDegree = theDegree;
+ std::list<ModelHighAPI_Double> aKnots;
+ std::list<ModelHighAPI_Integer> aMults;
+ getDefaultParameters(thePoles, aWeights, aDegree, aKnots, aMults);
+
+ setByParameters(aDegree, thePoles, aWeights, aKnots, aMults);
+}
+
+void SketchAPI_BSpline::setByParameters(const ModelHighAPI_Integer& theDegree,
+ const std::list<GeomPnt2dPtr>& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ const std::list<ModelHighAPI_Double>& theKnots,
+ const std::list<ModelHighAPI_Integer>& theMults)
+{
+ fillAttribute(theDegree, degree());
+
+ fillAttribute(thePoles, poles());
+ if (theWeights.size() <= 1) {
+ // prepare array of equal weights
+ std::list<ModelHighAPI_Double> aWeights(thePoles.size(),
+ theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front());
+ fillAttribute(aWeights, weights());
+ }
+ else
+ fillAttribute(theWeights, weights());
+
+ fillAttribute(theKnots, knots());
+ fillAttribute(theMults, multiplicities());
+
+ if (feature()->getKind() != SketchPlugin_BSplinePeriodic::ID())
+ setStartAndEndPoints();
+ execute();
+}
+
+void SketchAPI_BSpline::setStartAndEndPoints()
+{
+ fillAttribute(poles()->pnt(0), startPoint());
+ fillAttribute(poles()->pnt(poles()->size() - 1), endPoint());
+}
+
+void SketchAPI_BSpline::setByExternal(const ModelHighAPI_Selection & theExternal)
+{
+ fillAttribute(theExternal, external());
+ execute();
+}
+
+static CompositeFeaturePtr sketchForFeature(FeaturePtr theFeature)
+{
+ const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+ for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
+ if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID())
+ return std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
+ return CompositeFeaturePtr();
+}
+
+static void createInternalConstraint(const CompositeFeaturePtr& theSketch,
+ const AttributePoint2DPtr& thePoint,
+ const AttributePoint2DArrayPtr& thePoles,
+ const int thePoleIndex)
+{
+ FeaturePtr aConstraint = theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID());
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint);
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(thePoles);
+ aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B())
+ ->setValue(thePoleIndex);
+ aConstraint->execute();
+}
+
+static void createPole(const CompositeFeaturePtr& theSketch,
+ const FeaturePtr& theBSpline,
+ const AttributePoint2DArrayPtr& thePoles,
+ const int thePoleIndex,
+ const bool theAuxiliary,
+ std::list<FeaturePtr>& theEntities)
+{
+ GeomPnt2dPtr aPole = thePoles->pnt(thePoleIndex);
+
+ FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID());
+ AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+ aCoord->setValue(aPole);
+ aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+ aPointFeature->execute();
+
+ std::ostringstream aName;
+ aName << theBSpline->name() << "_" << thePoles->id() << "_" << thePoleIndex;
+ aPointFeature->data()->setName(aName.str());
+ aPointFeature->lastResult()->data()->setName(aName.str());
+
+ aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(theAuxiliary);
+
+ createInternalConstraint(theSketch, aCoord, thePoles, thePoleIndex);
+
+ theEntities.push_back(aPointFeature);
+}
+
+static void createSegment(const CompositeFeaturePtr& theSketch,
+ const FeaturePtr& theBSpline,
+ const AttributePoint2DArrayPtr& thePoles,
+ const int theStartPoleIndex,
+ const bool theAuxiliary,
+ std::list<FeaturePtr>& theEntities)
+{
+ int aEndPoleIndex = (theStartPoleIndex + 1) % thePoles->size();
+ GeomPnt2dPtr aStartPoint = thePoles->pnt(theStartPoleIndex);
+ GeomPnt2dPtr aEndPoint = thePoles->pnt(aEndPoleIndex);
+
+ FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID());
+ AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ aLineStart->setValue(aStartPoint);
+ AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+ aLineEnd->setValue(aEndPoint);
+ aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+ aLineFeature->execute();
+
+ std::ostringstream aName;
+ aName << theBSpline->name() << "_segment_" << theStartPoleIndex << "_" << aEndPoleIndex;
+ aLineFeature->data()->setName(aName.str());
+ aLineFeature->lastResult()->data()->setName(aName.str());
+
+ aLineFeature->boolean(SketchPlugin_Line::AUXILIARY_ID())->setValue(theAuxiliary);
+
+ createInternalConstraint(theSketch, aLineStart, thePoles, theStartPoleIndex);
+ createInternalConstraint(theSketch, aLineEnd, thePoles, aEndPoleIndex);
+
+ theEntities.push_back(aLineFeature);
+}
+
+static void toMapOfAuxIndices(const std::list<int>& theRegular,
+ const std::list<int>& theAuxiliary,
+ std::map<int, bool>& theIndices)
+{
+ for (auto it = theRegular.begin(); it != theRegular.end(); ++it)
+ theIndices[*it] = false;
+ for (auto it = theAuxiliary.begin(); it != theAuxiliary.end(); ++it)
+ theIndices[*it] = true;
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_BSpline::controlPoles(
+ const std::list<int>& regular,
+ const std::list<int>& auxiliary) const
+{
+ std::map<int, bool> anAux;
+ toMapOfAuxIndices(regular, auxiliary, anAux);
+
+ std::list<FeaturePtr> anEntities;
+
+ FeaturePtr aBSpline = feature();
+ CompositeFeaturePtr aSketch = sketchForFeature(aBSpline);
+ AttributePoint2DArrayPtr aPoles = poles();
+
+ for (auto it = anAux.begin(); it != anAux.end(); ++it)
+ createPole(aSketch, aBSpline, aPoles, it->first, it->second, anEntities);
+
+ return SketchAPI_SketchEntity::wrap(anEntities);
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_BSpline::controlPolygon(
+ const std::list<int>& regular,
+ const std::list<int>& auxiliary) const
+{
+ std::map<int, bool> anAux;
+ toMapOfAuxIndices(regular, auxiliary, anAux);
+
+ std::list<FeaturePtr> anEntities;
+
+ FeaturePtr aBSpline = feature();
+ CompositeFeaturePtr aSketch = sketchForFeature(aBSpline);
+ AttributePoint2DArrayPtr aPoles = poles();
+
+ for (auto it = anAux.begin(); it != anAux.end(); ++it)
+ createSegment(aSketch, aBSpline, aPoles, it->first, it->second, anEntities);
+
+ return SketchAPI_SketchEntity::wrap(anEntities);
+}
+
+
+void SketchAPI_BSpline::getDefaultParameters(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ ModelHighAPI_Integer& theDegree,
+ std::list<ModelHighAPI_Double>& theKnots,
+ std::list<ModelHighAPI_Integer>& theMults) const
+{
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+ try {
+ std::list<double> aWeights;
+ for (std::list<ModelHighAPI_Double>::const_iterator it = theWeights.begin();
+ it != theWeights.end(); ++it)
+ aWeights.push_back(it->value());
+
+ bool isPeriodic = feature()->getKind() == SketchPlugin_BSplinePeriodic::ID();
+ if (theDegree.intValue() < 0)
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(thePoles, aWeights, isPeriodic));
+ else {
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(theDegree.intValue(), thePoles, aWeights,
+ std::list<double>(), std::list<int>(), isPeriodic));
+ }
+ }
+ catch (...) {
+ // cannot build a B-spline curve
+ return;
+ }
+
+ theDegree = aBSplineCurve->degree();
+ std::list<double> aKnots = aBSplineCurve->knots();
+ std::list<int> aMults = aBSplineCurve->mults();
+ theKnots.assign(aKnots.begin(), aKnots.end());
+ theMults.assign(aMults.begin(), aMults.end());
+}
+
+void SketchAPI_BSpline::checkDefaultParameters(bool& isDefaultDegree,
+ bool& isDefaultWeights,
+ bool& isDefaultKnotsMults) const
+{
+ static const double TOLERANCE = 1.e-7;
+
+ AttributePoint2DArrayPtr aPolesAttr = poles();
+ AttributeDoubleArrayPtr aWeightsAttr = weights();
+ AttributeDoubleArrayPtr aKnotsAttr = knots();
+ AttributeIntArrayPtr aMultsAttr = multiplicities();
+
+ std::list<GeomPnt2dPtr> aPoles;
+ std::list<ModelHighAPI_Double> aWeights;
+ isDefaultWeights = true;
+ for (int anIndex = 0; anIndex < aPolesAttr->size(); ++anIndex) {
+ aPoles.push_back(aPolesAttr->pnt(anIndex));
+ double aCurWeight = aWeightsAttr->value(anIndex);
+ isDefaultWeights = isDefaultWeights && fabs(aCurWeight - 1.0) < TOLERANCE;
+ aWeights.push_back(aCurWeight);
+ }
+
+ ModelHighAPI_Integer aDegree(-1);
+ std::list<ModelHighAPI_Double> aKnots;
+ std::list<ModelHighAPI_Integer> aMults;
+ getDefaultParameters(aPoles, aWeights, aDegree, aKnots, aMults);
+ isDefaultDegree = aDegree.intValue() == degree()->value();
+ if (!isDefaultDegree) {
+ // recalculate knots and multiplicities with the actual degree
+ aDegree = degree()->value();
+ getDefaultParameters(aPoles, aWeights, aDegree, aKnots, aMults);
+ }
+
+ isDefaultKnotsMults = aKnotsAttr->size() == (int)aKnots.size()
+ && aMultsAttr->size() == (int)aMults.size();
+ if (isDefaultKnotsMults) {
+ std::list<ModelHighAPI_Double>::iterator anIt = aKnots.begin();
+ for (int anIndex = 0; isDefaultKnotsMults && anIt != aKnots.end(); ++anIt, ++anIndex)
+ isDefaultKnotsMults = fabs(anIt->value() - aKnotsAttr->value(anIndex)) < TOLERANCE;
+ }
+ if (isDefaultKnotsMults) {
+ std::list<ModelHighAPI_Integer>::iterator anIt = aMults.begin();
+ for (int anIndex = 0; isDefaultKnotsMults && anIt != aMults.end(); ++anIt, ++anIndex)
+ isDefaultKnotsMults = anIt->intValue() == aMultsAttr->value(anIndex);
+ }
+
+ isDefaultDegree = isDefaultDegree && isDefaultKnotsMults;
+ isDefaultWeights = isDefaultWeights && isDefaultKnotsMults;
+}
+
+
+static void bsplineAuxiliaryFeature(const AttributeRefAttrPtr& theReference,
+ FeaturePtr& thePoint,
+ FeaturePtr& theSegment)
+{
+ ObjectPtr anAuxObject;
+ if (theReference->isObject())
+ anAuxObject = theReference->object();
+ else
+ anAuxObject = theReference->attr()->owner();
+
+ FeaturePtr anAuxFeature = ModelAPI_Feature::feature(anAuxObject);
+ if (anAuxFeature->getKind() == SketchPlugin_Point::ID())
+ thePoint = anAuxFeature;
+ else if (anAuxFeature->getKind() == SketchPlugin_Line::ID() &&
+ theReference->attr()->id() == SketchPlugin_Line::START_ID()) {
+ // process only coincidence with start point
+ theSegment = anAuxFeature;
+ }
+}
+
+static void collectAuxiliaryFeatures(FeaturePtr theBSpline,
+ std::map<int, FeaturePtr>& thePoints,
+ std::map<int, FeaturePtr>& theSegments)
+{
+ const std::set<AttributePtr>& aRefs = theBSpline->data()->refsToMe();
+ for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+ aRefIt != aRefs.end(); ++aRefIt) {
+ FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+ if (anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+ // process internal constraints only
+ AttributeRefAttrPtr aRefAttrA = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A());
+ AttributeRefAttrPtr aRefAttrB = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B());
+ AttributePtr anAttrA = aRefAttrA->attr();
+ AttributePtr anAttrB = aRefAttrB->attr();
+
+ AttributeIntegerPtr aPoleIndex;
+ FeaturePtr aPoint, aLine;
+ if (anAttrA && anAttrA->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
+ aPoleIndex = anOwner->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ bsplineAuxiliaryFeature(aRefAttrB, aPoint, aLine);
+ }
+ else if (anAttrB && anAttrB->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
+ aPoleIndex = anOwner->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ bsplineAuxiliaryFeature(aRefAttrA, aPoint, aLine);
+ }
+
+ if (aPoint)
+ thePoints[aPoleIndex->value()] = aPoint;
+ else if (aLine)
+ theSegments[aPoleIndex->value()] = aLine;
+ }
+ }
+}
+
+void SketchAPI_BSpline::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ if (isCopy())
+ return; // no need to dump copied feature
+
+ FeaturePtr aBase = feature();
+ const std::string& aSketchName = theDumper.parentName(aBase);
+
+ AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
+ if (anExternal->context()) {
+ // B-spline is external
+ theDumper << aBase << " = " << aSketchName << ".addSpline(" << anExternal << ")" << std::endl;
+ } else {
+ // check if some B-spline parameters are default and should not be dumped
+ bool isDefaultDegree, isDefaultWeights, isDefaultKnotsMults;
+ checkDefaultParameters(isDefaultDegree, isDefaultWeights, isDefaultKnotsMults);
+
+ theDumper << aBase << " = " << aSketchName << ".addSpline(";
+ if (!isDefaultDegree)
+ theDumper << "degree = " << degree() << ", ";
+ theDumper << "poles = " << poles();
+ if (!isDefaultWeights)
+ theDumper << ", weights = " << weights();
+ if (!isDefaultKnotsMults)
+ theDumper << ", knots = " << knots() << ", multiplicities = " << multiplicities();
+ if (aBase->getKind() == SketchPlugin_BSplinePeriodic::ID())
+ theDumper << ", periodic = True";
+ theDumper << ")" << std::endl;
+ }
+ // dump "auxiliary" flag if necessary
+ SketchAPI_SketchEntity::dump(theDumper);
+
+ // dump control polygon
+ std::map<int, FeaturePtr> anAuxPoles, anAuxSegments;
+ collectAuxiliaryFeatures(aBase, anAuxPoles, anAuxSegments);
+
+ if (!anAuxPoles.empty())
+ dumpControlPolygon(theDumper, aBase, "controlPoles", anAuxPoles);
+ if (!anAuxSegments.empty())
+ dumpControlPolygon(theDumper, aBase, "controlPolygon", anAuxSegments);
+}
+
+static void dumpList(ModelHighAPI_Dumper& theDumper,
+ const std::string& theAttrName,
+ const std::set<int>& theIndices)
+{
+ theDumper << theAttrName << " = [";
+ std::set<int>::const_iterator it = theIndices.begin();
+ theDumper << *it;
+ for (++it; it != theIndices.end(); ++it)
+ theDumper << ", " << *it;
+ theDumper << "]";
+}
+
+void SketchAPI_BSpline::dumpControlPolygon(
+ ModelHighAPI_Dumper& theDumper,
+ const FeaturePtr& theBSpline,
+ const std::string& theMethod,
+ const std::map<int, FeaturePtr>& theAuxFeatures) const
+{
+ theDumper << "[";
+ bool isFirst = true;
+ // dump features and split them to auxiliary and regular
+ std::set<int> aRegular, anAuxiliary;
+ for (std::map<int, FeaturePtr>::const_iterator it = theAuxFeatures.begin();
+ it != theAuxFeatures.end(); ++it) {
+ if (!isFirst)
+ theDumper << ", ";
+ theDumper << theDumper.name(it->second, false);
+ theDumper.doNotDumpFeature(it->second);
+ isFirst = false;
+
+ if (it->second->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value())
+ anAuxiliary.insert(it->first);
+ else
+ aRegular.insert(it->first);
+ }
+ theDumper << "] = " << theDumper.name(theBSpline) << "." << theMethod << "(";
+ if (!aRegular.empty()) {
+ dumpList(theDumper, "regular", aRegular);
+ if (!anAuxiliary.empty())
+ theDumper << ", ";
+ }
+ if (!anAuxiliary.empty())
+ dumpList(theDumper, "auxiliary", anAuxiliary);
+ theDumper << ")" << std::endl;
+}
+
+static void setCoordinates(const FeaturePtr& theFeature,
+ const std::string& theAttrName,
+ const GeomPnt2dPtr& theCoordinates)
+{
+ AttributePoint2DPtr aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(theAttrName));
+ aPoint->setValue(theCoordinates);
+}
+
+bool SketchAPI_BSpline::insertPole(const int theIndex,
+ const GeomPnt2dPtr& theCoordinates,
+ const ModelHighAPI_Double& theWeight)
+{
+ std::ostringstream anActionName;
+ anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << theIndex;
+ bool isOk = feature()->customAction(anActionName.str());
+ if (isOk) {
+ int anIndex = theIndex + 1;
+ if (feature()->getKind() == SketchPlugin_BSpline::ID() && anIndex + 1 >= poles()->size())
+ anIndex = poles()->size() - 2;
+ // initialize coordinates and weight of new pole
+ poles()->setPnt(anIndex, theCoordinates);
+ weights()->setValue(anIndex, theWeight.value());
+
+ // update coordinates of points of control polygon
+ std::map<int, FeaturePtr> aPoints, aLines;
+ collectAuxiliaryFeatures(feature(), aPoints, aLines);
+ std::map<int, FeaturePtr>::iterator aFound = aPoints.find(anIndex);
+ if (aFound != aPoints.end())
+ setCoordinates(aFound->second, SketchPlugin_Point::COORD_ID(), theCoordinates);
+ aFound = aLines.find(anIndex);
+ if (aFound != aLines.end())
+ setCoordinates(aFound->second, SketchPlugin_Line::START_ID(), theCoordinates);
+ aFound = aLines.find(anIndex - 1);
+ if (aFound != aLines.end())
+ setCoordinates(aFound->second, SketchPlugin_Line::END_ID(), theCoordinates);
+ }
+ return isOk;
+}
+
+
+
+// =================================================================================================
+SketchAPI_BSplinePeriodic::SketchAPI_BSplinePeriodic(const FeaturePtr& theFeature)
+ : SketchAPI_BSpline(theFeature, false)
+{
+ initialize();
+}
--- /dev/null
+// Copyright (C) 2019-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 SketchAPI_BSpline_H_
+#define SketchAPI_BSpline_H_
+
+#include "SketchAPI.h"
+#include "SketchAPI_SketchEntity.h"
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Integer.h>
+
+class ModelHighAPI_Selection;
+
+/// \class SketchAPI_BSpline
+/// \ingroup CPPHighAPI
+/// \brief Interface for BSpline feature.
+class SketchAPI_BSpline : public SketchAPI_SketchEntity
+{
+public:
+ /// Constructor without values.
+ SKETCHAPI_EXPORT
+ explicit SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Destructor.
+ SKETCHAPI_EXPORT
+ virtual ~SketchAPI_BSpline();
+
+ INTERFACE_8(SketchPlugin_BSpline::ID(),
+ poles, SketchPlugin_BSplineBase::POLES_ID(),
+ GeomDataAPI_Point2DArray, /** B-spline poles */,
+ weights, SketchPlugin_BSplineBase::WEIGHTS_ID(),
+ ModelAPI_AttributeDoubleArray, /** B-spline weights */,
+ knots, SketchPlugin_BSplineBase::KNOTS_ID(),
+ ModelAPI_AttributeDoubleArray, /** B-spline knots */,
+ multiplicities, SketchPlugin_BSplineBase::MULTS_ID(),
+ ModelAPI_AttributeIntArray, /** Knots multiplicities */,
+ degree, SketchPlugin_BSplineBase::DEGREE_ID(),
+ ModelAPI_AttributeInteger, /** B-spline degree */,
+ startPoint, SketchPlugin_BSpline::START_ID(),
+ GeomDataAPI_Point2D, /** First pole of B-spline */,
+ endPoint, SketchPlugin_BSpline::END_ID(),
+ GeomDataAPI_Point2D, /** Last pole of B-spline */,
+ external, SketchPlugin_BSplineBase::EXTERNAL_ID(),
+ ModelAPI_AttributeSelection, /** External */)
+
+ /// Set by poles and weights.
+ SKETCHAPI_EXPORT
+ void setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights);
+
+ /// Initialize by full set of B-spline parameters.
+ SKETCHAPI_EXPORT
+ void setByParameters(const ModelHighAPI_Integer& theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ const std::list<ModelHighAPI_Double>& theKnots,
+ const std::list<ModelHighAPI_Integer>& theMults);
+
+ /// Set by external.
+ SKETCHAPI_EXPORT
+ void setByExternal(const ModelHighAPI_Selection& theExternal);
+
+ /// Generate list of construction points coincident with B-spline poles
+ SKETCHAPI_EXPORT
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > controlPoles(
+ const std::list<int>& regular = std::list<int>(),
+ const std::list<int>& auxiliary = std::list<int>()) const;
+
+ /// Generate control polygon for B-spline curve
+ SKETCHAPI_EXPORT
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > controlPolygon(
+ const std::list<int>& regular = std::list<int>(),
+ const std::list<int>& auxiliary = std::list<int>()) const;
+
+ /// Insert new pole after the pole with the given index
+ SKETCHAPI_EXPORT
+ bool insertPole(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theCoordinates,
+ const ModelHighAPI_Double& theWeight = ModelHighAPI_Double(1.0));
+
+ /// Dump wrapped feature
+ SKETCHAPI_EXPORT
+ virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+protected:
+ SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature, bool theInitialize);
+
+private:
+ /// Initialize start and end points of B-spline and apply internal coincidence
+ /// constraint to keep them on the corresponding pole.
+ void setStartAndEndPoints();
+
+ /// Compute default B-spline parameters (degree, knots and multiplicities)
+ /// basing on hte given poles and weights
+ void getDefaultParameters(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ ModelHighAPI_Integer& theDegree,
+ std::list<ModelHighAPI_Double>& theKnots,
+ std::list<ModelHighAPI_Integer>& theMults) const;
+
+ /// Check what parameters of B-spline are default
+ void checkDefaultParameters(bool& isDefaultDegree,
+ bool& isDefaultWeights,
+ bool& isDefaultKnotsMults) const;
+
+ void dumpControlPolygon(ModelHighAPI_Dumper& theDumper,
+ const FeaturePtr& theBSpline,
+ const std::string& theMethod,
+ const std::map<int, FeaturePtr>& theAuxFeatures) const;
+};
+
+/// Pointer on B-spline object.
+typedef std::shared_ptr<SketchAPI_BSpline> BSplinePtr;
+
+
+
+/// \class SketchAPI_BSplinePeriodic
+/// \ingroup CPPHighAPI
+/// \brief Interface for BSplinePeriodic feature.
+class SketchAPI_BSplinePeriodic : public SketchAPI_BSpline
+{
+public:
+ /// Constructor without values.
+ SKETCHAPI_EXPORT
+ explicit SketchAPI_BSplinePeriodic(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Destructor.
+ SKETCHAPI_EXPORT
+ virtual ~SketchAPI_BSplinePeriodic() {}
+
+ static std::string ID() { return SketchPlugin_BSplinePeriodic::ID(); }
+ virtual std::string getID() { return SketchPlugin_BSplinePeriodic::ID(); }
+};
+
+#endif // SketchAPI_BSpline_H_
return DUMMY;
}
-static std::string angleTypeToString(int theAngleType)
-{
- switch (theAngleType) {
- case SketcherPrs_Tools::ANGLE_COMPLEMENTARY:
- return std::string("Complementary");
- case SketcherPrs_Tools::ANGLE_BACKWARD:
- return std::string("Backward");
- default:
- break;
- }
- return std::string();
-}
-
bool SketchAPI_Constraint::areAllAttributesDumped(ModelHighAPI_Dumper& theDumper) const
{
bool areAttributesDumped = true;
std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(
aStartA->pnt(), aEndA->pnt(), aStartB->pnt(), aEndB->pnt()));
- theAngleDirect = anAng->angleDegree();
+ theAngleDirect = fabs(anAng->angleDegree());
+ theAngleComplementary = 180.0 - theAngleDirect;
theAngleBackward = 360.0 - theAngleDirect;
-
- if (theAngleDirect > 180.0)
- theAngleComplementary = theAngleDirect - 180.0;
- else
- theAngleComplementary = 180.0 - theAngleDirect;
}
static std::string angleTypeToString(FeaturePtr theFeature)
{
static const double TOLERANCE = 1.e-7;
+ static const std::string THE_ANGLE_DIRECT("Direct");
+ static const std::string THE_ANGLE_SUPPLEMENTARY("Supplementary");
+ static const std::string THE_ANGLE_BACKWARD("Backward");
+
double anAngleDirect, anAngleComplmentary, anAngleBackward;
calculatePossibleValuesOfAngle(theFeature, anAngleDirect, anAngleComplmentary, anAngleBackward);
// find the minimal difference
std::string aType;
if (isDirect && aDirectDiff < TOLERANCE) {
- // Nothing to do.
- // This case is empty and going the first to check the direct angle before the others.
+ aType = THE_ANGLE_DIRECT;
}
else if (isComplementary && aComplementaryDiff < TOLERANCE)
- aType = "Complementary";
+ aType = THE_ANGLE_SUPPLEMENTARY;
else if (isBackward && aBackwardDiff < TOLERANCE)
- aType = "Backward";
+ aType = THE_ANGLE_BACKWARD;
else {
if (aComplementaryDiff < aDirectDiff && aComplementaryDiff < aBackwardDiff)
- aType = "Complementary";
+ aType = THE_ANGLE_SUPPLEMENTARY;
else if (aBackwardDiff < aDirectDiff && aBackwardDiff < aComplementaryDiff)
- aType = "Backward";
+ aType = THE_ANGLE_BACKWARD;
}
return aType;
}
// calculate angle value as it was just applied to the attributes
FeaturePtr aBase = feature();
- std::string aSetterSuffix = angleTypeToString(aBase);
const std::string& aSketchName = theDumper.parentName(aBase);
- theDumper << aBase << " = " << aSketchName << "." << "setAngle" << aSetterSuffix << "(";
+ theDumper << aBase << " = " << aSketchName << "." << "setAngle(";
bool isFirstAttr = true;
for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
if (aValueAttr && aValueAttr->isInitialized())
theDumper << ", " << aValueAttr;
- theDumper << ")" << std::endl;
+ std::string aType = angleTypeToString(aBase);
+ theDumper << ", type = \"" << aType << "\")" << std::endl;
}
#include "SketchAPI_Projection.h"
#include <SketchPlugin_Line.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
#include <SketchPlugin_Point.h>
#include <SketchAPI_Arc.h>
+#include <SketchAPI_BSpline.h>
#include <SketchAPI_Circle.h>
#include <SketchAPI_Ellipse.h>
#include <SketchAPI_EllipticArc.h>
anEntity.reset(new SketchAPI_Ellipse(aProjectedFeature));
else if (aProjectedFeature->getKind() == SketchPlugin_EllipticArc::ID())
anEntity.reset(new SketchAPI_EllipticArc(aProjectedFeature));
+ else if (aProjectedFeature->getKind() == SketchPlugin_BSpline::ID())
+ anEntity.reset(new SketchAPI_BSpline(aProjectedFeature));
+ else if (aProjectedFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())
+ anEntity.reset(new SketchAPI_BSplinePeriodic(aProjectedFeature));
else if (aProjectedFeature->getKind() == SketchPlugin_Point::ID())
anEntity.reset(new SketchAPI_Point(aProjectedFeature));
#include <SketchPlugin_Split.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
+#include <SketchPlugin_MacroBSpline.h>
#include <SketcherPrs_Tools.h>
//--------------------------------------------------------------------------------------
#include <ModelAPI_Events.h>
#include <ModelHighAPI_Tools.h>
//--------------------------------------------------------------------------------------
#include "SketchAPI_Arc.h"
+#include "SketchAPI_BSpline.h"
#include "SketchAPI_Circle.h"
#include "SketchAPI_Ellipse.h"
#include "SketchAPI_EllipticArc.h"
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_XY.h>
#include <GeomAlgoAPI_SketchBuilder.h>
+
+#include <algorithm>
#include <cmath>
//--------------------------------------------------------------------------------------
SketchAPI_Sketch::SketchAPI_Sketch(
}
std::shared_ptr<SketchAPI_MacroEllipse> SketchAPI_Sketch::addEllipse(
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint1,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint2,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePassedPoint,
+ const PointOrReference& thePoint1,
+ const PointOrReference& thePoint2,
+ const PointOrReference& thePassedPoint,
bool isPoint1Center)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
}
std::shared_ptr<SketchAPI_MacroEllipticArc> SketchAPI_Sketch::addEllipticArc(
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theStartPoint,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theEndPoint,
+ const PointOrReference& theCenter,
+ const PointOrReference& theMajorAxisPoint,
+ const PointOrReference& theStartPoint,
+ const PointOrReference& theEndPoint,
bool theInversed)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature, theExternalName));
}
+//--------------------------------------------------------------------------------------
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(
+ const ModelHighAPI_Selection & external,
+ const int degree,
+ const std::list<PointOrReference>& poles,
+ const std::list<ModelHighAPI_Double>& weights,
+ const std::list<ModelHighAPI_Double>& knots,
+ const std::list<ModelHighAPI_Integer>& multiplicities,
+ const bool periodic)
+{
+ // split poles and references to other shapes
+ bool hasReference = false;
+ std::list<GeomPnt2dPtr> aPoints;
+ std::list<ModelHighAPI_RefAttr> aReferences;
+ for (std::list<PointOrReference>::const_iterator it = poles.begin(); it != poles.end(); ++it) {
+ aPoints.push_back(it->first);
+ aReferences.push_back(it->second);
+ if (!it->second.isEmpty())
+ hasReference = true;
+ }
+
+ BSplinePtr aBSpline;
+ CompositeFeaturePtr aSketch = compositeFeature();
+ if (hasReference) {
+ // use macro-feature to create coincidences to referred features
+ FeaturePtr aMacroFeature = aSketch->addFeature(
+ periodic ? SketchPlugin_MacroBSplinePeriodic::ID() : SketchPlugin_MacroBSpline::ID());
+ AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aMacroFeature->attribute(SketchPlugin_MacroBSpline::POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsAttr =
+ aMacroFeature->data()->realArray(SketchPlugin_MacroBSpline::WEIGHTS_ID());
+ AttributeRefAttrListPtr aPolesRefAttr =
+ aMacroFeature->data()->refattrlist(SketchPlugin_MacroBSpline::REF_POLES_ID());
+ // always generate a control polygon to apply coincidences correctly
+ aMacroFeature->boolean(SketchPlugin_MacroBSpline::CONTROL_POLYGON_ID())->setValue(true);
+ // initialize B-spline attributes
+ fillAttribute(aPoints, aPolesAttr);
+ if (weights.empty())
+ fillAttribute(std::list<ModelHighAPI_Double>(poles.size(), 1.0), aWeightsAttr);
+ else
+ fillAttribute(weights, aWeightsAttr);
+ fillAttribute(aReferences, aPolesRefAttr);
+ apply(); // to kill macro-feature
+
+ // find created B-spline feature
+ const std::string& aKindToFind =
+ periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID();
+ int aNbSubs = aSketch->numberOfSubs();
+ for (int anIndex = aNbSubs - 1; anIndex >= 0; --anIndex) {
+ FeaturePtr aFeature = aSketch->subFeature(anIndex);
+ if (aFeature->getKind() == aKindToFind) {
+ aBSpline.reset(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
+ : new SketchAPI_BSpline(aFeature));
+ aBSpline->execute();
+ break;
+ }
+ }
+ }
+ else {
+ // compute B-spline by parameters
+ FeaturePtr aFeature = aSketch->addFeature(
+ periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ aBSpline.reset(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
+ : new SketchAPI_BSpline(aFeature));
+ if (external.variantType() != ModelHighAPI_Selection::VT_Empty)
+ aBSpline->setByExternal(external);
+ else if (knots.empty() || multiplicities.empty())
+ aBSpline->setByDegreePolesAndWeights(degree, aPoints, weights);
+ else
+ aBSpline->setByParameters(degree, aPoints, weights, knots, multiplicities);
+ }
+ return aBSpline;
+}
+
//--------------------------------------------------------------------------------------
std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
const ModelHighAPI_Selection & theExternalFeature,
std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setAngle(
const ModelHighAPI_RefAttr & theLine1,
const ModelHighAPI_RefAttr & theLine2,
- const ModelHighAPI_Double & theValue)
+ const ModelHighAPI_Double & theValue,
+ const std::string& theType)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID());
- fillAttribute(SketcherPrs_Tools::ANGLE_DIRECT,
- aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
- // fill the value before llines to avoid calculation of angle value by the Angle feature
+
+ const int aVersion = theType.empty() ? SketchPlugin_ConstraintAngle::THE_VERSION_0
+ : SketchPlugin_ConstraintAngle::THE_VERSION_1;
+ fillAttribute(aVersion, aFeature->integer(SketchPlugin_ConstraintAngle::VERSION_ID()));
+
+ int aType = (int)SketcherPrs_Tools::ANGLE_DIRECT;
+ fillAttribute(aType, aFeature->integer(SketchPlugin_ConstraintAngle::PREV_TYPE_ID()));
+ fillAttribute(aType, aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
+
+ if (aVersion == SketchPlugin_ConstraintAngle::THE_VERSION_0)
+ fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
+
fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
- fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
+
+ if (aVersion == SketchPlugin_ConstraintAngle::THE_VERSION_1) {
+ std::string aTypeLC = theType;
+ std::transform(aTypeLC.begin(), aTypeLC.end(), aTypeLC.begin(), ::tolower);
+ if (aTypeLC == "supplementary")
+ aType = (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY;
+ else if (aTypeLC == "backward")
+ aType = (int)SketcherPrs_Tools::ANGLE_BACKWARD;
+
+ fillAttribute(aType, aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
+ fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
+ }
+
aFeature->execute();
return InterfacePtr(new ModelHighAPI_Interface(aFeature));
}
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID());
+ fillAttribute(SketchPlugin_ConstraintAngle::THE_VERSION_0,
+ aFeature->integer(SketchPlugin_ConstraintAngle::VERSION_ID()));
fillAttribute(SketcherPrs_Tools::ANGLE_COMPLEMENTARY,
aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
+ fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
- fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
aFeature->execute();
return InterfacePtr(new ModelHighAPI_Interface(aFeature));
}
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID());
+ fillAttribute(SketchPlugin_ConstraintAngle::THE_VERSION_0,
+ aFeature->integer(SketchPlugin_ConstraintAngle::VERSION_ID()));
fillAttribute(SketcherPrs_Tools::ANGLE_BACKWARD,
aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
+ fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
- fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
aFeature->execute();
return InterfacePtr(new ModelHighAPI_Interface(aFeature));
}
return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
}
-static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnBSpline(const FeaturePtr& theFeature,
+ SketchAPI_Sketch* theSketch)
+{
+ GeomAPI_Edge anEdge(theFeature->lastResult()->shape());
+ GeomPointPtr aMiddle = anEdge.middlePoint();
+ return theSketch->to2D(aMiddle);
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject,
+ SketchAPI_Sketch* theSketch)
{
std::shared_ptr<GeomAPI_Pnt2d> aMiddlePoint;
FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
aMiddlePoint = pointOnEllipse(aFeature);
else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
aMiddlePoint = pointOnEllipse(aFeature, false);
+ else if (aFeatureKind == SketchPlugin_BSpline::ID() ||
+ aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
+ aMiddlePoint = middlePointOnBSpline(aFeature, theSketch);
}
return aMiddlePoint;
}
if (aMessage->movedAttribute())
anOriginalPosition = pointCoordinates(aMessage->movedAttribute());
else
- anOriginalPosition = middlePoint(aMessage->movedObject());
+ anOriginalPosition = middlePoint(aMessage->movedObject(), this);
if (!anOriginalPosition)
return; // something has gone wrong, do not process movement
theDumper << *aFIt;
}
theDumper << "\n" << aSpaceShift << " ])" << std::endl;
+ // call model.do() for correct update of the document's labels related to the changed faces
+ theDumper << "model.do()" << std::endl;
}
}
#include <ModelHighAPI_Interface.h>
#include <ModelHighAPI_Macro.h>
+#include <ModelHighAPI_Selection.h>
//--------------------------------------------------------------------------------------
class ModelAPI_CompositeFeature;
class ModelAPI_Object;
class ModelHighAPI_Integer;
class ModelHighAPI_RefAttr;
class ModelHighAPI_Reference;
-class ModelHighAPI_Selection;
class SketchAPI_Arc;
class SketchAPI_MacroArc;
class SketchAPI_Circle;
class SketchAPI_MacroEllipse;
class SketchAPI_EllipticArc;
class SketchAPI_MacroEllipticArc;
+class SketchAPI_BSpline;
class SketchAPI_IntersectionPoint;
class SketchAPI_Line;
class SketchAPI_Mirror;
class SketchAPI_Rotation;
class SketchAPI_Translation;
//--------------------------------------------------------------------------------------
+typedef std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> PointOrReference;
+//--------------------------------------------------------------------------------------
/**\class SketchAPI_Sketch
* \ingroup CPPHighAPI
* \brief Interface for Sketch feature
/// Add ellipse
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_MacroEllipse> addEllipse(
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint1,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint2,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePassedPoint,
+ const PointOrReference& thePoint1,
+ const PointOrReference& thePoint2,
+ const PointOrReference& thePassedPoint,
bool isPoint1Center = true);
/// Add ellipse
SKETCHAPI_EXPORT
/// Add elliptic arc
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_MacroEllipticArc> addEllipticArc(
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theStartPoint,
- const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theEndPoint,
+ const PointOrReference& theCenter,
+ const PointOrReference& theMajorAxisPoint,
+ const PointOrReference& theStartPoint,
+ const PointOrReference& theEndPoint,
bool theInversed = false);
/// Add elliptic arc
SKETCHAPI_EXPORT
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(const std::string & theExternalName);
+ /// Add B-spline
+ SKETCHAPI_EXPORT
+ std::shared_ptr<SketchAPI_BSpline> addSpline(
+ const ModelHighAPI_Selection & external = ModelHighAPI_Selection(),
+ const int degree = -1,
+ const std::list<PointOrReference>& poles = std::list<PointOrReference>(),
+ const std::list<ModelHighAPI_Double>& weights = std::list<ModelHighAPI_Double>(),
+ const std::list<ModelHighAPI_Double>& knots = std::list<ModelHighAPI_Double>(),
+ const std::list<ModelHighAPI_Integer>& multiplicities = std::list<ModelHighAPI_Integer>(),
+ const bool periodic = false);
+
/// Add projection
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_Projection> addProjection(
std::shared_ptr<ModelHighAPI_Interface> setAngle(
const ModelHighAPI_RefAttr & theLine1,
const ModelHighAPI_RefAttr & theLine2,
- const ModelHighAPI_Double & theValue);
+ const ModelHighAPI_Double & theValue,
+ const std::string& type = std::string());
/// Set complementary angle
SKETCHAPI_EXPORT
#include "SketchAPI_SketchEntity.h"
#include <SketchAPI_Arc.h>
+#include <SketchAPI_BSpline.h>
#include <SketchAPI_Circle.h>
#include <SketchAPI_Ellipse.h>
#include <SketchAPI_EllipticArc.h>
#include <ModelHighAPI_Tools.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_IntersectionPoint.h>
{
// check the feature is a copy of another entity
AttributeBooleanPtr isCopy = feature()->boolean(SketchPlugin_SketchEntity::COPY_ID());
- return isCopy.get() && isCopy->value();
+ AttributeReferencePtr hasParent = feature()->reference(SketchPlugin_SketchEntity::PARENT_ID());
+ return (isCopy.get() && isCopy->value()) || (hasParent && hasParent->value());
}
std::list<std::shared_ptr<SketchAPI_SketchEntity> >
aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Ellipse(*anIt)));
else if ((*anIt)->getKind() == SketchPlugin_EllipticArc::ID())
aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_EllipticArc(*anIt)));
+ else if ((*anIt)->getKind() == SketchPlugin_BSpline::ID())
+ aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_BSpline(*anIt)));
+ else if ((*anIt)->getKind() == SketchPlugin_BSplinePeriodic::ID()) {
+ aResult.push_back(
+ std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_BSplinePeriodic(*anIt)));
+ }
else if ((*anIt)->getKind() == SketchPlugin_Point::ID())
aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Point(*anIt)));
else if ((*anIt)->getKind() == SketchPlugin_IntersectionPoint::ID())
#include "SketchAPI_MacroEllipse.h"
#include "SketchAPI_EllipticArc.h"
#include "SketchAPI_MacroEllipticArc.h"
+ #include "SketchAPI_BSpline.h"
#include "SketchAPI_Constraint.h"
#include "SketchAPI_ConstraintAngle.h"
#include "SketchAPI_IntersectionPoint.h"
SET(PROJECT_HEADERS
SketchPlugin.h
SketchPlugin_Arc.h
+ SketchPlugin_BSpline.h
+ SketchPlugin_BSplineBase.h
+ SketchPlugin_BSplinePeriodic.h
SketchPlugin_Circle.h
SketchPlugin_Constraint.h
SketchPlugin_ConstraintAngle.h
SketchPlugin_Line.h
SketchPlugin_MacroArc.h
SketchPlugin_MacroArcReentrantMessage.h
+ SketchPlugin_MacroBSpline.h
SketchPlugin_MacroCircle.h
SketchPlugin_MacroEllipse.h
SketchPlugin_MacroEllipticArc.h
SketchPlugin_Point.h
SketchPlugin_Projection.h
SketchPlugin_Sketch.h
+ SketchPlugin_SketchDrawer.h
SketchPlugin_SketchEntity.h
SketchPlugin_Split.h
SketchPlugin_Tools.h
SketchPlugin_Trim.h
SketchPlugin_Validators.h
- SketchPlugin_SketchDrawer.h
)
SET(PROJECT_SOURCES
SketchPlugin_Arc.cpp
+ SketchPlugin_BSpline.cpp
+ SketchPlugin_BSplineBase.cpp
+ SketchPlugin_BSplinePeriodic.cpp
SketchPlugin_Circle.cpp
SketchPlugin_Constraint.cpp
SketchPlugin_ConstraintAngle.cpp
SketchPlugin_IntersectionPoint.cpp
SketchPlugin_Line.cpp
SketchPlugin_MacroArc.cpp
+ SketchPlugin_MacroBSpline.cpp
SketchPlugin_MacroCircle.cpp
SketchPlugin_MacroEllipse.cpp
SketchPlugin_MacroEllipticArc.cpp
SketchPlugin_Point.cpp
SketchPlugin_Projection.cpp
SketchPlugin_Sketch.cpp
+ SketchPlugin_SketchDrawer.cpp
SketchPlugin_SketchEntity.cpp
SketchPlugin_Split.cpp
SketchPlugin_Tools.cpp
SketchPlugin_Trim.cpp
SketchPlugin_Validators.cpp
- SketchPlugin_SketchDrawer.cpp
)
SET(PROJECT_LIBRARIES
GeomAlgoAPI
ModelAPI
ModelGeomAlgo
+ ModuleBase
SketcherPrs
GeomDataAPI
)
)
SET(TEXT_RESOURCES
- SketchPlugin_msg_en.ts
- SketchPlugin_msg_fr.ts
+ SketchPlugin_msg_en.ts
+ SketchPlugin_msg_fr.ts
)
+# sources / moc wrappings
+QT_WRAP_MOC(PROJECT_AUTOMOC ${PROJECT_MOC_HEADERS})
+
+SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC})
SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
ADD_DEFINITIONS(-DSKETCHPLUGIN_EXPORTS)
-ADD_LIBRARY(SketchPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES})
+ADD_LIBRARY(SketchPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES} ${PROJECT_AUTOMOC})
TARGET_LINK_LIBRARIES(SketchPlugin ${PROJECT_LIBRARIES})
INCLUDE_DIRECTORIES(
../Events
../ModelAPI
../ModelGeomAlgo
+ ../ModuleBase
../GeomAPI
../GeomAlgoAPI
../GeomDataAPI
../SketcherPrs
+ ${OpenCASCADE_INCLUDE_DIR}
)
INSTALL(TARGETS SketchPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES})
Test3019.py
Test3087_1.py
Test3087_2.py
+ Test3132.py
TestArcBehavior.py
+ TestBSplineAddPole.py
TestChangeSketchPlane1.py
TestChangeSketchPlane2.py
TestChangeSketchPlane3.py
TestChangeSketchPlane4.py
TestConstraintAngle.py
+ TestConstraintAngle_v0_1.py
+ TestConstraintAngle_v0_2.py
+ TestConstraintAngle_v20191210_1.py
+ TestConstraintAngle_v20191210_2.py
+ TestConstraintAngleBehaviorDirect.py
+ TestConstraintAngleBehaviorSupplementary_1.py
+ TestConstraintAngleBehaviorSupplementary_2.py
+ TestConstraintAngleBehaviorBackward_1.py
+ TestConstraintAngleBehaviorBackward_2.py
TestConstraintAngleEllipse.py
TestConstraintCoincidence.py
+ TestConstraintCoincidenceBSpline.py
TestConstraintCoincidenceEllipse.py
TestConstraintCoincidenceEllipticArc.py
TestConstraintCollinear.py
TestConstraintRadius.py
TestConstraintRadiusFailure.py
TestConstraintTangent.py
+ TestConstraintTangentBSpline.py
TestConstraintTangentEllipse.py
TestConstraintTangentEllipticArc.py
TestConstraintVertical.py
TestCreateArcByThreePoints.py
TestCreateArcByTransversalLine.py
TestCreateArcChangeType.py
+ TestCreateBSpline.py
+ TestCreateBSplinePeriodic.py
TestCreateCircleByCenterAndPassed.py
TestCreateCircleByThreePoints.py
TestCreateCircleChangeType.py
TestCreateEllipseByExternal.py
TestCreateEllipticArc.py
TestCreateEllipticArcByExternal.py
+ TestCreateMacroBSpline.py
TestDegeneratedGeometry.py
TestDistanceDump.py
TestDistanceSignedVsUnsigned01.py
TestMultiTranslation.py
TestPresentation.py
TestProjection.py
+ TestProjectionBSpline.py
+ TestProjectionBSplinePeriodic.py
TestProjectionEllipse.py
TestProjectionEllipticArc.py
TestProjectionIntoResult.py
TestProjectionUpdate.py
TestRectangle.py
TestRemainingDoF.py
+ TestRemoveBSpline.py
+ TestRemoveBSplinePeriodic.py
TestRemoveEllipse.py
TestRemoveEllipticArc.py
TestRemoveSketch.py
if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
ADD_UNIT_TESTS(
TestMoveArc.py
+ TestMoveBSpline.py
+ TestMoveBSplinePeriodic.py
TestMoveCircle.py
TestMoveEllipse.py
TestMoveEllipticArc.py
--- /dev/null
+// Copyright (C) 2019-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_BSpline.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+
+SketchPlugin_BSpline::SketchPlugin_BSpline()
+ : SketchPlugin_BSplineBase()
+{
+}
+
+void SketchPlugin_BSpline::initDerivedClassAttributes()
+{
+ data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
+ data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId());
+
+ SketchPlugin_BSplineBase::initDerivedClassAttributes();
+}
+
+void SketchPlugin_BSpline::attributeChanged(const std::string& theID) {
+ if (theID == POLES_ID()) {
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(START_ID()))->setValue(aPolesArray->pnt(0));
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(END_ID()))->setValue(aPolesArray->pnt(aPolesArray->size() - 1));
+ }
+ else
+ SketchPlugin_BSplineBase::attributeChanged(theID);
+}
--- /dev/null
+// Copyright (C) 2019-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_BSpline_H_
+#define SketchPlugin_BSpline_H_
+
+#include <SketchPlugin_BSplineBase.h>
+
+/**\class SketchPlugin_BSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the B-spline curve in the sketch.
+ */
+class SketchPlugin_BSpline : public SketchPlugin_BSplineBase
+{
+public:
+ /// B-spline feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchBSpline");
+ return ID;
+ }
+
+ /// start point of B-spline curve
+ inline static const std::string& START_ID()
+ {
+ static const std::string ID("start_point");
+ return ID;
+ }
+ /// end point of B-spline curve
+ inline static const std::string& END_ID()
+ {
+ static const std::string ID("end_point");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_BSpline::ID();
+ return MY_KIND;
+ }
+
+ /// Called on change of any argument-attribute of this object
+ SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// Use plugin manager for features creation
+ SketchPlugin_BSpline();
+
+protected:
+ /// \brief Initializes attributes of derived class.
+ virtual void initDerivedClassAttributes();
+
+ virtual bool isPeriodic() const { return false; }
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2019-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_BSplineBase.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_MacroBSpline.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <Events_InfoMessage.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+
+SketchPlugin_BSplineBase::SketchPlugin_BSplineBase()
+ : SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_BSplineBase::initDerivedClassAttributes()
+{
+ data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+ data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+ data()->addAttribute(KNOTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+ data()->addAttribute(MULTS_ID(), ModelAPI_AttributeIntArray::typeId());
+ data()->addAttribute(DEGREE_ID(), ModelAPI_AttributeInteger::typeId());
+
+ data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_BSplineBase::execute()
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if(!aSketch) {
+ return;
+ }
+
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+ AttributeDoubleArrayPtr aKnotsArray = data()->realArray(KNOTS_ID());
+ AttributeIntArrayPtr aMultsArray = data()->intArray(MULTS_ID());
+ AttributeIntegerPtr aDegreeAttr = data()->integer(DEGREE_ID());
+
+ // collect poles
+ std::list<GeomPnt2dPtr> aPoles2D;
+ for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+ GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ aPoles2D.push_back(aPole);
+ }
+ // collect weights
+ std::list<double> aWeights;
+ for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
+ aWeights.push_back(aWeightsArray->value(anIndex));
+ // collect knots
+ std::list<double> aKnots;
+ for (int anIndex = 0; anIndex < aKnotsArray->size(); ++anIndex)
+ aKnots.push_back(aKnotsArray->value(anIndex));
+ // collect multiplicities
+ std::list<int> aMults;
+ for (int anIndex = 0; anIndex < aMultsArray->size(); ++anIndex)
+ aMults.push_back(aMultsArray->value(anIndex));
+
+ // create result B-spline curve
+ GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(),
+ aPoles2D, aWeights, aKnots, aMults, aDegreeAttr->value(), isPeriodic());
+
+ ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
+ aResult->setShape(anEdge);
+ aResult->setIsInHistory(false);
+ setResult(aResult, 0);
+}
+
+bool SketchPlugin_BSplineBase::isFixed() {
+ return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_BSplineBase::attributeChanged(const std::string& theID) {
+}
+
+bool SketchPlugin_BSplineBase::customAction(const std::string& theActionId)
+{
+ // parse for the action and an index divided by '#'
+ std::string anAction;
+ int anIndex = -1;
+ size_t pos = theActionId.find('#');
+ if (pos != std::string::npos) {
+ anAction = theActionId.substr(0, pos);
+ anIndex = std::stoi(theActionId.substr(pos + 1));
+ }
+
+ if (anAction == ADD_POLE_ACTION_ID()) {
+ return addPole(anIndex);
+ }
+
+ std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
+ Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(theActionId).send();
+ return false;
+}
+
+bool SketchPlugin_BSplineBase::addPole(const int theAfter)
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ int anAfter = (!isPeriodic() && theAfter == aPolesArray->size() - 1) ? theAfter - 1 : theAfter;
+
+ // find internal coincidences applied to the poles with greater indices
+ std::list<AttributeIntegerPtr> aCoincidentPoleIndex;
+ std::map<int, FeaturePtr> aControlPoles, aControlSegments;
+ bool hasAuxSegment = false;
+ const std::set<AttributePtr>& aRefs = data()->refsToMe();
+ for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature((*anIt)->owner());
+ if (aFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+ AttributeIntegerPtr anIndex;
+ AttributeRefAttrPtr aNonSplinePoint;
+ if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A()) {
+ anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ aNonSplinePoint = aFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
+ }
+ else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B()) {
+ anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ aNonSplinePoint = aFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
+ }
+
+ if (anIndex && anIndex->isInitialized()) {
+ if (anIndex->value() > anAfter) {
+ aCoincidentPoleIndex.push_back(anIndex);
+ FeaturePtr aParent = ModelAPI_Feature::feature(aNonSplinePoint->attr()->owner());
+ if (aParent->getKind() == SketchPlugin_Point::ID())
+ aControlPoles[anIndex->value()] = aParent;
+ else if (aParent->getKind() == SketchPlugin_Line::ID() &&
+ aNonSplinePoint->attr()->id() == SketchPlugin_Line::START_ID())
+ aControlSegments[anIndex->value()] = aParent;
+ }
+ else if (anIndex->value() == anAfter && !hasAuxSegment) {
+ // check the constrained object is a segment of the control polygon
+ if (aNonSplinePoint && !aNonSplinePoint->isObject() &&
+ aNonSplinePoint->attr()->id() == SketchPlugin_Line::START_ID()) {
+ hasAuxSegment = true;
+ aCoincidentPoleIndex.push_back(anIndex);
+ aControlSegments[anIndex->value()] =
+ ModelAPI_Feature::feature(aNonSplinePoint->attr()->owner());
+ }
+ }
+ }
+ }
+ }
+
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+
+ // add new pole and default weight
+ std::list<GeomPnt2dPtr> aPoles;
+ aPolesArray->setSize(aPolesArray->size() + 1);
+ aPolesArray->setPnt(aPolesArray->size() - 1, aPolesArray->pnt(0)); // for periodic spline
+ for (int i = aPolesArray->size() - 2; i > anAfter; --i) {
+ aPoles.push_front(aPolesArray->pnt(i));
+ aPolesArray->setPnt(i + 1, aPoles.front());
+ }
+
+ GeomPnt2dPtr aCurPole = aPolesArray->pnt(anAfter);
+ GeomPnt2dPtr aNextPole = aPolesArray->pnt(anAfter + 1);
+ aPolesArray->setPnt(anAfter + 1, (aCurPole->x() + aNextPole->x()) * 0.5,
+ (aCurPole->y() + aNextPole->y()) * 0.5);
+ for (int i = anAfter + 1; i >= 0; --i)
+ aPoles.push_front(aPolesArray->pnt(i));
+
+ std::list<double> aWeights;
+ for (int i = 0; i < aWeightsArray->size(); ++i) {
+ aWeights.push_back(aWeightsArray->value(i));
+ if (i == anAfter)
+ aWeights.push_back(1.0); // default weight
+ }
+ aWeightsArray->setSize(aWeightsArray->size() + 1);
+ std::list<double>::iterator aWIt = aWeights.begin();
+ for (int i = 0; i < aWeightsArray->size(); ++i, ++aWIt)
+ aWeightsArray->setValue(i, *aWIt);
+
+ // recalculate knots and multiplicities
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+ new GeomAPI_BSpline2d(aPoles, aWeights, isPeriodic()));
+
+ integer(DEGREE_ID())->setValue(aBSplineCurve->degree());
+
+ AttributeDoubleArrayPtr aKnotsAttr = data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ std::list<double> aKnots = aBSplineCurve->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 = data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ std::list<int> aMults = aBSplineCurve->mults();
+ aSize = (int)aMults.size();
+ aMultsAttr->setSize(aSize);
+ std::list<int>::iterator aMIt = aMults.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMultsAttr->setValue(index, *aMIt);
+
+ data()->blockSendAttributeUpdated(aWasBlocked, true);
+
+ // update indices of internal coincidences
+ for (std::list<AttributeIntegerPtr>::iterator aCIt = aCoincidentPoleIndex.begin();
+ aCIt != aCoincidentPoleIndex.end(); ++aCIt)
+ (*aCIt)->setValue((*aCIt)->value() + 1);
+
+ // create auxiliary segment and pole updating the control polygon
+ SketchPlugin_MacroBSpline::createAuxiliaryPole(aPolesArray, anAfter + 1);
+ if (hasAuxSegment)
+ SketchPlugin_MacroBSpline::createAuxiliarySegment(aPolesArray, anAfter, anAfter + 1);
+
+ // update names of features representing control polygon
+ for (std::map<int, FeaturePtr>::iterator anIt = aControlPoles.begin();
+ anIt != aControlPoles.end(); ++anIt) {
+ SketchPlugin_MacroBSpline::assignDefaultNameForAux(anIt->second, aPolesArray, anIt->first + 1);
+ }
+ for (std::map<int, FeaturePtr>::iterator anIt = aControlSegments.begin();
+ anIt != aControlSegments.end(); ++anIt) {
+ SketchPlugin_MacroBSpline::assignDefaultNameForAux(anIt->second, aPolesArray,
+ anIt->first + 1, (anIt->first + 2) % aPolesArray->size());
+ }
+
+ return true;
+}
--- /dev/null
+// Copyright (C) 2019-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_BSplineBase_H_
+#define SketchPlugin_BSplineBase_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_BSplineBase
+ * \ingroup Plugins
+ * \brief Base class for B-spline curves in the sketch.
+ */
+class SketchPlugin_BSplineBase : public SketchPlugin_SketchEntity
+{
+public:
+ /// list of B-spline poles
+ inline static const std::string& POLES_ID()
+ {
+ static const std::string ID("poles");
+ return ID;
+ }
+
+ /// list of B-spline weights
+ inline static const std::string& WEIGHTS_ID()
+ {
+ static const std::string ID("weights");
+ return ID;
+ }
+
+ /// attribute to store the degree of B-spline
+ inline static const std::string& DEGREE_ID()
+ {
+ static const std::string ID("degree");
+ return ID;
+ }
+
+ /// list of B-spline knots
+ inline static const std::string& KNOTS_ID()
+ {
+ static const std::string ID("knots");
+ return ID;
+ }
+
+ /// list of B-spline multiplicities
+ inline static const std::string& MULTS_ID()
+ {
+ static const std::string ID("multiplicities");
+ return ID;
+ }
+
+ /// name for add pole action
+ inline static const std::string& ADD_POLE_ACTION_ID()
+ {
+ static const std::string ID("AddPole");
+ return ID;
+ }
+
+ /// Returns true is sketch element is under the rigid constraint
+ SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+ /// 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();
+
+ /// Updates the B-spline curve.
+ /// \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);
+
+protected:
+ /// Called from the derived class
+ SketchPlugin_BSplineBase();
+
+ /// \brief Initializes attributes of derived class.
+ virtual void initDerivedClassAttributes();
+
+ /// \brief Return \c true if the B-spline curve is periodic
+ virtual bool isPeriodic() const = 0;
+
+ /// Add new pole after the pole with the given index
+ bool addPole(const int theAfter);
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2019-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_BSplinePeriodic.h>
+
+SketchPlugin_BSplinePeriodic::SketchPlugin_BSplinePeriodic()
+ : SketchPlugin_BSplineBase()
+{
+}
--- /dev/null
+// Copyright (C) 2019-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_BSplinePeriodic_H_
+#define SketchPlugin_BSplinePeriodic_H_
+
+#include <SketchPlugin_BSplineBase.h>
+
+/**\class SketchPlugin_BSplinePeriodic
+ * \ingroup Plugins
+ * \brief Feature for creation of the periodic B-spline curve in the sketch.
+ */
+class SketchPlugin_BSplinePeriodic : public SketchPlugin_BSplineBase
+{
+public:
+ /// B-spline feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchBSplinePeriodic");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_BSplinePeriodic::ID();
+ return MY_KIND;
+ }
+
+ /// Use plugin manager for features creation
+ SketchPlugin_BSplinePeriodic();
+
+protected:
+ virtual bool isPeriodic() const { return true; }
+};
+
+#endif
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_EventReentrantMessage.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
data()->addAttribute(LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
aValidators->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
+ data()->addAttribute(PREV_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
+ data()->attribute(PREV_TYPE_ID())->setIsArgument(false);
+ aValidators->registerNotObligatory(getKind(), PREV_TYPE_ID());
+ if (attribute(TYPE_ID())->isInitialized())
+ integer(PREV_TYPE_ID())->setValue(integer(TYPE_ID())->value());
+
data()->addAttribute(SELECTED_FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
data()->attribute(SELECTED_FIRST_POINT_ID())->setIsArgument(false);
aValidators->registerNotObligatory(getKind(), SELECTED_FIRST_POINT_ID());
data()->attribute(SELECTED_SECOND_POINT_ID())->setIsArgument(false);
aValidators->registerNotObligatory(getKind(), SELECTED_SECOND_POINT_ID());
- if (attribute(TYPE_ID())->isInitialized())
- myPrevAngleType = integer(TYPE_ID())->value();
- else
- myPrevAngleType = (int)SketcherPrs_Tools::ANGLE_DIRECT;
+ AttributeIntegerPtr aVerAttr = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(
+ data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId()));
+ aVerAttr->setIsArgument(false);
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID());
+ if (!aVerAttr->isInitialized()) {
+ // this is a newly created feature (not read from file),
+ // so, initialize the latest version
+ aVerAttr->setValue(THE_VERSION_1);
+ }
}
void SketchPlugin_ConstraintAngle::colorConfigInfo(std::string& theSection, std::string& theName,
if (!anAttrA->isInitialized() || !anAttrB->isInitialized())
return;
+ AttributeIntegerPtr aVersion = integer(VERSION_ID());
+ if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
+ updateVersion();
+
AttributeDoublePtr anAttrValue = real(ANGLE_VALUE_ID());
if (!anAttrValue->isInitialized())
calculateAngle();
return anAIS;
}
+// LCOV_EXCL_START
+std::string SketchPlugin_ConstraintAngle::processEvent(
+ const std::shared_ptr<Events_Message>& theMessage)
+{
+ std::string aFilledAttributeName;
+
+ std::shared_ptr<ModelAPI_EventReentrantMessage> aReentrantMessage =
+ std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+ if (aReentrantMessage.get()) {
+ aFilledAttributeName = ENTITY_A();
+ refattr(ENTITY_A())->setObject(aReentrantMessage->selectedObject());
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SELECTED_FIRST_POINT_ID()))
+ ->setValue(aReentrantMessage->clickedPoint());
+ }
+ return aFilledAttributeName;
+}
+// LCOV_EXCL_STOP
+
void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
{
+ if (myFlyoutUpdate)
+ return;
+
std::shared_ptr<ModelAPI_Data> aData = data();
if (!aData)
return;
if (!aLineA || !aLineB)
return;
+ AttributeIntegerPtr aVersion = integer(VERSION_ID());
+ if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
+ updateVersion();
+
if (theID == ENTITY_A() || theID == ENTITY_B() ||
theID == TYPE_ID() || theID == ANGLE_VALUE_ID()) {
calculateAngle();
- } else if (theID == FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
- // Recalculate flyout point in local coordinates
- // coordinates are calculated according to the center of shapes intersection
- std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FLYOUT_VALUE_PNT()));
-
- std::shared_ptr<ModelAPI_Data> aData = data();
- std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
-
- // Intersection of lines
- std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
- if (!anInter)
- return;
-
- myFlyoutUpdate = true;
- std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutAttr->pnt()->xy()->decreased(anInter->xy());
- if (aFlyoutDir->dot(aFlyoutDir) < tolerance * tolerance)
- aFlyoutAttr->setValue(aFlyoutAttr->x() + tolerance, aFlyoutAttr->y());
- myFlyoutUpdate = false;
+ } else if (theID == FLYOUT_VALUE_PNT()) {
+ compute(theID);
}
}
bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
- std::shared_ptr<GeomAPI_Angle2d> anAng(
- new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
- double anAngle = anAng->angleDegree();
-
AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
- if (!anAngleValueAttr->isInitialized())
- anAngleValueAttr->setValue(getAngleForType(fabs(anAngle)));
+ if (!anAngleValueAttr->isInitialized()) {
+ std::shared_ptr<GeomAPI_Angle2d> anAng(
+ new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
+ anAngleValueAttr->setValue(getAngleForType(fabs(anAng->angleDegree())));
+ }
+
+ std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aLine1, false, aLine2, false));
+ double anAngle = anAng->angleDegree();
anAngle /= fabs(anAngle);
- anAngle *= getAngleForType(anAngleValueAttr->value());
+ anAngle *= getAngleForType(anAngleValueAttr->value(), isReversed1, isReversed2);
// update value of the constraint to be passed to the solver
real(SketchPlugin_Constraint::VALUE())->setValue(anAngle);
boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
}
+// Convert angle value from the DIRECT to any given type.
static double angleForType(const double theAngle, const int theType)
{
double anAngle = theAngle;
return anAngle;
}
-double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle)
+double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle,
+ bool isReversed1,
+ bool isReversed2)
{
- return angleForType(theAngle, integer(TYPE_ID())->value());
+ double anAngle = angleForType(theAngle, integer(TYPE_ID())->value());
+ if (isReversed1 != isReversed2)
+ anAngle = 180.0 - anAngle;
+ return anAngle;
}
-void SketchPlugin_ConstraintAngle::updateAngleValue()
+// Convert angle value or a text expression from one angle type to another
+static void convertAngle(AttributeDoublePtr theAngle,
+ const int thePrevType, const int theNewType)
{
- AttributeIntegerPtr anAngleType = integer(TYPE_ID());
- AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
- if (anAngleValueAttr->isInitialized()) {
- if (anAngleValueAttr->text().empty()) {
+ if (theAngle->isInitialized()) {
+ if (theAngle->text().empty()) {
// calculate value related to the type twice:
// the first time - to return to direct angle,
// the second time - to apply new type
- double aValue = angleForType(anAngleValueAttr->value(), myPrevAngleType);
- aValue = angleForType(aValue, anAngleType->value());
- anAngleValueAttr->setValue(aValue);
+ double aValue = angleForType(theAngle->value(), thePrevType);
+ aValue = angleForType(aValue, theNewType);
+ theAngle->setValue(aValue);
}
else {
// process the parametric value
- std::string anAngleText = anAngleValueAttr->text();
- std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)",
+ std::string anAngleText = theAngle->text();
+ std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)$",
std::regex_constants::ECMAScript);
double anAnglePrefix = 0.0;
anAngleText = aResult[3].str();
}
- if (myPrevAngleType != SketcherPrs_Tools::ANGLE_DIRECT)
+ if (thePrevType != SketcherPrs_Tools::ANGLE_DIRECT)
aSignInd = 1 - aSignInd;
- anAnglePrefix = angleForType(anAnglePrefix, myPrevAngleType);
+ anAnglePrefix = angleForType(anAnglePrefix, thePrevType);
- if (anAngleType->value() != SketcherPrs_Tools::ANGLE_DIRECT)
+ if (theNewType != SketcherPrs_Tools::ANGLE_DIRECT)
aSignInd = 1 - aSignInd;
- anAnglePrefix = angleForType(anAnglePrefix, anAngleType->value());
+ anAnglePrefix = angleForType(anAnglePrefix, theNewType);
std::ostringstream aText;
bool isPrintSign = true;
if (isPrintSign)
aText << " " << aSignPrefix[aSignInd] << " (";
aText << anAngleText << (isPrintSign ? ")" : "");
- anAngleValueAttr->setText(aText.str());
+ theAngle->setText(aText.str());
}
}
- myPrevAngleType = anAngleType->value();
+}
+
+void SketchPlugin_ConstraintAngle::updateAngleValue()
+{
+ AttributeIntegerPtr anAngleType = integer(TYPE_ID());
+ AttributeIntegerPtr aPrevAngleType = integer(PREV_TYPE_ID());
+ convertAngle(real(ANGLE_VALUE_ID()), aPrevAngleType->value(), anAngleType->value());
+ aPrevAngleType->setValue(anAngleType->value());
+}
+
+static GeomPnt2dPtr lineBoundary(const FeaturePtr& theLine, const bool theReversed,
+ const GeomPnt2dPtr& thePointToAvoid)
+{
+ GeomPnt2dPtr aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
+ theReversed ? SketchPlugin_Line::START_ID() : SketchPlugin_Line::END_ID());
+ if (aPoint->distance(thePointToAvoid) < tolerance) {
+ // extremity is equal to the intersection point,
+ // thus recalculate it using another boundary point
+ aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
+ theReversed ? SketchPlugin_Line::END_ID() : SketchPlugin_Line::START_ID());
+ aPoint->setX(thePointToAvoid->x() * 2.0 - aPoint->x());
+ aPoint->setY(thePointToAvoid->y() * 2.0 - aPoint->y());
+ }
+ return aPoint;
}
bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
GeomDataAPI_Point2D>(attribute(theAttributeId));
- if (aFlyOutAttr->isInitialized() &&
- (fabs(aFlyOutAttr->x()) >= tolerance || fabs(aFlyOutAttr->y()) >= tolerance))
- return false;
DataPtr aData = data();
std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
- FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
- FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
+ FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
+ FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
if ((aLineA.get() == NULL) || (aLineB.get() == NULL))
return false;
- // Start and end points of lines
- GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
- GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
- if (aStartA->distance(aEndA) < tolerance)
+ // Intersection of lines
+ std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
+ if (!anInter)
return false;
- GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
- GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
- if (aStartB->distance(aEndB) < tolerance)
- return false;
+ bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
+ bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
+
+ int anAngleType = integer(TYPE_ID())->value();
+
+ bool isSupplementary = anAngleType == (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY;
+
+ // point on lines to compose an angle
+ GeomPnt2dPtr aPointA = lineBoundary(aLineA, isReversed1 ^ isSupplementary, anInter);
+ GeomPnt2dPtr aPointB = lineBoundary(aLineB, isReversed2, anInter);
myFlyoutUpdate = true;
- double aX = (aStartA->x() + aEndA->x() + aStartB->x() + aEndB->x()) / 4.;
- double aY = (aStartA->y() + aEndA->y() + aStartB->y() + aEndB->y()) / 4.;
+ if (aFlyOutAttr->isInitialized()) {
+ std::shared_ptr<GeomAPI_XY> aFlyoutPoint = aFlyOutAttr->pnt()->xy();
+ std::shared_ptr<GeomAPI_XY> anInterXY = anInter->xy();
+ std::shared_ptr<GeomAPI_XY> aDirIF = aFlyoutPoint->decreased(anInterXY);
+ std::shared_ptr<GeomAPI_XY> aDirIA = aPointA->xy()->decreased(anInterXY);
+ std::shared_ptr<GeomAPI_XY> aDirIB = aPointB->xy()->decreased(anInterXY);
+ double aSign = aDirIA->cross(aDirIB);
+ aSign /= fabs(aSign);
+ if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD)
+ aSign *= -1.0;
+
+ double cross1 = aSign * aDirIA->cross(aDirIF);
+ if (cross1 < -tolerance)
+ boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(!isReversed2);
+ double cross2 = aSign * aDirIF->cross(aDirIB);
+ if (cross2 < -tolerance)
+ boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(!isReversed1);
+
+ // the direction is reversed only once
+ if ((cross1 + tolerance) * (cross2 + tolerance) < 0.0) {
+ if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
+ convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_BACKWARD,
+ (int)SketcherPrs_Tools::ANGLE_DIRECT);
+ }
+ convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
+ (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY);
+ if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
+ convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
+ (int)SketcherPrs_Tools::ANGLE_BACKWARD);
+ }
+ }
- aFlyOutAttr->setValue(aX, aY);
+ calculateAngle();
+ }
+ else {
+ // default position of the presentation
+ double aX = (aPointA->x() + aPointB->x() + anInter->x()) / 3.;
+ double aY = (aPointA->y() + aPointB->y() + anInter->y()) / 3.;
+ aFlyOutAttr->setValue(aX, aY);
+ }
myFlyoutUpdate = false;
return true;
}
+void SketchPlugin_ConstraintAngle::updateVersion()
+{
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+
+ // Calculate angle value by the old algorithm and
+ // update the corresponding attribute to meet the new requirements.
+ FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_A());
+ FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_B());
+
+ GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
+ GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
+ GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
+ GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
+
+ std::shared_ptr<GeomAPI_Angle2d> anAng;
+
+ if (boolean(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
+ boolean(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized()) {
+ bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
+ bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
+
+ std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
+ std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
+ anAng.reset(new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
+ }
+ else {
+ anAng.reset(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
+
+ bool isReversed1 = anAng->isReversed(0);
+ bool isReversed2 = anAng->isReversed(1);
+
+ boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
+ boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
+ }
+ double anAngleValue = anAng->angleDegree();
+ double aConstValue = real(ANGLE_VALUE_ID())->value();
+
+ AttributeIntegerPtr aType = integer(TYPE_ID());
+ switch ((SketcherPrs_Tools::AngleType)aType->value()) {
+ case SketcherPrs_Tools::ANGLE_DIRECT:
+ if (anAngleValue < 0.0 && aConstValue > 180.0)
+ convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_BACKWARD,
+ SketcherPrs_Tools::ANGLE_DIRECT);
+ break;
+ case SketcherPrs_Tools::ANGLE_BACKWARD:
+ if (anAngleValue < 0.0 && aConstValue < 180.0)
+ convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_DIRECT,
+ SketcherPrs_Tools::ANGLE_BACKWARD);
+ break;
+ default:
+ break;
+ }
+ data()->blockSendAttributeUpdated(aWasBlocked, false);
+ integer(VERSION_ID())->setValue(THE_VERSION_1);
+}
+
// =============== Auxiliary functions ==================================
std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
#define SketchPlugin_ConstraintAngle_H_
#include "SketchPlugin.h"
-#include <SketchPlugin_Sketch.h>
+#include "SketchPlugin_Sketch.h"
#include "SketchPlugin_ConstraintBase.h"
+#include <ModelAPI_IReentrant.h>
+
/** \class SketchPlugin_ConstraintAngle
* \ingroup Plugins
* \brief Feature for creation of a new constraint fix angle between two lines
* This constraint has two attributes:
* SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
*/
-class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase
+class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase,
+ public ModelAPI_IReentrant
{
- public:
+public:
/// Angle constraint kind
inline static const std::string& ID()
{
static const std::string MY_TYPE_ID("AngleType");
return MY_TYPE_ID;
}
+ /// attribute name of previous value of operation type
+ inline static const std::string& PREV_TYPE_ID()
+ {
+ static const std::string MY_TYPE_ID("AngleTypePrevious");
+ return MY_TYPE_ID;
+ }
/// attribute name of operation type
inline static const std::string& ANGLE_VALUE_ID()
return MY_SELECTED_SECOND_POINT_ID;
}
+public:
+ static const int THE_VERSION_0 = 0;
+ static const int THE_VERSION_1 = 20191210;
+
+ /// Attribute name of the version of Angle feature
+ inline static const std::string& VERSION_ID()
+ {
+ static const std::string MY_VERSION_ID("version");
+ return MY_VERSION_ID;
+ }
+
+public:
/// \brief Creates a new part document if needed
SKETCHPLUGIN_EXPORT virtual void execute();
/// Returns the AIS preview
SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+ /// Apply information of the message to current object.
+ /// It fills selected point and the first object.
+ virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
/// \brief Use plugin manager for features creation
SketchPlugin_ConstraintAngle();
/// The in/out angle is in degree.
/// \param theAngle a source for the calculated angle
/// \param a double angle value
- double getAngleForType(double theAngle);
+ double getAngleForType(double theAngle, bool isReversed1 = false, bool isReversed2 = false);
/// Update value of ANGLE_VALUE attribute according to the current type
void updateAngleValue();
+ /// Update parameters of the Angle to meet requirements for the latest version
+ void updateVersion();
+
private:
bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point
- int myPrevAngleType;
};
#endif
#include "SketchPlugin_ConstraintCoincidenceInternal.h"
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
SketchPlugin_ConstraintCoincidenceInternal::SketchPlugin_ConstraintCoincidenceInternal()
{
}
void SketchPlugin_ConstraintCoincidenceInternal::initAttributes()
{
SketchPlugin_ConstraintCoincidence::initAttributes();
+
+ data()->addAttribute(INDEX_ENTITY_A(), ModelAPI_AttributeInteger::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_A());
+
+ data()->addAttribute(INDEX_ENTITY_B(), ModelAPI_AttributeInteger::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_B());
}
void SketchPlugin_ConstraintCoincidenceInternal::execute()
class SketchPlugin_ConstraintCoincidenceInternal : public SketchPlugin_ConstraintCoincidence
{
public:
- /// Coincidence constraint kind
+ /// \brief Coincidence constraint kind
inline static const std::string& ID()
{
static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidenceInternal");
return MY_KIND;
}
- /// Returns the AIS preview
+ /// \brief Index of point in the array if the first attribute is an array
+ inline static const std::string& INDEX_ENTITY_A()
+ {
+ static const std::string MY_INDEX("ConstraintEntityA_Index");
+ return MY_INDEX;
+ }
+ /// \brief Index of point in the array if the second attribute is an array
+ inline static const std::string& INDEX_ENTITY_B()
+ {
+ static const std::string MY_INDEX("ConstraintEntityB_Index");
+ return MY_INDEX;
+ }
+
+ /// \brief Returns the AIS preview
SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
/// \brief Creates a new part document if needed
--- /dev/null
+// Copyright (C) 2019-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_MacroBSpline.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+#include <GeomAPI_BSpline2d.h>
+
+#include <sstream>
+
+/// Create internal coincidence constraint with B-spline pole
+static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+ AttributePtr thePoint,
+ AttributePtr theBSplinePoles,
+ const int thePoleIndex);
+
+
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
+ : SketchPlugin_SketchEntity(),
+ myDegree(3),
+ myIsPeriodic(false)
+{
+}
+
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline(bool isPeriodic)
+ : SketchPlugin_SketchEntity(),
+ myDegree(3),
+ myIsPeriodic(isPeriodic)
+{
+}
+
+void SketchPlugin_MacroBSpline::initAttributes()
+{
+ data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+ data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+
+ data()->addAttribute(REF_POLES_ID(), ModelAPI_AttributeRefAttrList::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), REF_POLES_ID());
+
+ data()->addAttribute(CONTROL_POLYGON_ID(), ModelAPI_AttributeBoolean::typeId());
+
+ data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
+}
+
+void SketchPlugin_MacroBSpline::execute()
+{
+ FeaturePtr aBSpline = createBSplineFeature();
+
+ if (boolean(CONTROL_POLYGON_ID())->value()) {
+ std::list<FeaturePtr> aControlPoles;
+ createControlPolygon(aBSpline, aControlPoles);
+ constraintsForPoles(aControlPoles);
+
+ // message to init reentrant operation
+ static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
+ ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+ // set here the last pole to make coincidence with the start point of the next B-spline curve
+ aMessage->setCreatedFeature(aControlPoles.back());
+ Events_Loop::loop()->send(aMessage);
+ }
+}
+
+// LCOV_EXCL_START
+std::string SketchPlugin_MacroBSpline::processEvent(
+ const std::shared_ptr<Events_Message>& theMessage)
+{
+ ReentrantMessagePtr aReentrantMessage =
+ std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+ if (aReentrantMessage) {
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ ObjectPtr anObject = aReentrantMessage->selectedObject();
+ AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+ std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+ if (aClickedPoint) {
+ // fill points list (it consists of 2 points to make editable the second one)
+ AttributePoint2DArrayPtr aPointArrayAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ aPointArrayAttr->setSize(2);
+ aPointArrayAttr->setPnt(0, aClickedPoint);
+ aPointArrayAttr->setPnt(1, aClickedPoint);
+
+ // fill weights
+ AttributeDoubleArrayPtr aWeightsArrayAttr = data()->realArray(WEIGHTS_ID());
+ aWeightsArrayAttr->setSize(2);
+ aWeightsArrayAttr->setValue(0, 1.0);
+ aWeightsArrayAttr->setValue(1, 1.0);
+
+ // fill reference attribute
+ AttributeRefAttrListPtr aRefAttrList =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(attribute(REF_POLES_ID()));
+ if (anAttribute) {
+ if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+ if (aCreatedFeature && anAttribute->id() == SketchPlugin_Point::COORD_ID())
+ anAttribute = aCreatedFeature->attribute(SketchPlugin_Point::COORD_ID());
+ }
+ aRefAttrList->append(anAttribute);
+ }
+ }
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ }
+ return std::string();
+}
+// LCOV_EXCL_STOP
+
+FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
+{
+ if (myKnots.empty() || myMultiplicities.empty())
+ getAISObject(AISObjectPtr()); // fill B-spline parameters
+
+ FeaturePtr aBSpline = sketch()->addFeature(
+ myIsPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ aBSpline->integer(SketchPlugin_BSplineBase::DEGREE_ID())->setValue(myDegree);
+
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aBSpline->attribute(SketchPlugin_BSplineBase::POLES_ID()));
+ AttributePoint2DArrayPtr aPolesMacro =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ aPoles->assign(aPolesMacro);
+
+ AttributeDoubleArrayPtr aWeights =
+ aBSpline->data()->realArray(SketchPlugin_BSplineBase::WEIGHTS_ID());
+ AttributeDoubleArrayPtr aWeightsMacro = data()->realArray(WEIGHTS_ID());
+ int aSize = aWeightsMacro->size();
+ aWeights->setSize(aSize);
+ for (int index = 0; index < aSize; ++index)
+ aWeights->setValue(index, aWeightsMacro->value(index));
+
+ AttributeDoubleArrayPtr aKnots =
+ aBSpline->data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ aSize = (int)myKnots.size();
+ aKnots->setSize(aSize);
+ std::list<double>::iterator aKIt = myKnots.begin();
+ for (int index = 0; index < aSize; ++index, ++aKIt)
+ aKnots->setValue(index, *aKIt);
+
+ AttributeIntArrayPtr aMults = aBSpline->data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ aSize = (int)myMultiplicities.size();
+ aMults->setSize(aSize);
+ std::list<int>::iterator aMIt = myMultiplicities.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMults->setValue(index, *aMIt);
+
+ if (!myIsPeriodic) {
+ AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSpline->attribute(SketchPlugin_BSpline::START_ID()));
+ aStartPoint->setValue(aPoles->pnt(0));
+
+ AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSpline->attribute(SketchPlugin_BSpline::END_ID()));
+ aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1));
+ }
+
+ aBSpline->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+ boolean(AUXILIARY_ID())->value());
+
+ aBSpline->execute();
+
+ return aBSpline;
+}
+
+void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
+ std::list<FeaturePtr>& thePoles)
+{
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ theBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+ int aSize = aPoles->size();
+ // poles
+ for (int index = 0; index < aSize; ++index)
+ thePoles.push_back(createAuxiliaryPole(aPoles, index));
+ // segments
+ for (int index = 1; index < aSize; ++index)
+ createAuxiliarySegment(aPoles, index - 1, index);
+ if (myIsPeriodic) {
+ // additional segment to close the control polygon
+ createAuxiliarySegment(aPoles, aSize - 1, 0);
+ }
+}
+
+void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
+{
+ AttributeRefAttrListPtr aRefAttrList = data()->refattrlist(REF_POLES_ID());
+ std::list<std::pair<ObjectPtr, AttributePtr> > aList;
+ if (aRefAttrList)
+ aList = aRefAttrList->list();
+
+ SketchPlugin_Sketch* aSketch = sketch();
+
+ std::list<std::pair<ObjectPtr, AttributePtr> >::iterator aLIt = aList.begin();
+ std::list<FeaturePtr>::const_iterator aPIt = thePoles.begin();
+ for (; aLIt != aList.end() && aPIt != thePoles.end(); ++aPIt, ++aLIt) {
+ // firstly, check the attribute (in this case the object will be not empty too)
+ if (aLIt->second) {
+ SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->second);
+ }
+ // now add coincidence with the result
+ else if (aLIt->first) {
+ SketchPlugin_Tools::createConstraintAttrObject(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->first);
+ }
+ }
+}
+
+AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if (!aSketch)
+ return AISObjectPtr();
+
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ if (aPolesArray->size() < 2)
+ return AISObjectPtr();
+
+ std::list<GeomShapePtr> aShapes;
+
+ // convert poles to vertices and collect weights
+ std::list<GeomPnt2dPtr> aPoles2D;
+ std::list<double> aWeights;
+ for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+ double aWeight = aWeightsArray->value(anIndex);
+ if (aWeight < 1.e-10)
+ continue; // skip poles with zero weights
+
+ aWeights.push_back(aWeight);
+
+ GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ aPoles2D.push_back(aPole);
+ GeomPointPtr aPole3D = aSketch->to3D(aPole->x(), aPole->y());
+ aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D));
+ }
+
+ // create result non-periodic B-spline curve
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+ try {
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, myIsPeriodic));
+ } catch (...) {
+ // cannot build a B-spline curve
+ return AISObjectPtr();
+ }
+ GeomShapePtr anEdge =
+ GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(), aBSplineCurve);
+ if (!anEdge)
+ return AISObjectPtr();
+
+ // store transient parameters of B-spline curve
+ myDegree = aBSplineCurve->degree();
+ myKnots = aBSplineCurve->knots();
+ myMultiplicities = aBSplineCurve->mults();
+
+ aShapes.push_back(anEdge);
+ GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+
+ AISObjectPtr anAIS = thePrevious;
+ if (!anAIS)
+ anAIS.reset(new GeomAPI_AISObject());
+ anAIS->createShape(aCompound);
+
+ // Modify attributes
+ SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
+ return anAIS;
+}
+
+
+
+// ========================== Auxiliary functions ===========================================
+
+void SketchPlugin_MacroBSpline::assignDefaultNameForAux(FeaturePtr theAuxFeature,
+ AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2)
+{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+ std::ostringstream aName;
+ aName << aBSpline->name();
+ if (theAuxFeature->getKind() == SketchPlugin_Point::ID())
+ aName << "_" << theBSplinePoles->id() << "_" << thePoleIndex1;
+ else
+ aName << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+
+ theAuxFeature->data()->setName(aName.str());
+ theAuxFeature->lastResult()->data()->setName(aName.str());
+}
+
+FeaturePtr SketchPlugin_MacroBSpline::createAuxiliaryPole(AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex)
+{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+ SketchPlugin_Sketch* aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->sketch();
+
+ // create child point equal to the B-spline's pole
+ FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
+ aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+ aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
+
+ GeomPnt2dPtr aPole = theBSplinePoles->pnt(thePoleIndex);
+
+ AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+ aCoord->setValue(aPole);
+
+ aPointFeature->execute();
+ assignDefaultNameForAux(aPointFeature, theBSplinePoles, thePoleIndex);
+
+ // internal constraint to keep position of the point
+ createInternalConstraint(aSketch, aCoord, theBSplinePoles, thePoleIndex);
+
+ return aPointFeature;
+}
+
+void SketchPlugin_MacroBSpline::createAuxiliarySegment(AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2)
+{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+ SketchPlugin_Sketch* aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->sketch();
+
+ // create child segment between B-spline poles
+ FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+ aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+ aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
+
+ AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ aLineStart->setValue(theBSplinePoles->pnt(thePoleIndex1));
+
+ AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+ aLineEnd->setValue(theBSplinePoles->pnt(thePoleIndex2));
+
+ aLineFeature->execute();
+ assignDefaultNameForAux(aLineFeature, theBSplinePoles, thePoleIndex1, thePoleIndex2);
+
+ // internal constraints to keep the segment position
+ createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);
+ createInternalConstraint(aSketch, aLineEnd, theBSplinePoles, thePoleIndex2);
+}
+
+void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+ AttributePtr thePoint,
+ AttributePtr theBSplinePoles,
+ const int thePoleIndex)
+{
+ std::shared_ptr<SketchPlugin_ConstraintCoincidenceInternal> aConstraint =
+ std::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidenceInternal>(
+ theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID()));
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint);
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(theBSplinePoles);
+ aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B())
+ ->setValue(thePoleIndex);
+}
--- /dev/null
+// Copyright (C) 2019-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_MacroBSpline_H_
+#define SketchPlugin_MacroBSpline_H_
+
+#include <ModelAPI_IReentrant.h>
+
+#include "SketchPlugin.h"
+
+#include "SketchPlugin_SketchEntity.h"
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+
+class GeomDataAPI_Point2DArray;
+
+/**\class SketchPlugin_MacroBSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the new B-spline in Sketch.
+ */
+class SketchPlugin_MacroBSpline : public SketchPlugin_SketchEntity,
+ public GeomAPI_IPresentable,
+ public ModelAPI_IReentrant
+{
+public:
+ /// B-spline macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchMacroBSpline");
+ return ID;
+ }
+
+
+ /// list of B-spline poles
+ inline static const std::string& POLES_ID()
+ {
+ static const std::string ID("poles");
+ return ID;
+ }
+
+ /// list of references of B-spline poles
+ inline static const std::string& REF_POLES_ID()
+ {
+ static const std::string ID("poles_ref");
+ return ID;
+ }
+
+ /// list of B-spline weights
+ inline static const std::string& WEIGHTS_ID()
+ {
+ static const std::string ID("weights");
+ return ID;
+ }
+
+ /// flag attribute whether control polygon is need to be created
+ inline static const std::string& CONTROL_POLYGON_ID()
+ {
+ static const std::string ID("need_control_poly");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_MacroBSpline::ID();
+ return MY_KIND;
+ }
+
+ /// \brief Request for initialization of data model of the feature: adding all attributes.
+ SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+ /// 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;};
+
+ /// Apply information of the message to current object. It fills reference object,
+ /// tangent type and tangent point refence in case of tangent arc
+ virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+ /// Use plugin manager for features creation
+ SketchPlugin_MacroBSpline();
+
+protected:
+ SketchPlugin_MacroBSpline(bool isPeriodic);
+
+private:
+ FeaturePtr createBSplineFeature();
+
+ void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
+ void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
+
+ /// Create Point feature coincident with the B-spline pole
+ static FeaturePtr createAuxiliaryPole(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex);
+ /// Create segment between consequtive B-spline poles
+ static void createAuxiliarySegment(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2);
+ /// Set name of auxiliary feature representing the control polygon
+ static void assignDefaultNameForAux(FeaturePtr theAuxFeature,
+ std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2 = -1);
+ friend class SketchPlugin_BSplineBase;
+
+private:
+ std::list<double> myKnots;
+ std::list<int> myMultiplicities;
+ int myDegree;
+ bool myIsPeriodic;
+};
+
+
+/**\class SketchPlugin_MacroBSpline
+* \ingroup Plugins
+* \brief Feature for creation of the new B-spline in Sketch.
+*/
+class SketchPlugin_MacroBSplinePeriodic : public SketchPlugin_MacroBSpline
+{
+public:
+ /// B-spline macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchMacroBSplinePeriodic");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ return SketchPlugin_MacroBSpline::ID();
+ }
+
+ /// Use plugin manager for features creation
+ SketchPlugin_MacroBSplinePeriodic() : SketchPlugin_MacroBSpline(true) {}
+};
+
+#endif
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_PointBuilder.h>
+static const double TOLERANCE = 1.e-7;
SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse()
: SketchPlugin_SketchEntity(),
anEllipsePoints[0]->setY(0.5 * (anEllipsePoints[0]->y() + anEllipsePoints[1]->y()));
}
+ if (anEllipsePoints[0]->distance(anEllipsePoints[1]) < TOLERANCE)
+ return; // ellipse is not valid
+
std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
if (aNbInitialized == 2) {
GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
#include <GeomAlgoAPI_PointBuilder.h>
+const double TOLERANCE = 1.e-7;
const double paramTolerance = 1.e-4;
const double PI = 3.141592653589793238463;
myStartPnt = anEllipsePoints[2];
myEndPnt = anEllipsePoints[3];
+ if (myCenter->distance(myMajorAxis) < TOLERANCE)
+ return; // ellipse is not valid
+
std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
if (aNbInitialized == 2) {
GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
return GeomShapePtr();
SketchPlugin_Sketch* aSketch = sketch();
- if (!aSketch)
+ if (!aSketch || myCenter->distance(myMajorAxis) < 1.e-7)
return GeomShapePtr();
GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
#include <SketchPlugin_IntersectionPoint.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Projection.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
#include <SketchPlugin_MacroArc.h>
+#include <SketchPlugin_MacroBSpline.h>
#include <SketchPlugin_MacroCircle.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
new SketchPlugin_SketchFeatureValidator);
aFactory->registerValidator("SketchPlugin_MultiRotationAngleValidator",
new SketchPlugin_MultiRotationAngleValidator);
+ aFactory->registerValidator("SketchPlugin_BSplineValidator",
+ new SketchPlugin_BSplineValidator);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new SketchPlugin_Circle);
} else if (theFeatureID == SketchPlugin_Arc::ID()) {
return FeaturePtr(new SketchPlugin_Arc);
+ } else if (theFeatureID == SketchPlugin_BSpline::ID()) {
+ return FeaturePtr(new SketchPlugin_BSpline);
+ } else if (theFeatureID == SketchPlugin_BSplinePeriodic::ID()) {
+ return FeaturePtr(new SketchPlugin_BSplinePeriodic);
} else if (theFeatureID == SketchPlugin_Projection::ID()) {
return FeaturePtr(new SketchPlugin_Projection);
} else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
return FeaturePtr(new SketchPlugin_Trim);
} else if (theFeatureID == SketchPlugin_MacroArc::ID()) {
return FeaturePtr(new SketchPlugin_MacroArc);
+ } else if (theFeatureID == SketchPlugin_MacroBSpline::ID()) {
+ return FeaturePtr(new SketchPlugin_MacroBSpline);
+ } else if (theFeatureID == SketchPlugin_MacroBSplinePeriodic::ID()) {
+ return FeaturePtr(new SketchPlugin_MacroBSplinePeriodic);
} else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
return FeaturePtr(new SketchPlugin_MacroCircle);
} else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_BSpline::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_BSplinePeriodic::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Split::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_MacroBSpline::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_MacroBSplinePeriodic::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
#include <SketchPlugin_Projection.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_AttributeSelection.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
#include <Events_Loop.h>
+#include <GeomAPI_BSpline.h>
#include <GeomAPI_Circ.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Ellipse.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_Projection.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <cmath>
return aProj;
}
+static const std::set<std::string>& BSPLINE_PROJECTION()
+{
+ static std::set<std::string> aProj;
+ if (aProj.empty()) {
+ aProj.insert(SketchPlugin_BSpline::ID());
+ aProj.insert(SketchPlugin_BSplinePeriodic::ID());
+ }
+ return aProj;
+}
+
static const std::set<std::string>& possibleProjectionTypes(GeomEdgePtr theEdge,
GeomVertexPtr theVertex)
else
return ARC_PROJECTION();
}
+ else
+ return BSPLINE_PROJECTION();
}
static const std::set<std::string> DUMMY;
return DUMMY;
// if the type of feature differs with already selected, remove it and create once again
bool isRebuild = rebuildProjectedFeature(aProjection, aProjType);
- std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
-
ResultConstructionPtr aResult =
std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
keepCurrentFeature();
- if (aVertex) {
- std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(aVertex->point());
- std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
+ bool isProjected = false;
+ if (aVertex)
+ isProjected = projectPoint(aProjection, aVertex->point());
+ else
+ isProjected = projectEdge(aProjection, anEdge);
- rebuildProjectedFeature(aProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
-
- // update coordinates of projection
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
- }
- else if (anEdge->isLine()) {
- std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
- std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
-
- std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
- std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
- if (aFirstInSketch->distance(aLastInSketch) < tolerance)
- return; // line is semi-orthogonal to the sketch plane
-
- rebuildProjectedFeature(aProjection, LINE_PROJECTION(), SketchPlugin_Line::ID());
-
- // update attributes of projection
- std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Line::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Line::END_ID()));
- aStartPnt->setValue(aFirstInSketch);
- aEndPnt->setValue(aLastInSketch);
- }
- else if (anEdge->isCircle() || anEdge->isArc() || anEdge->isEllipse()) {
- GeomAlgoAPI_Projection aProjAlgo(aSketchPlane);
- GeomCurvePtr aProjectedCurve = aProjAlgo.project(anEdge);
-
- if (aProjectedCurve->isCircle()) {
- GeomAPI_Circ aCircle(aProjectedCurve);
- GeomPointPtr aCenter = aSketchPlane->project(aCircle.center());
- GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
-
- if (aProjectedCurve->isTrimmed()) {
- // ARC is a projection
- rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
-
- GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam());
- GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam());
- GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst));
- GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast));
-
- double aNormalsDot = aCircle.normal()->dot(aSketchPlane->direction());
- if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
- return; // arc is not in the plane, parallel to the sketch plane
-
- bool isInversed = aNormalsDot < 0.;
-
- bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true);
-
- // update attributes of projection
- std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Arc::END_ID()));
- aStartPnt->setValue(aFirstInSketch);
- aEndPnt->setValue(aLastInSketch);
- aCenterPnt->setValue(aCenterInSketch);
- aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
-
- aProjection->data()->blockSendAttributeUpdated(aWasBlocked);
- }
- else {
- // CIRCLE is a projection
- rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(),
- SketchPlugin_Circle::ID());
-
- // update attributes of projection
- std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
- aCenterPnt->setValue(aCenterInSketch);
- aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
- }
- }
- else if (aProjectedCurve->isEllipse()) {
- GeomAPI_Ellipse anEllipse(aProjectedCurve);
- GeomPointPtr aCenter = aSketchPlane->project(anEllipse.center());
- GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
- GeomPointPtr aFocus = aSketchPlane->project(anEllipse.firstFocus());
- GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
-
- if (aProjectedCurve->isTrimmed()) {
- // ELLIPTIC ARC is a projection
- rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
-
- GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam());
- GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam());
- GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst));
- GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast));
-
- double aNormalsDot = anEllipse.normal()->dot(aSketchPlane->direction());
- if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
- return; // arc is not in the plane, parallel to the sketch plane
-
- bool isInversed = aNormalsDot < 0.;
-
- bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true);
-
- // update attributes of projection
- std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
- aStartPnt->setValue(aFirstInSketch);
- aEndPnt->setValue(aLastInSketch);
- aCenterPnt->setValue(aCenterInSketch);
- aFocusPnt->setValue(aFocusInSketch);
- aProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
-
- aProjection->data()->blockSendAttributeUpdated(aWasBlocked);
- }
- else {
- // ELLIPSE is a projection
- rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(),
- SketchPlugin_Ellipse::ID());
-
- // update attributes of projection
- std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
- aCenterPnt->setValue(aCenterInSketch);
- std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
- aFocusPnt->setValue(aFocusInSketch);
- aProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(
- anEllipse.minorRadius());
- }
- }
- else
- return;
- } else
- return;
+ if (!isProjected)
+ return; // projection is not computed, stop processing
aProjection->boolean(COPY_ID())->setValue(true);
aProjection->execute();
theProjection = sketch()->addFeature(theRequestedFeature);
return isRebuild;
}
+
+bool SketchPlugin_Projection::projectPoint(FeaturePtr& theProjection, const GeomPointPtr& thePoint)
+{
+ std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+ std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(thePoint);
+ std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
+
+ rebuildProjectedFeature(theProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
+
+ // update coordinates of projection
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
+ return true;
+}
+
+bool SketchPlugin_Projection::projectSegment(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
+{
+ std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+ std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(theEdge->firstPoint());
+ std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(theEdge->lastPoint());
+
+ std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
+ std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
+ if (aFirstInSketch->distance(aLastInSketch) < tolerance)
+ return false; // line is semi-orthogonal to the sketch plane
+
+ rebuildProjectedFeature(theProjection, LINE_PROJECTION(), SketchPlugin_Line::ID());
+
+ // update attributes of projection
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Line::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Line::END_ID()));
+ aStartPnt->setValue(aFirstInSketch);
+ aEndPnt->setValue(aLastInSketch);
+
+ return true;
+}
+
+bool SketchPlugin_Projection::projectEdge(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
+{
+ if (theEdge->isLine())
+ return projectSegment(theProjection, theEdge);
+
+ std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+ GeomAlgoAPI_Projection aProjAlgo(aSketchPlane);
+ GeomCurvePtr aProjectedCurve = aProjAlgo.project(theEdge);
+
+ bool isOk = false;
+ if (aProjectedCurve->isCircle()) {
+ if (aProjectedCurve->isTrimmed()) {
+ // ARC is a projection
+ isOk = fillArc(theProjection, aProjectedCurve, aSketchPlane);
+ }
+ else {
+ // CIRCLE is a projection
+ isOk = fillCircle(theProjection, aProjectedCurve, aSketchPlane);
+ }
+ }
+ else if (aProjectedCurve->isEllipse()) {
+ if (aProjectedCurve->isTrimmed()) {
+ // ELLIPTIC ARC is a projection
+ isOk = fillEllipticArc(theProjection, aProjectedCurve, aSketchPlane);
+ }
+ else {
+ // ELLIPSE is a projection
+ isOk = fillEllipse(theProjection, aProjectedCurve, aSketchPlane);
+ }
+ }
+ else
+ isOk = fillBSpline(theProjection, aProjectedCurve, aSketchPlane);
+
+ return isOk;
+}
+
+bool SketchPlugin_Projection::fillArc(FeaturePtr& theProjection,
+ const GeomCurvePtr& theArc,
+ const GeomPlanePtr& thePlane)
+{
+ rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
+
+ GeomAPI_Circ aCircle(theArc);
+
+ double aNormalsDot = aCircle.normal()->dot(thePlane->direction());
+ if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
+ return false; // arc is not in the plane, parallel to the sketch plane
+
+ bool isInversed = aNormalsDot < 0.;
+
+ GeomPointPtr aCenter = thePlane->project(aCircle.center());
+ GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
+
+ GeomPointPtr aFirst = theArc->getPoint(theArc->startParam());
+ GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
+
+ GeomPointPtr aLast = theArc->getPoint(theArc->endParam());
+ GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
+
+ bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
+
+ // update attributes of projection
+ std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Arc::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Arc::END_ID()));
+ aStartPnt->setValue(aFirstInSketch);
+ aEndPnt->setValue(aLastInSketch);
+ aCenterPnt->setValue(aCenterInSketch);
+ theProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
+
+ theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
+ return true;
+}
+
+bool SketchPlugin_Projection::fillCircle(FeaturePtr& theProjection,
+ const GeomCurvePtr& theCircle,
+ const GeomPlanePtr& thePlane)
+{
+ rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Circle::ID());
+
+ GeomAPI_Circ aCircle(theCircle);
+ GeomPointPtr aCenter = thePlane->project(aCircle.center());
+ GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
+
+ // update attributes of projection
+ std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
+ aCenterPnt->setValue(aCenterInSketch);
+ theProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
+ return true;
+}
+
+bool SketchPlugin_Projection::fillEllipse(FeaturePtr& theProjection,
+ const GeomCurvePtr& theEllipse,
+ const GeomPlanePtr& thePlane)
+{
+ rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Ellipse::ID());
+
+ GeomAPI_Ellipse anEllipse(theEllipse);
+ GeomPointPtr aCenter = thePlane->project(anEllipse.center());
+ GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
+ GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
+ GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
+
+ // update attributes of projection
+ std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
+ aCenterPnt->setValue(aCenterInSketch);
+ std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
+ aFocusPnt->setValue(aFocusInSketch);
+ theProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipse.minorRadius());
+ return true;
+}
+
+bool SketchPlugin_Projection::fillEllipticArc(FeaturePtr& theProjection,
+ const GeomCurvePtr& theEllipticArc,
+ const GeomPlanePtr& thePlane)
+{
+ rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
+
+ GeomAPI_Ellipse anEllipse(theEllipticArc);
+
+ double aNormalsDot = anEllipse.normal()->dot(thePlane->direction());
+ if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
+ return false; // arc is not in the plane, parallel to the sketch plane
+
+ bool isInversed = aNormalsDot < 0.;
+
+ GeomPointPtr aCenter = thePlane->project(anEllipse.center());
+ GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
+ GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
+ GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
+
+ GeomPointPtr aFirst = theEllipticArc->getPoint(theEllipticArc->startParam());
+ GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
+ GeomPointPtr aLast = theEllipticArc->getPoint(theEllipticArc->endParam());
+ GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
+
+ bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
+
+ // update attributes of projection
+ std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+ aStartPnt->setValue(aFirstInSketch);
+ aEndPnt->setValue(aLastInSketch);
+ aCenterPnt->setValue(aCenterInSketch);
+ aFocusPnt->setValue(aFocusInSketch);
+ theProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
+
+ theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
+ return true;
+}
+
+bool SketchPlugin_Projection::fillBSpline(FeaturePtr& theProjection,
+ const GeomCurvePtr& theCurve,
+ const GeomPlanePtr& thePlane)
+{
+ GeomAPI_BSpline aBSpline(theCurve);
+
+ rebuildProjectedFeature(theProjection, BSPLINE_PROJECTION(),
+ aBSpline.isPeriodic() ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ theProjection->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree());
+
+ AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ theProjection->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 =
+ theProjection->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 =
+ theProjection->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 =
+ theProjection->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);
+
+ return true;
+}
#include "SketchPlugin_SketchEntity.h"
+class GeomAPI_Curve;
+
/** \class SketchPlugin_Projection
* \ingroup Plugins
* \brief Feature for creation of external feature as a projection onto the sketch plane.
/// \brief Find projection of a feature onto sketch plane
void computeProjection(const std::string& theID);
+ /// \brief Project point to the sketch plane
+ bool projectPoint(FeaturePtr& theProjection, const std::shared_ptr<GeomAPI_Pnt>& thePoint);
+ /// \brief Project segment to the sketch plane
+ bool projectSegment(FeaturePtr& theProjection, const std::shared_ptr<GeomAPI_Edge>& theEdge);
+ /// \brief Project any edge to sketch plane
+ bool projectEdge(FeaturePtr& theProjection, const std::shared_ptr<GeomAPI_Edge>& theEdge);
+
+ /// \brief Fill attributes of the Arc feature
+ bool fillArc(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theArc,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the Circle feature
+ bool fillCircle(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theCircle,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the Ellipse feature
+ bool fillEllipse(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theEllipse,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the EllipticArc feature
+ bool fillEllipticArc(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theEllipticArc,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the B-spline feature
+ bool fillBSpline(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theCurve,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+
/// \brief Delete already calculated projected feature
/// if the selection of the projection is changed
/// \param[in/out] theProjection projected feature
aRefsToParent.push_back(*aRef);
}
for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
- aRef != aRefsToParent.end(); ++aRef)
- std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(theSplitFeature);
+ aRef != aRefsToParent.end(); ++aRef) {
+ std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(
+ theBaseFeatureModified);
+
+ FeaturePtr anOwner = ModelAPI_Feature::feature((*aRef)->owner());
+ SketchPlugin_Tools::replaceInName(anOwner,
+ aBaseFeature->name(), theBaseFeatureModified->name());
+ SketchPlugin_Tools::replaceInName(anOwner->lastResult(),
+ aBaseFeature->name(), theBaseFeatureModified->name());
+ }
}
theCreatedFeatures.insert(theBaseFeatureModified);
theDimPrs->setColor(aColor[0], aColor[1], aColor[2]);
}
+void replaceInName(ObjectPtr theObject, const std::string& theSource, const std::string& theDest)
+{
+ std::string aName = theObject->data()->name();
+ size_t aPos = aName.find(theSource);
+ if (aPos != std::string::npos) {
+ std::string aNewName = aName.substr(0, aPos) + theDest
+ + aName.substr(aPos + theSource.size());
+ theObject->data()->setName(aNewName);
+ }
+}
+
} // namespace SketchPlugin_Tools
void setDimensionColor(const AISObjectPtr& theDimPrs);
+/// Replace string in the name of object
+void replaceInName(ObjectPtr theObject, const std::string& theSource, const std::string& theDest);
+
}; // namespace SketchPlugin_Tools
namespace SketchPlugin_SegmentationTools
aRefsToParent.push_back(*aRef);
}
for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
- aRef != aRefsToParent.end(); ++aRef)
+ aRef != aRefsToParent.end(); ++aRef) {
std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(anNewFeature);
+
+ FeaturePtr anOwner = ModelAPI_Feature::feature((*aRef)->owner());
+ SketchPlugin_Tools::replaceInName(anOwner, aBaseFeature->name(), anNewFeature->name());
+ SketchPlugin_Tools::replaceInName(anOwner->lastResult(),
+ aBaseFeature->name(), anNewFeature->name());
+ }
}
const std::string& aStartAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
#include <GeomAPI_Lin.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Vertex.h>
+
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <algorithm>
#include <cmath>
}
AttributeReferencePtr aFeatureAttr =
std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
+ std::shared_ptr<SketchPlugin_Feature> aSplitFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
ObjectPtr anAttrObject = aFeatureAttr->value();
+ if (!anAttrObject) {
+ AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
+ aFeatureAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
+ anAttrObject = aFeatureAttr->value();
+ }
+
FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
if (!anAttrFeature)
return aValid;
std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
+ bool aValid = true;
if (anEdge->isLine()) {
std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
double aDot = fabs(aNormal->dot(aLineDir));
- bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
+ aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
if (!aValid)
theError = "Error: Line is orthogonal to the sketch plane.";
- return aValid;
}
else if (anEdge->isCircle() || anEdge->isArc()) {
std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
double aDot = fabs(aNormal->dot(aCircNormal));
- bool aValid = aDot >= tolerance * tolerance;
+ aValid = aDot >= tolerance * tolerance;
if (!aValid)
theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
: "Error: Arc is orthogonal to the sketch plane.");
- return aValid;
}
else if (anEdge->isEllipse()) {
std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
double aDot = fabs(aNormal->dot(anEllipseNormal));
- bool aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
+ aValid = fabs(aDot - 1.0) <= 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 aValid;
}
- theError = "Error: Selected object is not supported for projection.";
- return false;
+ return aValid;
}
return true;
}
+
+bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPolesArray)
+ return false;
+
+ if (aPolesArray->size() < 2) {
+ theError = "Number of B-spline poles should be 2 or more";
+ return false;
+ }
+
+ return true;
+}
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_BSplineValidator
+ * \ingroup Validators
+ * \brief Validator for checking poles/weights of B-spline curve.
+ */
+class SketchPlugin_BSplineValidator : public ModelAPI_AttributeValidator
+{
+ //! returns true if attribute is valid
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute
+ //! \param theError error message
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
#endif
<source>Sketch</source>
<translation>Esquisse</translation>
</message>
+ <message>
+ <source><b>The constraint is conflicting with others. To fix this, you can either <font color='red'>undo (Ctrl+Z)</font> your operation or <font color='red'>remove</font> a conflicting constraint.</b></source>
+ <translation><b>La contrainte est en conflit avec d'autres. Pour y remédier, vous pouvez soit <font color='red'>annuler (Ctrl+Z)</font> votre opération, soit <font color='red'>supprimer</font> une contrainte conflictuelle.</b></translation>
+ </message>
</context>
<context>
<name>Sketch:External</name>
<source>The constraint is conflicting with others. To fix this, you can either undo your operation or remove a conflicting constraint.</source>
<translation>La contrainte est en conflit avec les autres. Pour résoudre ce problème, vous pouvez annuler votre opération ou supprimer une contrainte en conflit.</translation>
</message>
- </context>
- <context>
- <name>Sketch:SketchPlugin_SolverErrorValidator</name>
<message>
<source>The set of constraints lead to degenerated geometry. To fix this, you can either undo your operation or remove a constraint or the degenerated geometry.</source>
<translation>L'ensemble des contraintes conduit à une géométrie dégénérée. Pour résoudre ce problème, vous pouvez annuler votre opération ou supprimer une contrainte ou la géométrie dégénérée..</translation>
</message>
+ <message>
+ <source><b>The constraint is conflicting with others. To fix this, you can either <font color='red'>undo (Ctrl+Z)</font> your operation or <font color='red'>remove</font> a conflicting constraint.</b></source>
+ <translation><b>La contrainte est en conflit avec d'autres. Pour y remédier, vous pouvez soit <font color='red'>annuler (Ctrl+Z)</font> votre opération, soit <font color='red'>supprimer</font> une contrainte conflictuelle.</b></translation>
+ </message>
</context>
<context>
<translation>Type d'angle</translation>
</message>
<message>
- <source>Complementary</source>
- <translation>Complémentaire</translation>
+ <source>Supplementary</source>
+ <translation>Supplémentaire</translation>
</message>
<message>
<source>Direct</source>
</message>
</context>
+ <context>
+ <name>SketchBSpline</name>
+ <message>
+ <source>Number of B-spline poles should be 2 or more</source>
+ <translation>Le nombre de pôles B-spline doit être de 2 ou plus</translation>
+ </message>
+ </context>
+
</TS>
Events_Loop.loop().flush(event);
assert(listener.myEventProcessed)
+ # explicitly remove the listener to improve code coverage
+ listener.__del__()
Events_Loop.loop().flush(event);
assert(listener.myEventProcessed)
+ # explicitly remove the listener to improve code coverage
+ listener.__del__()
--- /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 *
+import math
+
+ELL_CENTER_X = 10
+ELL_CENTER_Y = 10
+ELL_MAJOR_RAD = 30
+ELL_MINOR_RAD = 15
+DOF_1 = 5
+DOF_2 = 9
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipse_1 = Sketch_1.addEllipse(ELL_CENTER_X, ELL_CENTER_Y, ELL_CENTER_X + math.sqrt(ELL_MAJOR_RAD**2 + ELL_MINOR_RAD**2), ELL_CENTER_Y, ELL_MINOR_RAD)
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchLine_1, SketchLine_2] = SketchEllipse_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+assert(model.dof(Sketch_1) == DOF_1)
+
+# trim the ellipse
+ANGLE = math.pi/4
+Sketch_1.addTrim(SketchEllipse_1.feature(), GeomAPI_Pnt2d(ELL_CENTER_X + ELL_MAJOR_RAD * math.cos(ANGLE), ELL_CENTER_Y + ELL_MINOR_RAD * math.sin(ANGLE)))
+model.do()
+assert(model.dof(Sketch_1) == DOF_1)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipse_2 = Sketch_2.addEllipse(ELL_CENTER_X, ELL_CENTER_Y, ELL_CENTER_X + math.sqrt(ELL_MAJOR_RAD**2 + ELL_MINOR_RAD**2), ELL_CENTER_Y, ELL_MINOR_RAD)
+[SketchPoint_8, SketchPoint_9, SketchPoint_10, SketchPoint_11, SketchPoint_12, SketchPoint_13, SketchPoint_14, SketchLine_3, SketchLine_4] = SketchEllipse_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+SketchLine_5 = Sketch_2.addLine(15.23538168732762, 24.77570901315218, 37.44845404222143, 43.05543771157006)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_5.startPoint(), SketchEllipse_2.result())
+SketchLine_6 = Sketch_2.addLine(37.44845404222143, 43.05543771157006, 37.66137837703927, 15.83721541173749)
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchEllipse_2.result())
+model.do()
+assert(model.dof(Sketch_2) == DOF_2)
+
+# split the ellipse
+Sketch_2.addSplit(SketchEllipse_2.feature(), GeomAPI_Pnt2d(ELL_CENTER_X + ELL_MAJOR_RAD * math.cos(ANGLE), ELL_CENTER_Y + ELL_MINOR_RAD * math.sin(ANGLE)))
+DOF_2 += 3
+model.do()
+assert(model.dof(Sketch_2) == DOF_2)
+
+
+model.end()
+
+assert(model.checkPythonDump())
#=========================================================================
# of the test
#=========================================================================
+from GeomAPI import *
from GeomDataAPI import *
from ModelAPI import *
import math
--- /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 for adding a pole to already created B-spline curve
+"""
+
+from salome.shaper import model
+from GeomAPI import *
+import random
+
+TOLERANCE = 1.e-7
+
+def assertSubFeatures(theSketch, theNbPoints, theNbLines, theNbSplines, theNbSplinesP, theNbCoincidences, theNbInternal):
+ model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+ model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+ model.testNbSubFeatures(theSketch, "SketchBSpline", theNbSplines)
+ model.testNbSubFeatures(theSketch, "SketchBSplinePeriodic", theNbSplinesP)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidence", theNbCoincidences)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternal)
+
+def assertPoles(thePoles, theReference):
+ assert(thePoles.size() == len(theReference))
+ for ind in range(0, len(theReference)):
+ pole = thePoles.pnt(ind)
+ ref = GeomAPI_Pnt2d(theReference[ind][0], theReference[ind][1])
+ assert(model.distancePointPoint(pole, ref) < TOLERANCE), "Index = {}, pole = ({}, {}), refdata = ({}, {})".format(ind, pole.x(), pole.y(), ref.x(), ref.y())
+
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+SketchBSpline_1_poles = [(-25, 5), (-15, 35), (15, 35), (28, 5)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4] = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3])
+[SketchLine_1, SketchLine_2, SketchLine_3] = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2])
+
+SketchBSplinePeriodic_1_poles = [(-20, -10), (20, -40), (20, -10), (-20, -40)]
+SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, periodic = True)
+[SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchPoint_8] = SketchBSplinePeriodic_1.controlPoles(auxiliary = [0, 1, 2, 3])
+[SketchLine_4, SketchLine_5, SketchLine_6, SketchLine_7] = SketchBSplinePeriodic_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+model.do()
+
+# check original values
+NBPOINTS = 8
+NBLINES = 7
+NBSPLINES = 1
+NBSPLINESPERIODIC = 1
+NBCOINCIDENCES = 0
+NBINTERNAL = 22
+assertSubFeatures(Sketch_1, NBPOINTS, NBLINES, NBSPLINES, NBSPLINESPERIODIC, NBCOINCIDENCES, NBINTERNAL)
+assertPoles(SketchBSpline_1.poles(), SketchBSpline_1_poles)
+assertPoles(SketchBSplinePeriodic_1.poles(), SketchBSplinePeriodic_1_poles)
+
+# add poles to non-periodic B-spline
+ind = 0
+while ind < len(SketchBSpline_1_poles):
+ x = random.uniform(-25, 25)
+ y = random.uniform(5, 40)
+ SketchBSpline_1.insertPole(ind, GeomAPI_Pnt2d(x, y))
+ if ind + 1 < len(SketchBSpline_1_poles):
+ SketchBSpline_1_poles.insert(ind + 1, (x, y))
+ else:
+ SketchBSpline_1_poles.insert(len(SketchBSpline_1_poles) - 1, (x, y))
+ ind += 2
+ model.do()
+
+ NBPOINTS += 1
+ NBLINES += 1
+ NBINTERNAL += 3
+ assertSubFeatures(Sketch_1, NBPOINTS, NBLINES, NBSPLINES, NBSPLINESPERIODIC, NBCOINCIDENCES, NBINTERNAL)
+ assertPoles(SketchBSpline_1.poles(), SketchBSpline_1_poles)
+
+# add poles to periodic B-spline
+ind = 0
+while ind < len(SketchBSplinePeriodic_1_poles):
+ x = random.uniform(-25, 25)
+ y = random.uniform(-45, -5)
+ SketchBSplinePeriodic_1.insertPole(ind, GeomAPI_Pnt2d(x, y))
+ SketchBSplinePeriodic_1_poles.insert(ind + 1, (x, y))
+ ind += 2
+ model.do()
+
+ NBPOINTS += 1
+ NBLINES += 1
+ NBINTERNAL += 3
+ assertSubFeatures(Sketch_1, NBPOINTS, NBLINES, NBSPLINES, NBSPLINESPERIODIC, NBCOINCIDENCES, NBINTERNAL)
+ assertPoles(SketchBSplinePeriodic_1.poles(), SketchBSplinePeriodic_1_poles)
+
+model.end()
+
+# check error on incorrect action
+model.begin()
+assert(not SketchBSpline_1.feature().customAction("wrong_action"))
+model.end()
+
+#assert(model.checkPythonDump())
--- /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
+#
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2019-12-12"
+
+ANGLE_DIRECT = 0
+ANGLE_COMPLEMENTARY = 1
+ANGLE_BACKWARD = 2
+
+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()
+#=========================================================================
+# Create two lines
+#=========================================================================
+aSession.startOperation()
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aStartPointA = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aEndPointA = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aStartPointA.setValue(-100., 25.)
+aEndPointA.setValue(100., -25.)
+
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aStartPointB = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aEndPointB = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aStartPointB.setValue(-100., -25.)
+aEndPointB.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make a constraint to keep the angle
+#=========================================================================
+ANGLE_DEGREE = 330.
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintAngle")
+anAngleType = aConstraint.integer("AngleType")
+anAngleType.setValue(ANGLE_DIRECT)
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointA")).setValue(aStartPointA.pnt())
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointB")).setValue(aStartPointB.pnt())
+aConstraint.refattr("ConstraintEntityA").setObject(aSketchLineA.firstResult())
+aConstraint.refattr("ConstraintEntityB").setObject(aSketchLineB.firstResult())
+anAngleVal = aConstraint.real("AngleValue")
+anAngleVal.setValue(360. - ANGLE_DEGREE)
+aSession.finishOperation()
+#=========================================================================
+# Change the type of the constraint
+#=========================================================================
+aSession.startOperation()
+anAngleType.setValue(ANGLE_BACKWARD)
+aSession.finishOperation()
+#=========================================================================
+# Move presentation of the angle and check the angle value
+#=========================================================================
+pointsA = [aStartPointA.pnt(), aEndPointA.pnt()]
+pointsB = [aStartPointB.pnt(), aEndPointB.pnt()]
+refs = [(pointsA[0], pointsB[1], 540. - ANGLE_DEGREE),
+ (pointsA[1], pointsB[1], ANGLE_DEGREE),
+ (pointsA[1], pointsB[0], 540. - ANGLE_DEGREE),
+ (pointsA[0], pointsB[0], ANGLE_DEGREE)
+ ]
+aFlyoutPoint = geomDataAPI_Point2D(aConstraint.attribute("ConstraintFlyoutValuePnt"))
+for ref in refs:
+ aSession.startOperation()
+ aFlyoutPoint.setValue(0.5 * (ref[0].x() + ref[1].x()), 0.5 * (ref[0].y() + ref[1].y()))
+ aSession.finishOperation()
+ assert(anAngleType.value() == ANGLE_BACKWARD)
+ assert(anAngleVal.value() == ref[2])
+ assert(aStartPointA.x() == pointsA[0].x() and aStartPointA.y() == pointsA[0].y())
+ assert(aEndPointA.x() == pointsA[1].x() and aEndPointA.y() == pointsA[1].y())
+ assert(aStartPointB.x() == pointsB[0].x() and aStartPointB.y() == pointsB[0].y())
+ assert(aEndPointB.x() == pointsB[1].x() and aEndPointB.y() == pointsB[1].y())
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2019-12-12"
+
+ANGLE_DIRECT = 0
+ANGLE_COMPLEMENTARY = 1
+ANGLE_BACKWARD = 2
+
+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()
+#=========================================================================
+# Create two lines
+#=========================================================================
+aSession.startOperation()
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aStartPointA = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aEndPointA = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aStartPointA.setValue(-100., 25.)
+aEndPointA.setValue(100., -25.)
+
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aStartPointB = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aEndPointB = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aStartPointB.setValue(-100., -25.)
+aEndPointB.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make a constraint to keep the angle
+#=========================================================================
+ANGLE_DEGREE = 330.
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintAngle")
+anAngleType = aConstraint.integer("AngleType")
+anAngleType.setValue(ANGLE_BACKWARD)
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointA")).setValue(aStartPointA.pnt())
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointB")).setValue(aStartPointB.pnt())
+aConstraint.refattr("ConstraintEntityA").setObject(aSketchLineA.firstResult())
+aConstraint.refattr("ConstraintEntityB").setObject(aSketchLineB.firstResult())
+anAngleVal = aConstraint.real("AngleValue")
+anAngleVal.setValue(ANGLE_DEGREE)
+aSession.finishOperation()
+#=========================================================================
+# Move presentation of the angle and check the angle value
+#=========================================================================
+pointsA = [aStartPointA.pnt(), aEndPointA.pnt()]
+pointsB = [aStartPointB.pnt(), aEndPointB.pnt()]
+refs = [(pointsA[0], pointsB[1], 540. - ANGLE_DEGREE),
+ (pointsA[1], pointsB[1], ANGLE_DEGREE),
+ (pointsA[1], pointsB[0], 540. - ANGLE_DEGREE),
+ (pointsA[0], pointsB[0], ANGLE_DEGREE)
+ ]
+aFlyoutPoint = geomDataAPI_Point2D(aConstraint.attribute("ConstraintFlyoutValuePnt"))
+for ref in refs:
+ aSession.startOperation()
+ aFlyoutPoint.setValue(0.5 * (ref[0].x() + ref[1].x()), 0.5 * (ref[0].y() + ref[1].y()))
+ aSession.finishOperation()
+ assert(anAngleType.value() == ANGLE_BACKWARD)
+ assert(anAngleVal.value() == ref[2])
+ assert(aStartPointA.x() == pointsA[0].x() and aStartPointA.y() == pointsA[0].y())
+ assert(aEndPointA.x() == pointsA[1].x() and aEndPointA.y() == pointsA[1].y())
+ assert(aStartPointB.x() == pointsB[0].x() and aStartPointB.y() == pointsB[0].y())
+ assert(aEndPointB.x() == pointsB[1].x() and aEndPointB.y() == pointsB[1].y())
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2019-12-12"
+
+ANGLE_DIRECT = 0
+ANGLE_COMPLEMENTARY = 1
+ANGLE_BACKWARD = 2
+
+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()
+#=========================================================================
+# Create two lines
+#=========================================================================
+aSession.startOperation()
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aStartPointA = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aEndPointA = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aStartPointA.setValue(-100., 25.)
+aEndPointA.setValue(100., -25.)
+
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aStartPointB = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aEndPointB = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aStartPointB.setValue(-100., -25.)
+aEndPointB.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make a constraint to keep the angle
+#=========================================================================
+ANGLE_DEGREE = 30.
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintAngle")
+anAngleType = aConstraint.integer("AngleType")
+anAngleType.setValue(ANGLE_DIRECT)
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointA")).setValue(aStartPointA.pnt())
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointB")).setValue(aStartPointB.pnt())
+aConstraint.refattr("ConstraintEntityA").setObject(aSketchLineA.firstResult())
+aConstraint.refattr("ConstraintEntityB").setObject(aSketchLineB.firstResult())
+anAngleVal = aConstraint.real("AngleValue")
+anAngleVal.setValue(ANGLE_DEGREE)
+aSession.finishOperation()
+#=========================================================================
+# Move presentation of the angle and check the angle value
+#=========================================================================
+pointsA = [aStartPointA.pnt(), aEndPointA.pnt()]
+pointsB = [aStartPointB.pnt(), aEndPointB.pnt()]
+refs = [(pointsA[0], pointsB[1], 180. - ANGLE_DEGREE),
+ (pointsA[1], pointsB[1], ANGLE_DEGREE),
+ (pointsA[1], pointsB[0], 180. - ANGLE_DEGREE),
+ (pointsA[0], pointsB[0], ANGLE_DEGREE)
+ ]
+aFlyoutPoint = geomDataAPI_Point2D(aConstraint.attribute("ConstraintFlyoutValuePnt"))
+for ref in refs:
+ aSession.startOperation()
+ aFlyoutPoint.setValue(0.5 * (ref[0].x() + ref[1].x()), 0.5 * (ref[0].y() + ref[1].y()))
+ aSession.finishOperation()
+ assert(anAngleType.value() == ANGLE_DIRECT)
+ assert(anAngleVal.value() == ref[2])
+ assert(aStartPointA.x() == pointsA[0].x() and aStartPointA.y() == pointsA[0].y())
+ assert(aEndPointA.x() == pointsA[1].x() and aEndPointA.y() == pointsA[1].y())
+ assert(aStartPointB.x() == pointsB[0].x() and aStartPointB.y() == pointsB[0].y())
+ assert(aEndPointB.x() == pointsB[1].x() and aEndPointB.y() == pointsB[1].y())
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2019-12-12"
+
+ANGLE_DIRECT = 0
+ANGLE_COMPLEMENTARY = 1
+ANGLE_BACKWARD = 2
+
+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()
+#=========================================================================
+# Create two lines
+#=========================================================================
+aSession.startOperation()
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aStartPointA = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aEndPointA = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aStartPointA.setValue(-100., 25.)
+aEndPointA.setValue(100., -25.)
+
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aStartPointB = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aEndPointB = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aStartPointB.setValue(-100., -25.)
+aEndPointB.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make a constraint to keep the angle
+#=========================================================================
+ANGLE_DEGREE = 30.
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintAngle")
+anAngleType = aConstraint.integer("AngleType")
+anAngleType.setValue(ANGLE_DIRECT)
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointA")).setValue(aStartPointA.pnt())
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointB")).setValue(aStartPointB.pnt())
+aConstraint.refattr("ConstraintEntityA").setObject(aSketchLineA.firstResult())
+aConstraint.refattr("ConstraintEntityB").setObject(aSketchLineB.firstResult())
+anAngleVal = aConstraint.real("AngleValue")
+anAngleVal.setValue(ANGLE_DEGREE)
+aSession.finishOperation()
+#=========================================================================
+# Change the type of the constraint
+#=========================================================================
+aSession.startOperation()
+anAngleType.setValue(ANGLE_COMPLEMENTARY)
+aSession.finishOperation()
+#=========================================================================
+# Move presentation of the angle and check the angle value
+#=========================================================================
+pointsA = [aStartPointA.pnt(), aEndPointA.pnt()]
+pointsB = [aStartPointB.pnt(), aEndPointB.pnt()]
+refs = [(pointsA[0], pointsB[0], ANGLE_DEGREE),
+ (pointsA[0], pointsB[1], 180. - ANGLE_DEGREE),
+ (pointsA[1], pointsB[1], ANGLE_DEGREE),
+ (pointsA[1], pointsB[0], 180. - ANGLE_DEGREE),
+ ]
+aFlyoutPoint = geomDataAPI_Point2D(aConstraint.attribute("ConstraintFlyoutValuePnt"))
+for ref in refs:
+ aSession.startOperation()
+ aFlyoutPoint.setValue(0.5 * (ref[0].x() + ref[1].x()), 0.5 * (ref[0].y() + ref[1].y()))
+ aSession.finishOperation()
+ assert(anAngleType.value() == ANGLE_COMPLEMENTARY)
+ assert(anAngleVal.value() == ref[2])
+ assert(aStartPointA.x() == pointsA[0].x() and aStartPointA.y() == pointsA[0].y())
+ assert(aEndPointA.x() == pointsA[1].x() and aEndPointA.y() == pointsA[1].y())
+ assert(aStartPointB.x() == pointsB[0].x() and aStartPointB.y() == pointsB[0].y())
+ assert(aEndPointB.x() == pointsB[1].x() and aEndPointB.y() == pointsB[1].y())
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2019-12-12"
+
+ANGLE_DIRECT = 0
+ANGLE_COMPLEMENTARY = 1
+ANGLE_BACKWARD = 2
+
+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()
+#=========================================================================
+# Create two lines
+#=========================================================================
+aSession.startOperation()
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aStartPointA = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aEndPointA = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aStartPointA.setValue(-100., 25.)
+aEndPointA.setValue(100., -25.)
+
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aStartPointB = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aEndPointB = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aStartPointB.setValue(-100., -25.)
+aEndPointB.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make a constraint to keep the angle
+#=========================================================================
+ANGLE_DEGREE = 30.
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintAngle")
+anAngleType = aConstraint.integer("AngleType")
+anAngleType.setValue(ANGLE_COMPLEMENTARY)
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointA")).setValue(aStartPointA.pnt())
+geomDataAPI_Point2D(aConstraint.attribute("SelectedPointB")).setValue(aStartPointB.pnt())
+aConstraint.refattr("ConstraintEntityA").setObject(aSketchLineA.firstResult())
+aConstraint.refattr("ConstraintEntityB").setObject(aSketchLineB.firstResult())
+anAngleVal = aConstraint.real("AngleValue")
+anAngleVal.setValue(ANGLE_DEGREE)
+aSession.finishOperation()
+#=========================================================================
+# Move presentation of the angle and check the angle value
+#=========================================================================
+pointsA = [aStartPointA.pnt(), aEndPointA.pnt()]
+pointsB = [aStartPointB.pnt(), aEndPointB.pnt()]
+refs = [(pointsA[0], pointsB[0], ANGLE_DEGREE),
+ (pointsA[0], pointsB[1], 180. - ANGLE_DEGREE),
+ (pointsA[1], pointsB[1], ANGLE_DEGREE),
+ (pointsA[1], pointsB[0], 180. - ANGLE_DEGREE),
+ ]
+aFlyoutPoint = geomDataAPI_Point2D(aConstraint.attribute("ConstraintFlyoutValuePnt"))
+for ref in refs:
+ aSession.startOperation()
+ aFlyoutPoint.setValue(0.5 * (ref[0].x() + ref[1].x()), 0.5 * (ref[0].y() + ref[1].y()))
+ aSession.finishOperation()
+ assert(anAngleType.value() == ANGLE_COMPLEMENTARY)
+ assert(anAngleVal.value() == ref[2])
+ assert(aStartPointA.x() == pointsA[0].x() and aStartPointA.y() == pointsA[0].y())
+ assert(aEndPointA.x() == pointsA[1].x() and aEndPointA.y() == pointsA[1].y())
+ assert(aStartPointB.x() == pointsB[0].x() and aStartPointB.y() == pointsB[0].y())
+ assert(aEndPointB.x() == pointsB[1].x() and aEndPointB.y() == pointsB[1].y())
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, 0.4653113240225388, -68.74815303974528)
+SketchLine_2 = Sketch_1.addLine(0.4653113240225388, -68.74815303974528, 8.542125432770632, -50.45156664083665)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(8.542125432770632, -50.45156664083665, -8.178735979228234, 7.171456480488104)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(-30.39232801419296, -18.99499937550162, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.endPoint())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), 220)
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 140)
+SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_4.result(), 140)
+SketchConstraintAngle_4 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_5.result(), 220)
+SketchConstraintAngle_5 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), 220)
+SketchConstraintAngle_6 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_7.result(), 140)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_4.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_5.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_6.result())
+SketchLine_8 = Sketch_1.addLine(14.775406531722, -47.38691166633646, -20.64529817713098, 1.042146531487715)
+SketchPoint_1 = Sketch_1.addPoint(2.968504962104344, -31.24389226706174)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_3.result())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_8.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.endPoint(), 40, True)
+SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_8.result())
+SketchLine_9 = Sketch_1.addLine(19.58460105006861, -42.37517030669127, -30.26368721382418, -8.981336187802668)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintEqual_6 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_9.result())
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_9.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintAngle_7 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_8.result(), 20)
+SketchConstraintAngle_8 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_8.result(), 340)
+SketchLine_10 = Sketch_1.addLine(3.875430505227681, -29.75334619738324, -48.69363438803513, -0.8311502875301234)
+SketchPoint_2 = Sketch_1.addPoint(-13.64759112585992, -20.1126142274322)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_10.result())
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_9.result())
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_10.startPoint(), 20, True)
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_9.endPoint(), 20, True)
+SketchConstraintEqual_7 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(0.001529676402264532, -26.13785899518266, -31.94417752476854, -12.03580011868412)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_11.result())
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchLine_11.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_9 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_10.result(), 185)
+SketchConstraintAngle_10 = Sketch_1.setAngle(SketchLine_11.result(), SketchLine_10.result(), 355)
+SketchLine_12 = Sketch_1.addLine(5.283311970593094, -26.56404104269606, -51.50939731876596, -7.20976059690448)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_12.result())
+SketchConstraintEqual_8 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_12.result())
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_12.startPoint(), 20, True)
+SketchConstraintAngle_11 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_11.result(), 355)
+SketchLine_13 = Sketch_1.addLine(25.19469725542325, -29.66649476390714, -33.06873531650151, -15.33567395919474)
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_13.result())
+SketchConstraintEqual_9 = Sketch_1.setEqual(SketchLine_12.result(), SketchLine_13.result())
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchLine_13.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_12 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_13.result(), 185)
+SketchLine_14 = Sketch_1.addLine(25.87956617560386, -26.24481087018098, -33.41116977659181, -17.04651590605781)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_14.result())
+SketchConstraintDistance_10 = Sketch_1.setDistance(SketchLine_14.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_13 = Sketch_1.setAngle(SketchLine_13.result(), SketchLine_14.result(), 5)
+SketchConstraintEqual_10 = Sketch_1.setEqual(SketchLine_13.result(), SketchLine_14.result())
+SketchLine_15 = Sketch_1.addLine(26.26360956157018, -22.77645725728195, -33.60319146957497, -18.78069271250733)
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_15.result())
+SketchConstraintEqual_11 = Sketch_1.setEqual(SketchLine_14.result(), SketchLine_15.result())
+SketchConstraintDistance_11 = Sketch_1.setDistance(SketchLine_15.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_14 = Sketch_1.setAngle(SketchLine_15.result(), SketchLine_14.result(), 355)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_15.result())
+
+SketchLine_16 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 78.00643494689578, -67.38706888260469)
+SketchLine_17 = Sketch_1.addLine(78.00643494689578, -67.38706888260469, 86.19687277706721, -49.141063069)
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_16.endPoint(), SketchLine_17.startPoint())
+SketchLine_18 = Sketch_1.addLine(86.19687277706721, -49.141063069, 69.83467154684908, 8.584826884311665)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_18.startPoint())
+SketchLine_19 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_16.startPoint(), SketchLine_19.startPoint())
+SketchLine_20 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_19.endPoint(), SketchLine_20.endPoint())
+SketchLine_21 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_20.startPoint(), SketchLine_21.startPoint())
+SketchLine_22 = Sketch_1.addLine(47.45878924889096, -17.44298467461911, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_21.endPoint(), SketchLine_22.endPoint())
+SketchConstraintAngle_15 = Sketch_1.setAngleComplementary(SketchLine_16.result(), SketchLine_17.result(), 40)
+SketchConstraintAngle_16 = Sketch_1.setAngleComplementary(SketchLine_18.result(), SketchLine_17.result(), 40)
+SketchConstraintAngle_17 = Sketch_1.setAngleComplementary(SketchLine_16.result(), SketchLine_19.result(), 40)
+SketchConstraintAngle_18 = Sketch_1.setAngleComplementary(SketchLine_21.result(), SketchLine_20.result(), 40)
+SketchConstraintAngle_19 = Sketch_1.setAngleComplementary(SketchLine_20.result(), SketchLine_19.result(), 40)
+SketchConstraintAngle_20 = Sketch_1.setAngleComplementary(SketchLine_21.result(), SketchLine_22.result(), 40)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_17.result(), 20)
+SketchConstraintEqual_12 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_16.result())
+SketchConstraintEqual_13 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_19.result())
+SketchConstraintEqual_14 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_20.result())
+SketchConstraintEqual_15 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_21.result())
+SketchLine_23 = Sketch_1.addLine(92.44909133742235, -46.11522988707736, 57.3302344261388, 2.533160520466375)
+SketchPoint_3 = Sketch_1.addPoint(80.74280570032784, -29.89909975122945)
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_18.result())
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_23.result())
+SketchConstraintDistance_12 = Sketch_1.setDistance(SketchLine_17.endPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_13 = Sketch_1.setDistance(SketchLine_23.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_14 = Sketch_1.setDistance(SketchPoint_3.coordinates(), SketchLine_18.endPoint(), 40, True)
+SketchConstraintEqual_16 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_23.result())
+SketchLine_24 = Sketch_1.addLine(97.289359083568, -41.13349208617944, 47.64969893384747, -7.430315081329468)
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_24.result())
+SketchConstraintEqual_17 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_24.result())
+SketchConstraintDistance_15 = Sketch_1.setDistance(SketchLine_24.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintAngle_21 = Sketch_1.setAngleComplementary(SketchLine_18.result(), SketchLine_23.result(), 160)
+SketchConstraintAngle_22 = Sketch_1.setAngleComplementary(SketchLine_24.result(), SketchLine_23.result(), 160)
+SketchLine_25 = Sketch_1.addLine(81.65898287743471, -28.41422234660911, 29.27079119639352, 0.8343224443798635)
+SketchPoint_4 = Sketch_1.addPoint(64.19625231708766, -18.66470741627946)
+SketchConstraintCoincidence_27 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_25.result())
+SketchConstraintCoincidence_28 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_24.result())
+SketchConstraintDistance_16 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_25.startPoint(), 20, True)
+SketchConstraintDistance_17 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_24.endPoint(), 20, True)
+SketchConstraintEqual_18 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_25.result())
+SketchLine_26 = Sketch_1.addLine(95.51651619313817, -32.72404055044315, 45.95024650348294, -10.47426958610802)
+SketchConstraintCoincidence_29 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_26.result())
+SketchConstraintDistance_18 = Sketch_1.setDistance(SketchLine_26.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_23 = Sketch_1.setAngleComplementary(SketchLine_24.result(), SketchLine_25.result(), 5)
+SketchConstraintAngle_24 = Sketch_1.setAngleComplementary(SketchLine_26.result(), SketchLine_25.result(), 5)
+SketchLine_27 = Sketch_1.addLine(83.08667026246893, -25.23373396888348, 26.41541642632507, -5.526654311071399)
+SketchConstraintCoincidence_30 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_27.result())
+SketchConstraintEqual_19 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_27.result())
+SketchConstraintDistance_19 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_27.startPoint(), 20, True)
+SketchConstraintAngle_25 = Sketch_1.setAngleComplementary(SketchLine_27.result(), SketchLine_26.result(), 5)
+SketchLine_28 = Sketch_1.addLine(102.9783774975822, -28.45994944924871, 44.80518972684035, -13.76708639979482)
+SketchConstraintCoincidence_31 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_28.result())
+SketchConstraintEqual_20 = Sketch_1.setEqual(SketchLine_27.result(), SketchLine_28.result())
+SketchConstraintDistance_20 = Sketch_1.setDistance(SketchLine_28.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_26 = Sketch_1.setAngleComplementary(SketchLine_27.result(), SketchLine_28.result(), 5)
+SketchLine_29 = Sketch_1.addLine(103.6845113974033, -25.04259067061018, 44.45212277692985, -15.47576578911409)
+SketchConstraintCoincidence_32 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_29.result())
+SketchConstraintDistance_21 = Sketch_1.setDistance(SketchLine_29.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_27 = Sketch_1.setAngleComplementary(SketchLine_28.result(), SketchLine_29.result(), 175)
+SketchConstraintEqual_21 = Sketch_1.setEqual(SketchLine_28.result(), SketchLine_29.result())
+SketchLine_30 = Sketch_1.addLine(104.0901158019603, -21.57669234933498, 44.24932057465131, -17.20871494975169)
+SketchConstraintCoincidence_33 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_30.result())
+SketchConstraintEqual_22 = Sketch_1.setEqual(SketchLine_29.result(), SketchLine_30.result())
+SketchConstraintDistance_22 = Sketch_1.setDistance(SketchLine_30.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_28 = Sketch_1.setAngleComplementary(SketchLine_30.result(), SketchLine_29.result(), 175)
+SketchConstraintCoincidence_34 = Sketch_1.setCoincident(SketchLine_22.startPoint(), SketchLine_30.result())
+
+SketchLine_31 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 156.7284871354776, -69.4178124771163)
+SketchLine_32 = Sketch_1.addLine(156.7284871354776, -69.4178124771163, 164.8053019156854, -51.12122637461573)
+SketchConstraintCoincidence_35 = Sketch_1.setCoincident(SketchLine_31.endPoint(), SketchLine_32.startPoint())
+SketchLine_33 = Sketch_1.addLine(164.8053019156854, -51.12122637461573, 148.0844426183728, 6.501797360341752)
+SketchConstraintCoincidence_36 = Sketch_1.setCoincident(SketchLine_32.endPoint(), SketchLine_33.startPoint())
+SketchLine_34 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_37 = Sketch_1.setCoincident(SketchLine_31.startPoint(), SketchLine_34.startPoint())
+SketchLine_35 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_38 = Sketch_1.setCoincident(SketchLine_34.endPoint(), SketchLine_35.endPoint())
+SketchLine_36 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_39 = Sketch_1.setCoincident(SketchLine_35.startPoint(), SketchLine_36.startPoint())
+SketchLine_37 = Sketch_1.addLine(125.8708496231354, -19.66465768043951, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_40 = Sketch_1.setCoincident(SketchLine_36.endPoint(), SketchLine_37.endPoint())
+SketchConstraintAngle_29 = Sketch_1.setAngleBackward(SketchLine_31.result(), SketchLine_32.result(), 140)
+SketchConstraintAngle_30 = Sketch_1.setAngleBackward(SketchLine_33.result(), SketchLine_32.result(), 220)
+SketchConstraintAngle_31 = Sketch_1.setAngleBackward(SketchLine_31.result(), SketchLine_34.result(), 220)
+SketchConstraintAngle_32 = Sketch_1.setAngleBackward(SketchLine_36.result(), SketchLine_35.result(), 140)
+SketchConstraintAngle_33 = Sketch_1.setAngleBackward(SketchLine_35.result(), SketchLine_34.result(), 140)
+SketchConstraintAngle_34 = Sketch_1.setAngleBackward(SketchLine_36.result(), SketchLine_37.result(), 220)
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_32.result(), 20)
+SketchConstraintEqual_23 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_31.result())
+SketchConstraintEqual_24 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_34.result())
+SketchConstraintEqual_25 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_35.result())
+SketchConstraintEqual_26 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_36.result())
+SketchLine_38 = Sketch_1.addLine(171.0385831271055, -48.05657162886843, 135.6178801955327, 0.3724878688471688)
+SketchPoint_5 = Sketch_1.addPoint(159.2316821499145, -31.91355179629657)
+SketchConstraintCoincidence_41 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_33.result())
+SketchConstraintCoincidence_42 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_38.result())
+SketchConstraintDistance_23 = Sketch_1.setDistance(SketchLine_32.endPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_24 = Sketch_1.setDistance(SketchLine_38.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_25 = Sketch_1.setDistance(SketchPoint_5.coordinates(), SketchLine_33.endPoint(), 40, True)
+SketchConstraintEqual_27 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_38.result())
+SketchLine_39 = Sketch_1.addLine(175.8477778293761, -43.04483044571408, 125.9994907909914, -9.650994497461493)
+SketchConstraintCoincidence_43 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_39.result())
+SketchConstraintEqual_28 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_39.result())
+SketchConstraintDistance_26 = Sketch_1.setDistance(SketchLine_39.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintAngle_35 = Sketch_1.setAngleBackward(SketchLine_33.result(), SketchLine_38.result(), 340)
+SketchConstraintAngle_36 = Sketch_1.setAngleBackward(SketchLine_39.result(), SketchLine_38.result(), 20)
+SketchLine_40 = Sketch_1.addLine(160.1386077477389, -30.42300575990098, 107.5695439158812, -1.500807920835093)
+SketchPoint_6 = Sketch_1.addPoint(142.615586470453, -20.78227314687903)
+SketchConstraintCoincidence_44 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_40.result())
+SketchConstraintCoincidence_45 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_39.result())
+SketchConstraintDistance_27 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_40.startPoint(), 20, True)
+SketchConstraintDistance_28 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_39.endPoint(), 20, True)
+SketchConstraintEqual_29 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_40.result())
+SketchLine_41 = Sketch_1.addLine(147.1612701207084, -22.78891223719074, 124.3190003679524, -12.70545836667124)
+SketchConstraintCoincidence_46 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_41.result())
+SketchConstraintDistance_29 = Sketch_1.setDistance(SketchLine_41.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_37 = Sketch_1.setAngleBackward(SketchLine_39.result(), SketchLine_40.result(), 175)
+SketchConstraintAngle_38 = Sketch_1.setAngleBackward(SketchLine_41.result(), SketchLine_40.result(), 5)
+SketchLine_42 = Sketch_1.addLine(161.5464893301474, -27.23370065688114, 104.7537807510641, -7.879418126874779)
+SketchConstraintCoincidence_47 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_42.result())
+SketchConstraintEqual_30 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_42.result())
+SketchConstraintDistance_30 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_42.startPoint(), 20, True)
+SketchConstraintAngle_39 = Sketch_1.setAngleBackward(SketchLine_42.result(), SketchLine_41.result(), 5)
+SketchLine_43 = Sketch_1.addLine(181.4578745011218, -30.33615510881286, 123.1944424551186, -16.0053321659121)
+SketchConstraintCoincidence_48 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_43.result())
+SketchConstraintEqual_31 = Sketch_1.setEqual(SketchLine_42.result(), SketchLine_43.result())
+SketchConstraintDistance_31 = Sketch_1.setDistance(SketchLine_43.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_40 = Sketch_1.setAngleBackward(SketchLine_42.result(), SketchLine_43.result(), 175)
+SketchLine_44 = Sketch_1.addLine(182.1427435468735, -26.91447124022047, 122.8520079322427, -17.71617410020831)
+SketchConstraintCoincidence_49 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_44.result())
+SketchConstraintDistance_32 = Sketch_1.setDistance(SketchLine_44.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_41 = Sketch_1.setAngleBackward(SketchLine_43.result(), SketchLine_44.result(), 355)
+SketchConstraintEqual_32 = Sketch_1.setEqual(SketchLine_43.result(), SketchLine_44.result())
+SketchLine_45 = Sketch_1.addLine(182.5267870601237, -23.44611764141531, 122.6599861756176, -19.45035089961089)
+SketchConstraintCoincidence_50 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_45.result())
+SketchConstraintEqual_33 = Sketch_1.setEqual(SketchLine_44.result(), SketchLine_45.result())
+SketchConstraintDistance_33 = Sketch_1.setDistance(SketchLine_45.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_42 = Sketch_1.setAngleBackward(SketchLine_45.result(), SketchLine_44.result(), 5)
+SketchConstraintCoincidence_51 = Sketch_1.setCoincident(SketchLine_37.startPoint(), SketchLine_45.result())
+model.do()
+
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_9f-SketchLine_15f-SketchLine_7f-SketchLine_6r-SketchLine_5f-SketchLine_4r"), model.selection("FACE", "Sketch_1/Face-SketchLine_16f-SketchLine_17f-SketchLine_18f-SketchLine_24f-SketchLine_30f-SketchLine_22f-SketchLine_21r-SketchLine_20f-SketchLine_19r"), model.selection("FACE", "Sketch_1/Face-SketchLine_31f-SketchLine_32f-SketchLine_33f-SketchLine_39f-SketchLine_45f-SketchLine_37f-SketchLine_36r-SketchLine_35f-SketchLine_34r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+
+model.end()
+
+from GeomAPI import *
+
+REF_VOLUME = 25018.7130187615
+
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [11, 11, 11])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [54, 54, 54])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [108, 108, 108])
+model.testResultsVolumes(Extrusion_1, [REF_VOLUME, REF_VOLUME, REF_VOLUME])
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "Ang", "140")
+model.addParameter(Part_1_doc, "dAng", "5")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, 0.4653113240225388, -68.74815303974528)
+SketchLine_2 = Sketch_1.addLine(0.4653113240225388, -68.74815303974528, 8.542125432770632, -50.45156664083665)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(8.542125432770632, -50.45156664083665, -8.178735979228234, 7.171456480488104)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(-30.39232801419296, -18.99499937550162, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.endPoint())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), "360-Ang")
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), "Ang")
+SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_4.result(), "Ang")
+SketchConstraintAngle_4 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_5.result(), "360-Ang")
+SketchConstraintAngle_5 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), "360-Ang")
+SketchConstraintAngle_6 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_7.result(), "Ang")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_4.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_5.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_6.result())
+SketchLine_8 = Sketch_1.addLine(14.775406531722, -47.38691166633646, -20.64529817713098, 1.042146531487715)
+SketchPoint_1 = Sketch_1.addPoint(2.968504962104344, -31.24389226706174)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_3.result())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_8.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.endPoint(), 40, True)
+SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_8.result())
+SketchLine_9 = Sketch_1.addLine(19.58460105006861, -42.37517030669127, -30.26368721382418, -8.981336187802668)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintEqual_6 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_9.result())
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_9.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintAngle_7 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_8.result(), "(180-Ang)/2")
+SketchConstraintAngle_8 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_8.result(), "360-(180-Ang)/2")
+SketchLine_10 = Sketch_1.addLine(3.875430505227681, -29.75334619738324, -48.69363438803513, -0.8311502875301234)
+SketchPoint_2 = Sketch_1.addPoint(-13.64759112585992, -20.1126142274322)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_10.result())
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_9.result())
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_10.startPoint(), 20, True)
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_9.endPoint(), 20, True)
+SketchConstraintEqual_7 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(0.001529676402264532, -26.13785899518266, -31.94417752476854, -12.03580011868412)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_11.result())
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchLine_11.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_9 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_10.result(), "180+dAng")
+SketchConstraintAngle_10 = Sketch_1.setAngle(SketchLine_11.result(), SketchLine_10.result(), "360-dAng")
+SketchLine_12 = Sketch_1.addLine(5.283311970593094, -26.56404104269606, -51.50939731876596, -7.20976059690448)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_12.result())
+SketchConstraintEqual_8 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_12.result())
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_12.startPoint(), 20, True)
+SketchConstraintAngle_11 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_11.result(), "360-dAng")
+SketchLine_13 = Sketch_1.addLine(25.19469725542325, -29.66649476390714, -33.06873531650151, -15.33567395919474)
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_13.result())
+SketchConstraintEqual_9 = Sketch_1.setEqual(SketchLine_12.result(), SketchLine_13.result())
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchLine_13.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_12 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_13.result(), "180+dAng")
+SketchLine_14 = Sketch_1.addLine(25.87956617560386, -26.24481087018098, -33.41116977659181, -17.04651590605781)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_14.result())
+SketchConstraintDistance_10 = Sketch_1.setDistance(SketchLine_14.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_13 = Sketch_1.setAngle(SketchLine_13.result(), SketchLine_14.result(), "dAng")
+SketchConstraintEqual_10 = Sketch_1.setEqual(SketchLine_13.result(), SketchLine_14.result())
+SketchLine_15 = Sketch_1.addLine(26.26360956157018, -22.77645725728195, -33.60319146957497, -18.78069271250733)
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_15.result())
+SketchConstraintEqual_11 = Sketch_1.setEqual(SketchLine_14.result(), SketchLine_15.result())
+SketchConstraintDistance_11 = Sketch_1.setDistance(SketchLine_15.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_14 = Sketch_1.setAngle(SketchLine_15.result(), SketchLine_14.result(), "360-dAng")
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_15.result())
+
+SketchLine_16 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 78.00643494689578, -67.38706888260469)
+SketchLine_17 = Sketch_1.addLine(78.00643494689578, -67.38706888260469, 86.19687277706721, -49.141063069)
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_16.endPoint(), SketchLine_17.startPoint())
+SketchLine_18 = Sketch_1.addLine(86.19687277706721, -49.141063069, 69.83467154684908, 8.584826884311665)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_18.startPoint())
+SketchLine_19 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_16.startPoint(), SketchLine_19.startPoint())
+SketchLine_20 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_19.endPoint(), SketchLine_20.endPoint())
+SketchLine_21 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_20.startPoint(), SketchLine_21.startPoint())
+SketchLine_22 = Sketch_1.addLine(47.45878924889096, -17.44298467461911, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_21.endPoint(), SketchLine_22.endPoint())
+SketchConstraintAngle_15 = Sketch_1.setAngleComplementary(SketchLine_16.result(), SketchLine_17.result(), "180-Ang")
+SketchConstraintAngle_16 = Sketch_1.setAngleComplementary(SketchLine_18.result(), SketchLine_17.result(), "180-Ang")
+SketchConstraintAngle_17 = Sketch_1.setAngleComplementary(SketchLine_16.result(), SketchLine_19.result(), "180-Ang")
+SketchConstraintAngle_18 = Sketch_1.setAngleComplementary(SketchLine_21.result(), SketchLine_20.result(), "180-Ang")
+SketchConstraintAngle_19 = Sketch_1.setAngleComplementary(SketchLine_20.result(), SketchLine_19.result(), "180-Ang")
+SketchConstraintAngle_20 = Sketch_1.setAngleComplementary(SketchLine_21.result(), SketchLine_22.result(), "180-Ang")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_17.result(), 20)
+SketchConstraintEqual_12 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_16.result())
+SketchConstraintEqual_13 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_19.result())
+SketchConstraintEqual_14 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_20.result())
+SketchConstraintEqual_15 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_21.result())
+SketchLine_23 = Sketch_1.addLine(92.44909133742235, -46.11522988707736, 57.3302344261388, 2.533160520466375)
+SketchPoint_3 = Sketch_1.addPoint(80.74280570032784, -29.89909975122945)
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_18.result())
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_23.result())
+SketchConstraintDistance_12 = Sketch_1.setDistance(SketchLine_17.endPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_13 = Sketch_1.setDistance(SketchLine_23.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_14 = Sketch_1.setDistance(SketchPoint_3.coordinates(), SketchLine_18.endPoint(), 40, True)
+SketchConstraintEqual_16 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_23.result())
+SketchLine_24 = Sketch_1.addLine(97.289359083568, -41.13349208617944, 47.64969893384747, -7.430315081329468)
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_24.result())
+SketchConstraintEqual_17 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_24.result())
+SketchConstraintDistance_15 = Sketch_1.setDistance(SketchLine_24.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintAngle_21 = Sketch_1.setAngleComplementary(SketchLine_18.result(), SketchLine_23.result(), "90+Ang/2")
+SketchConstraintAngle_22 = Sketch_1.setAngleComplementary(SketchLine_24.result(), SketchLine_23.result(), "90+Ang/2")
+SketchLine_25 = Sketch_1.addLine(81.65898287743471, -28.41422234660911, 29.27079119639352, 0.8343224443798635)
+SketchPoint_4 = Sketch_1.addPoint(64.19625231708766, -18.66470741627946)
+SketchConstraintCoincidence_27 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_25.result())
+SketchConstraintCoincidence_28 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_24.result())
+SketchConstraintDistance_16 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_25.startPoint(), 20, True)
+SketchConstraintDistance_17 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_24.endPoint(), 20, True)
+SketchConstraintEqual_18 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_25.result())
+SketchLine_26 = Sketch_1.addLine(95.51651619313817, -32.72404055044315, 45.95024650348294, -10.47426958610802)
+SketchConstraintCoincidence_29 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_26.result())
+SketchConstraintDistance_18 = Sketch_1.setDistance(SketchLine_26.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_23 = Sketch_1.setAngleComplementary(SketchLine_24.result(), SketchLine_25.result(), "dAng")
+SketchConstraintAngle_24 = Sketch_1.setAngleComplementary(SketchLine_26.result(), SketchLine_25.result(), "dAng")
+SketchLine_27 = Sketch_1.addLine(83.08667026246893, -25.23373396888348, 26.41541642632507, -5.526654311071399)
+SketchConstraintCoincidence_30 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_27.result())
+SketchConstraintEqual_19 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_27.result())
+SketchConstraintDistance_19 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_27.startPoint(), 20, True)
+SketchConstraintAngle_25 = Sketch_1.setAngleComplementary(SketchLine_27.result(), SketchLine_26.result(), "dAng")
+SketchLine_28 = Sketch_1.addLine(102.9783774975822, -28.45994944924871, 44.80518972684035, -13.76708639979482)
+SketchConstraintCoincidence_31 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_28.result())
+SketchConstraintEqual_20 = Sketch_1.setEqual(SketchLine_27.result(), SketchLine_28.result())
+SketchConstraintDistance_20 = Sketch_1.setDistance(SketchLine_28.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_26 = Sketch_1.setAngleComplementary(SketchLine_27.result(), SketchLine_28.result(), "dAng")
+SketchLine_29 = Sketch_1.addLine(103.6845113974033, -25.04259067061018, 44.45212277692985, -15.47576578911409)
+SketchConstraintCoincidence_32 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_29.result())
+SketchConstraintDistance_21 = Sketch_1.setDistance(SketchLine_29.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_27 = Sketch_1.setAngleComplementary(SketchLine_28.result(), SketchLine_29.result(), "180-dAng")
+SketchConstraintEqual_21 = Sketch_1.setEqual(SketchLine_28.result(), SketchLine_29.result())
+SketchLine_30 = Sketch_1.addLine(104.0901158019603, -21.57669234933498, 44.24932057465131, -17.20871494975169)
+SketchConstraintCoincidence_33 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_30.result())
+SketchConstraintEqual_22 = Sketch_1.setEqual(SketchLine_29.result(), SketchLine_30.result())
+SketchConstraintDistance_22 = Sketch_1.setDistance(SketchLine_30.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_28 = Sketch_1.setAngleComplementary(SketchLine_30.result(), SketchLine_29.result(), "180-dAng")
+SketchConstraintCoincidence_34 = Sketch_1.setCoincident(SketchLine_22.startPoint(), SketchLine_30.result())
+
+SketchLine_31 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 156.7284871354776, -69.4178124771163)
+SketchLine_32 = Sketch_1.addLine(156.7284871354776, -69.4178124771163, 164.8053019156854, -51.12122637461573)
+SketchConstraintCoincidence_35 = Sketch_1.setCoincident(SketchLine_31.endPoint(), SketchLine_32.startPoint())
+SketchLine_33 = Sketch_1.addLine(164.8053019156854, -51.12122637461573, 148.0844426183728, 6.501797360341752)
+SketchConstraintCoincidence_36 = Sketch_1.setCoincident(SketchLine_32.endPoint(), SketchLine_33.startPoint())
+SketchLine_34 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_37 = Sketch_1.setCoincident(SketchLine_31.startPoint(), SketchLine_34.startPoint())
+SketchLine_35 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_38 = Sketch_1.setCoincident(SketchLine_34.endPoint(), SketchLine_35.endPoint())
+SketchLine_36 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_39 = Sketch_1.setCoincident(SketchLine_35.startPoint(), SketchLine_36.startPoint())
+SketchLine_37 = Sketch_1.addLine(125.8708496231354, -19.66465768043951, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_40 = Sketch_1.setCoincident(SketchLine_36.endPoint(), SketchLine_37.endPoint())
+SketchConstraintAngle_29 = Sketch_1.setAngleBackward(SketchLine_31.result(), SketchLine_32.result(), "Ang")
+SketchConstraintAngle_30 = Sketch_1.setAngleBackward(SketchLine_33.result(), SketchLine_32.result(), "360-Ang")
+SketchConstraintAngle_31 = Sketch_1.setAngleBackward(SketchLine_31.result(), SketchLine_34.result(), "360-Ang")
+SketchConstraintAngle_32 = Sketch_1.setAngleBackward(SketchLine_36.result(), SketchLine_35.result(), "Ang")
+SketchConstraintAngle_33 = Sketch_1.setAngleBackward(SketchLine_35.result(), SketchLine_34.result(), "Ang")
+SketchConstraintAngle_34 = Sketch_1.setAngleBackward(SketchLine_36.result(), SketchLine_37.result(), "360-Ang")
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_32.result(), 20)
+SketchConstraintEqual_23 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_31.result())
+SketchConstraintEqual_24 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_34.result())
+SketchConstraintEqual_25 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_35.result())
+SketchConstraintEqual_26 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_36.result())
+SketchLine_38 = Sketch_1.addLine(171.0385831271055, -48.05657162886843, 135.6178801955327, 0.3724878688471688)
+SketchPoint_5 = Sketch_1.addPoint(159.2316821499145, -31.91355179629657)
+SketchConstraintCoincidence_41 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_33.result())
+SketchConstraintCoincidence_42 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_38.result())
+SketchConstraintDistance_23 = Sketch_1.setDistance(SketchLine_32.endPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_24 = Sketch_1.setDistance(SketchLine_38.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_25 = Sketch_1.setDistance(SketchPoint_5.coordinates(), SketchLine_33.endPoint(), 40, True)
+SketchConstraintEqual_27 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_38.result())
+SketchLine_39 = Sketch_1.addLine(175.8477778293761, -43.04483044571408, 125.9994907909914, -9.650994497461493)
+SketchConstraintCoincidence_43 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_39.result())
+SketchConstraintEqual_28 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_39.result())
+SketchConstraintDistance_26 = Sketch_1.setDistance(SketchLine_39.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintAngle_35 = Sketch_1.setAngleBackward(SketchLine_33.result(), SketchLine_38.result(), "360-(180-Ang)/2")
+SketchConstraintAngle_36 = Sketch_1.setAngleBackward(SketchLine_39.result(), SketchLine_38.result(), "(180-Ang)/2")
+SketchLine_40 = Sketch_1.addLine(160.1386077477389, -30.42300575990098, 107.5695439158812, -1.500807920835093)
+SketchPoint_6 = Sketch_1.addPoint(142.615586470453, -20.78227314687903)
+SketchConstraintCoincidence_44 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_40.result())
+SketchConstraintCoincidence_45 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_39.result())
+SketchConstraintDistance_27 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_40.startPoint(), 20, True)
+SketchConstraintDistance_28 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_39.endPoint(), 20, True)
+SketchConstraintEqual_29 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_40.result())
+SketchLine_41 = Sketch_1.addLine(147.1612701207084, -22.78891223719074, 124.3190003679524, -12.70545836667124)
+SketchConstraintCoincidence_46 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_41.result())
+SketchConstraintDistance_29 = Sketch_1.setDistance(SketchLine_41.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_37 = Sketch_1.setAngleBackward(SketchLine_39.result(), SketchLine_40.result(), "180-dAng")
+SketchConstraintAngle_38 = Sketch_1.setAngleBackward(SketchLine_41.result(), SketchLine_40.result(), "dAng")
+SketchLine_42 = Sketch_1.addLine(161.5464893301474, -27.23370065688114, 104.7537807510641, -7.879418126874779)
+SketchConstraintCoincidence_47 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_42.result())
+SketchConstraintEqual_30 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_42.result())
+SketchConstraintDistance_30 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_42.startPoint(), 20, True)
+SketchConstraintAngle_39 = Sketch_1.setAngleBackward(SketchLine_42.result(), SketchLine_41.result(), "dAng")
+SketchLine_43 = Sketch_1.addLine(181.4578745011218, -30.33615510881286, 123.1944424551186, -16.0053321659121)
+SketchConstraintCoincidence_48 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_43.result())
+SketchConstraintEqual_31 = Sketch_1.setEqual(SketchLine_42.result(), SketchLine_43.result())
+SketchConstraintDistance_31 = Sketch_1.setDistance(SketchLine_43.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_40 = Sketch_1.setAngleBackward(SketchLine_42.result(), SketchLine_43.result(), "180-dAng")
+SketchLine_44 = Sketch_1.addLine(182.1427435468735, -26.91447124022047, 122.8520079322427, -17.71617410020831)
+SketchConstraintCoincidence_49 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_44.result())
+SketchConstraintDistance_32 = Sketch_1.setDistance(SketchLine_44.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_41 = Sketch_1.setAngleBackward(SketchLine_43.result(), SketchLine_44.result(), "360-dAng")
+SketchConstraintEqual_32 = Sketch_1.setEqual(SketchLine_43.result(), SketchLine_44.result())
+SketchLine_45 = Sketch_1.addLine(182.5267870601237, -23.44611764141531, 122.6599861756176, -19.45035089961089)
+SketchConstraintCoincidence_50 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_45.result())
+SketchConstraintEqual_33 = Sketch_1.setEqual(SketchLine_44.result(), SketchLine_45.result())
+SketchConstraintDistance_33 = Sketch_1.setDistance(SketchLine_45.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_42 = Sketch_1.setAngleBackward(SketchLine_45.result(), SketchLine_44.result(), "dAng")
+SketchConstraintCoincidence_51 = Sketch_1.setCoincident(SketchLine_37.startPoint(), SketchLine_45.result())
+model.do()
+
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_9f-SketchLine_15f-SketchLine_7f-SketchLine_6r-SketchLine_5f-SketchLine_4r"), model.selection("FACE", "Sketch_1/Face-SketchLine_16f-SketchLine_17f-SketchLine_18f-SketchLine_24f-SketchLine_30f-SketchLine_22f-SketchLine_21r-SketchLine_20f-SketchLine_19r"), model.selection("FACE", "Sketch_1/Face-SketchLine_31f-SketchLine_32f-SketchLine_33f-SketchLine_39f-SketchLine_45f-SketchLine_37f-SketchLine_36r-SketchLine_35f-SketchLine_34r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+
+model.end()
+
+from GeomAPI import *
+
+REF_VOLUME = 25018.7130187615
+
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [11, 11, 11])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [54, 54, 54])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [108, 108, 108])
+model.testResultsVolumes(Extrusion_1, [REF_VOLUME, REF_VOLUME, REF_VOLUME])
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, 0.4653113240225388, -68.74815303974528)
+SketchLine_2 = Sketch_1.addLine(0.4653113240225388, -68.74815303974528, 8.542125432770632, -50.45156664083665)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(8.542125432770632, -50.45156664083665, -8.178735979228234, 7.171456480488104)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(-30.39232801419296, -18.99499937550162, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.endPoint())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), 140, type = "Direct")
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 140, type = "Direct")
+SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_4.result(), 140, type = "Direct")
+SketchConstraintAngle_4 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_5.result(), 140, type = "Direct")
+SketchConstraintAngle_5 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), 140, type = "Direct")
+SketchConstraintAngle_6 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_7.result(), 140, type = "Direct")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_4.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_5.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_6.result())
+SketchLine_8 = Sketch_1.addLine(14.775406531722, -47.38691166633646, -20.64529817713098, 1.042146531487715)
+SketchPoint_1 = Sketch_1.addPoint(2.968504962104344, -31.24389226706174)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_3.result())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_8.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.endPoint(), 40, True)
+SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_8.result())
+SketchLine_9 = Sketch_1.addLine(19.58460105006861, -42.37517030669127, -30.26368721382418, -8.981336187802668)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintEqual_6 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_9.result())
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_9.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintAngle_7 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_8.result(), 20, type = "Direct")
+SketchConstraintAngle_8 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_8.result(), 20, type = "Direct")
+SketchLine_10 = Sketch_1.addLine(3.875430505227681, -29.75334619738324, -48.69363438803513, -0.8311502875301234)
+SketchPoint_2 = Sketch_1.addPoint(-13.64759112585992, -20.1126142274322)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_10.result())
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_9.result())
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_10.startPoint(), 20, True)
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_9.endPoint(), 20, True)
+SketchConstraintEqual_7 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(0.001529676402264532, -26.13785899518266, -31.94417752476854, -12.03580011868412)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_11.result())
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchLine_11.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_9 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_10.result(), 175, type = "Direct")
+SketchConstraintAngle_10 = Sketch_1.setAngle(SketchLine_11.result(), SketchLine_10.result(), 5, type = "Direct")
+SketchLine_12 = Sketch_1.addLine(5.283311970593094, -26.56404104269606, -51.50939731876596, -7.20976059690448)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_12.result())
+SketchConstraintEqual_8 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_12.result())
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_12.startPoint(), 20, True)
+SketchConstraintAngle_11 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_11.result(), 5, type = "Direct")
+SketchLine_13 = Sketch_1.addLine(25.19469725542325, -29.66649476390714, -33.06873531650151, -15.33567395919474)
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_13.result())
+SketchConstraintEqual_9 = Sketch_1.setEqual(SketchLine_12.result(), SketchLine_13.result())
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchLine_13.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_12 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_13.result(), 175, type = "Direct")
+SketchLine_14 = Sketch_1.addLine(25.87956617560386, -26.24481087018098, -33.41116977659181, -17.04651590605781)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_14.result())
+SketchConstraintDistance_10 = Sketch_1.setDistance(SketchLine_14.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_13 = Sketch_1.setAngle(SketchLine_13.result(), SketchLine_14.result(), 5, type = "Direct")
+SketchConstraintEqual_10 = Sketch_1.setEqual(SketchLine_13.result(), SketchLine_14.result())
+SketchLine_15 = Sketch_1.addLine(26.26360956157018, -22.77645725728195, -33.60319146957497, -18.78069271250733)
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_15.result())
+SketchConstraintEqual_11 = Sketch_1.setEqual(SketchLine_14.result(), SketchLine_15.result())
+SketchConstraintDistance_11 = Sketch_1.setDistance(SketchLine_15.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_14 = Sketch_1.setAngle(SketchLine_15.result(), SketchLine_14.result(), 5, type = "Direct")
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_15.result())
+
+SketchLine_16 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 78.00643494689578, -67.38706888260469)
+SketchLine_17 = Sketch_1.addLine(78.00643494689578, -67.38706888260469, 86.19687277706721, -49.141063069)
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_16.endPoint(), SketchLine_17.startPoint())
+SketchLine_18 = Sketch_1.addLine(86.19687277706721, -49.141063069, 69.83467154684908, 8.584826884311665)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_18.startPoint())
+SketchLine_19 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_16.startPoint(), SketchLine_19.startPoint())
+SketchLine_20 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_19.endPoint(), SketchLine_20.endPoint())
+SketchLine_21 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_20.startPoint(), SketchLine_21.startPoint())
+SketchLine_22 = Sketch_1.addLine(47.45878924889096, -17.44298467461911, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_21.endPoint(), SketchLine_22.endPoint())
+SketchConstraintAngle_15 = Sketch_1.setAngle(SketchLine_16.result(), SketchLine_17.result(), 40, type = "Supplementary")
+SketchConstraintAngle_16 = Sketch_1.setAngle(SketchLine_18.result(), SketchLine_17.result(), 40, type = "Supplementary")
+SketchConstraintAngle_17 = Sketch_1.setAngle(SketchLine_16.result(), SketchLine_19.result(), 40, type = "Supplementary")
+SketchConstraintAngle_18 = Sketch_1.setAngle(SketchLine_21.result(), SketchLine_20.result(), 40, type = "Supplementary")
+SketchConstraintAngle_19 = Sketch_1.setAngle(SketchLine_20.result(), SketchLine_19.result(), 40, type = "Supplementary")
+SketchConstraintAngle_20 = Sketch_1.setAngle(SketchLine_21.result(), SketchLine_22.result(), 40, type = "Supplementary")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_17.result(), 20)
+SketchConstraintEqual_12 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_16.result())
+SketchConstraintEqual_13 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_19.result())
+SketchConstraintEqual_14 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_20.result())
+SketchConstraintEqual_15 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_21.result())
+SketchLine_23 = Sketch_1.addLine(92.44909133742235, -46.11522988707736, 57.3302344261388, 2.533160520466375)
+SketchPoint_3 = Sketch_1.addPoint(80.74280570032784, -29.89909975122945)
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_18.result())
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_23.result())
+SketchConstraintDistance_12 = Sketch_1.setDistance(SketchLine_17.endPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_13 = Sketch_1.setDistance(SketchLine_23.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_14 = Sketch_1.setDistance(SketchPoint_3.coordinates(), SketchLine_18.endPoint(), 40, True)
+SketchConstraintEqual_16 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_23.result())
+SketchLine_24 = Sketch_1.addLine(97.289359083568, -41.13349208617944, 47.64969893384747, -7.430315081329468)
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_24.result())
+SketchConstraintEqual_17 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_24.result())
+SketchConstraintDistance_15 = Sketch_1.setDistance(SketchLine_24.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintAngle_21 = Sketch_1.setAngle(SketchLine_18.result(), SketchLine_23.result(), 160, type = "Supplementary")
+SketchConstraintAngle_22 = Sketch_1.setAngle(SketchLine_24.result(), SketchLine_23.result(), 160, type = "Supplementary")
+SketchLine_25 = Sketch_1.addLine(81.65898287743471, -28.41422234660911, 29.27079119639352, 0.8343224443798635)
+SketchPoint_4 = Sketch_1.addPoint(64.19625231708766, -18.66470741627946)
+SketchConstraintCoincidence_27 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_25.result())
+SketchConstraintCoincidence_28 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_24.result())
+SketchConstraintDistance_16 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_25.startPoint(), 20, True)
+SketchConstraintDistance_17 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_24.endPoint(), 20, True)
+SketchConstraintEqual_18 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_25.result())
+SketchLine_26 = Sketch_1.addLine(95.51651619313817, -32.72404055044315, 45.95024650348294, -10.47426958610802)
+SketchConstraintCoincidence_29 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_26.result())
+SketchConstraintDistance_18 = Sketch_1.setDistance(SketchLine_26.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_23 = Sketch_1.setAngle(SketchLine_24.result(), SketchLine_25.result(), 5, type = "Supplementary")
+SketchConstraintAngle_24 = Sketch_1.setAngle(SketchLine_26.result(), SketchLine_25.result(), 5, type = "Supplementary")
+SketchLine_27 = Sketch_1.addLine(83.08667026246893, -25.23373396888348, 26.41541642632507, -5.526654311071399)
+SketchConstraintCoincidence_30 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_27.result())
+SketchConstraintEqual_19 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_27.result())
+SketchConstraintDistance_19 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_27.startPoint(), 20, True)
+SketchConstraintAngle_25 = Sketch_1.setAngle(SketchLine_27.result(), SketchLine_26.result(), 5, type = "Supplementary")
+SketchLine_28 = Sketch_1.addLine(102.9783774975822, -28.45994944924871, 44.80518972684035, -13.76708639979482)
+SketchConstraintCoincidence_31 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_28.result())
+SketchConstraintEqual_20 = Sketch_1.setEqual(SketchLine_27.result(), SketchLine_28.result())
+SketchConstraintDistance_20 = Sketch_1.setDistance(SketchLine_28.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_26 = Sketch_1.setAngle(SketchLine_27.result(), SketchLine_28.result(), 5, type = "Supplementary")
+SketchLine_29 = Sketch_1.addLine(103.6845113974033, -25.04259067061018, 44.45212277692985, -15.47576578911409)
+SketchConstraintCoincidence_32 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_29.result())
+SketchConstraintDistance_21 = Sketch_1.setDistance(SketchLine_29.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_27 = Sketch_1.setAngle(SketchLine_28.result(), SketchLine_29.result(), 175, type = "Supplementary")
+SketchConstraintEqual_21 = Sketch_1.setEqual(SketchLine_28.result(), SketchLine_29.result())
+SketchLine_30 = Sketch_1.addLine(104.0901158019603, -21.57669234933498, 44.24932057465131, -17.20871494975169)
+SketchConstraintCoincidence_33 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_30.result())
+SketchConstraintEqual_22 = Sketch_1.setEqual(SketchLine_29.result(), SketchLine_30.result())
+SketchConstraintDistance_22 = Sketch_1.setDistance(SketchLine_30.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_28 = Sketch_1.setAngle(SketchLine_30.result(), SketchLine_29.result(), 175, type = "Supplementary")
+SketchConstraintCoincidence_34 = Sketch_1.setCoincident(SketchLine_22.startPoint(), SketchLine_30.result())
+
+SketchLine_31 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 156.7284871354776, -69.4178124771163)
+SketchLine_32 = Sketch_1.addLine(156.7284871354776, -69.4178124771163, 164.8053019156854, -51.12122637461573)
+SketchConstraintCoincidence_35 = Sketch_1.setCoincident(SketchLine_31.endPoint(), SketchLine_32.startPoint())
+SketchLine_33 = Sketch_1.addLine(164.8053019156854, -51.12122637461573, 148.0844426183728, 6.501797360341752)
+SketchConstraintCoincidence_36 = Sketch_1.setCoincident(SketchLine_32.endPoint(), SketchLine_33.startPoint())
+SketchLine_34 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_37 = Sketch_1.setCoincident(SketchLine_31.startPoint(), SketchLine_34.startPoint())
+SketchLine_35 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_38 = Sketch_1.setCoincident(SketchLine_34.endPoint(), SketchLine_35.endPoint())
+SketchLine_36 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_39 = Sketch_1.setCoincident(SketchLine_35.startPoint(), SketchLine_36.startPoint())
+SketchLine_37 = Sketch_1.addLine(125.8708496231354, -19.66465768043951, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_40 = Sketch_1.setCoincident(SketchLine_36.endPoint(), SketchLine_37.endPoint())
+SketchConstraintAngle_29 = Sketch_1.setAngle(SketchLine_31.result(), SketchLine_32.result(), 220, type = "Backward")
+SketchConstraintAngle_30 = Sketch_1.setAngle(SketchLine_33.result(), SketchLine_32.result(), 220, type = "Backward")
+SketchConstraintAngle_31 = Sketch_1.setAngle(SketchLine_31.result(), SketchLine_34.result(), 220, type = "Backward")
+SketchConstraintAngle_32 = Sketch_1.setAngle(SketchLine_36.result(), SketchLine_35.result(), 220, type = "Backward")
+SketchConstraintAngle_33 = Sketch_1.setAngle(SketchLine_35.result(), SketchLine_34.result(), 220, type = "Backward")
+SketchConstraintAngle_34 = Sketch_1.setAngle(SketchLine_36.result(), SketchLine_37.result(), 220, type = "Backward")
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_32.result(), 20)
+SketchConstraintEqual_23 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_31.result())
+SketchConstraintEqual_24 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_34.result())
+SketchConstraintEqual_25 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_35.result())
+SketchConstraintEqual_26 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_36.result())
+SketchLine_38 = Sketch_1.addLine(171.0385831271055, -48.05657162886843, 135.6178801955327, 0.3724878688471688)
+SketchPoint_5 = Sketch_1.addPoint(159.2316821499145, -31.91355179629657)
+SketchConstraintCoincidence_41 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_33.result())
+SketchConstraintCoincidence_42 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_38.result())
+SketchConstraintDistance_23 = Sketch_1.setDistance(SketchLine_32.endPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_24 = Sketch_1.setDistance(SketchLine_38.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_25 = Sketch_1.setDistance(SketchPoint_5.coordinates(), SketchLine_33.endPoint(), 40, True)
+SketchConstraintEqual_27 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_38.result())
+SketchLine_39 = Sketch_1.addLine(175.8477778293761, -43.04483044571408, 125.9994907909914, -9.650994497461493)
+SketchConstraintCoincidence_43 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_39.result())
+SketchConstraintEqual_28 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_39.result())
+SketchConstraintDistance_26 = Sketch_1.setDistance(SketchLine_39.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintAngle_35 = Sketch_1.setAngle(SketchLine_33.result(), SketchLine_38.result(), 340, type = "Backward")
+SketchConstraintAngle_36 = Sketch_1.setAngle(SketchLine_39.result(), SketchLine_38.result(), 340, type = "Backward")
+SketchLine_40 = Sketch_1.addLine(160.1386077477389, -30.42300575990098, 107.5695439158812, -1.500807920835093)
+SketchPoint_6 = Sketch_1.addPoint(142.615586470453, -20.78227314687903)
+SketchConstraintCoincidence_44 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_40.result())
+SketchConstraintCoincidence_45 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_39.result())
+SketchConstraintDistance_27 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_40.startPoint(), 20, True)
+SketchConstraintDistance_28 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_39.endPoint(), 20, True)
+SketchConstraintEqual_29 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_40.result())
+SketchLine_41 = Sketch_1.addLine(147.1612701207084, -22.78891223719074, 124.3190003679524, -12.70545836667124)
+SketchConstraintCoincidence_46 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_41.result())
+SketchConstraintDistance_29 = Sketch_1.setDistance(SketchLine_41.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_37 = Sketch_1.setAngle(SketchLine_39.result(), SketchLine_40.result(), 185, type = "Backward")
+SketchConstraintAngle_38 = Sketch_1.setAngle(SketchLine_41.result(), SketchLine_40.result(), 355, type = "Backward")
+SketchLine_42 = Sketch_1.addLine(161.5464893301474, -27.23370065688114, 104.7537807510641, -7.879418126874779)
+SketchConstraintCoincidence_47 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_42.result())
+SketchConstraintEqual_30 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_42.result())
+SketchConstraintDistance_30 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_42.startPoint(), 20, True)
+SketchConstraintAngle_39 = Sketch_1.setAngle(SketchLine_42.result(), SketchLine_41.result(), 355, type = "Backward")
+SketchLine_43 = Sketch_1.addLine(181.4578745011218, -30.33615510881286, 123.1944424551186, -16.0053321659121)
+SketchConstraintCoincidence_48 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_43.result())
+SketchConstraintEqual_31 = Sketch_1.setEqual(SketchLine_42.result(), SketchLine_43.result())
+SketchConstraintDistance_31 = Sketch_1.setDistance(SketchLine_43.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_40 = Sketch_1.setAngle(SketchLine_42.result(), SketchLine_43.result(), 185, type = "Backward")
+SketchLine_44 = Sketch_1.addLine(182.1427435468735, -26.91447124022047, 122.8520079322427, -17.71617410020831)
+SketchConstraintCoincidence_49 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_44.result())
+SketchConstraintDistance_32 = Sketch_1.setDistance(SketchLine_44.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_41 = Sketch_1.setAngle(SketchLine_43.result(), SketchLine_44.result(), 355, type = "Backward")
+SketchConstraintEqual_32 = Sketch_1.setEqual(SketchLine_43.result(), SketchLine_44.result())
+SketchLine_45 = Sketch_1.addLine(182.5267870601237, -23.44611764141531, 122.6599861756176, -19.45035089961089)
+SketchConstraintCoincidence_50 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_45.result())
+SketchConstraintEqual_33 = Sketch_1.setEqual(SketchLine_44.result(), SketchLine_45.result())
+SketchConstraintDistance_33 = Sketch_1.setDistance(SketchLine_45.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_42 = Sketch_1.setAngle(SketchLine_45.result(), SketchLine_44.result(), 355, type = "Backward")
+SketchConstraintCoincidence_51 = Sketch_1.setCoincident(SketchLine_37.startPoint(), SketchLine_45.result())
+model.do()
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_9f-SketchLine_15f-SketchLine_7f-SketchLine_6r-SketchLine_5f-SketchLine_4r"), model.selection("FACE", "Sketch_1/Face-SketchLine_16f-SketchLine_17f-SketchLine_18f-SketchLine_24f-SketchLine_30f-SketchLine_22f-SketchLine_21r-SketchLine_20f-SketchLine_19r"), model.selection("FACE", "Sketch_1/Face-SketchLine_31f-SketchLine_32f-SketchLine_33f-SketchLine_39f-SketchLine_45f-SketchLine_37f-SketchLine_36r-SketchLine_35f-SketchLine_34r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+model.do()
+
+model.end()
+
+from GeomAPI import *
+
+REF_VOLUME = 25018.7130187615
+
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [11, 11, 11])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [54, 54, 54])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [108, 108, 108])
+model.testResultsVolumes(Extrusion_1, [REF_VOLUME, REF_VOLUME, REF_VOLUME])
+
+assert(model.checkPythonDump())
--- /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
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "Ang", "140")
+model.addParameter(Part_1_doc, "dAng", "5")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, 0.4653113240225388, -68.74815303974528)
+SketchLine_2 = Sketch_1.addLine(0.4653113240225388, -68.74815303974528, 8.542125432770632, -50.45156664083665)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(8.542125432770632, -50.45156664083665, -8.178735979228234, 7.171456480488104)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-17.48270627886662, -77.57247534383079, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -36.90385046950819, -72.79553507559329)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(-48.71075203912585, -56.65251567631857, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(-30.39232801419296, -18.99499937550162, -47.37883052420096, -36.69691533260352)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.endPoint())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), "Ang", type = "Direct")
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), "Ang", type = "Direct")
+SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_4.result(), "Ang", type = "Direct")
+SketchConstraintAngle_4 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_5.result(), "Ang", type = "Direct")
+SketchConstraintAngle_5 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), "Ang", type = "Direct")
+SketchConstraintAngle_6 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_7.result(), "Ang", type = "Direct")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_4.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_5.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_6.result())
+SketchLine_8 = Sketch_1.addLine(14.775406531722, -47.38691166633646, -20.64529817713098, 1.042146531487715)
+SketchPoint_1 = Sketch_1.addPoint(2.968504962104344, -31.24389226706174)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_3.result())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_8.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.endPoint(), 40, True)
+SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_8.result())
+SketchLine_9 = Sketch_1.addLine(19.58460105006861, -42.37517030669127, -30.26368721382418, -8.981336187802668)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintEqual_6 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_9.result())
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_9.startPoint(), SketchPoint_1.coordinates(), 20, True)
+SketchConstraintAngle_7 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_8.result(), "(180-Ang)/2", type = "Direct")
+SketchConstraintAngle_8 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_8.result(), "(180-Ang)/2", type = "Direct")
+SketchLine_10 = Sketch_1.addLine(3.875430505227681, -29.75334619738324, -48.69363438803513, -0.8311502875301234)
+SketchPoint_2 = Sketch_1.addPoint(-13.64759112585992, -20.1126142274322)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_10.result())
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_9.result())
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_10.startPoint(), 20, True)
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_9.endPoint(), 20, True)
+SketchConstraintEqual_7 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(0.001529676402264532, -26.13785899518266, -31.94417752476854, -12.03580011868412)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_11.result())
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchLine_11.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_9 = Sketch_1.setAngle(SketchLine_9.result(), SketchLine_10.result(), "180-dAng", type = "Direct")
+SketchConstraintAngle_10 = Sketch_1.setAngle(SketchLine_11.result(), SketchLine_10.result(), "dAng", type = "Direct")
+SketchLine_12 = Sketch_1.addLine(5.283311970593094, -26.56404104269606, -51.50939731876596, -7.20976059690448)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_12.result())
+SketchConstraintEqual_8 = Sketch_1.setEqual(SketchLine_9.result(), SketchLine_12.result())
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchLine_12.startPoint(), 20, True)
+SketchConstraintAngle_11 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_11.result(), "dAng", type = "Direct")
+SketchLine_13 = Sketch_1.addLine(25.19469725542325, -29.66649476390714, -33.06873531650151, -15.33567395919474)
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_13.result())
+SketchConstraintEqual_9 = Sketch_1.setEqual(SketchLine_12.result(), SketchLine_13.result())
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchLine_13.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_12 = Sketch_1.setAngle(SketchLine_12.result(), SketchLine_13.result(), "180-dAng", type = "Direct")
+SketchLine_14 = Sketch_1.addLine(25.87956617560386, -26.24481087018098, -33.41116977659181, -17.04651590605781)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_14.result())
+SketchConstraintDistance_10 = Sketch_1.setDistance(SketchLine_14.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_13 = Sketch_1.setAngle(SketchLine_13.result(), SketchLine_14.result(), "dAng", type = "Direct")
+SketchConstraintEqual_10 = Sketch_1.setEqual(SketchLine_13.result(), SketchLine_14.result())
+SketchLine_15 = Sketch_1.addLine(26.26360956157018, -22.77645725728195, -33.60319146957497, -18.78069271250733)
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_15.result())
+SketchConstraintEqual_11 = Sketch_1.setEqual(SketchLine_14.result(), SketchLine_15.result())
+SketchConstraintDistance_11 = Sketch_1.setDistance(SketchLine_15.endPoint(), SketchPoint_2.coordinates(), 20, True)
+SketchConstraintAngle_14 = Sketch_1.setAngle(SketchLine_15.result(), SketchLine_14.result(), "dAng", type = "Direct")
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_15.result())
+SketchLine_16 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 78.00643494689578, -67.38706888260469)
+SketchLine_17 = Sketch_1.addLine(78.00643494689578, -67.38706888260469, 86.19687277706721, -49.141063069)
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_16.endPoint(), SketchLine_17.startPoint())
+SketchLine_18 = Sketch_1.addLine(86.19687277706721, -49.141063069, 69.83467154684908, 8.584826884311665)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_17.endPoint(), SketchLine_18.startPoint())
+SketchLine_19 = Sketch_1.addLine(60.00388909712782, -76.09960829009104, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_16.startPoint(), SketchLine_19.startPoint())
+SketchLine_20 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 40.61282650688053, -71.20198727360641)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_19.endPoint(), SketchLine_20.endPoint())
+SketchLine_21 = Sketch_1.addLine(28.90654086978602, -54.98585713775849, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_20.startPoint(), SketchLine_21.startPoint())
+SketchLine_22 = Sketch_1.addLine(47.45878924889096, -17.44298467461911, 30.36253333631381, -35.03892539532215)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_21.endPoint(), SketchLine_22.endPoint())
+SketchConstraintAngle_15 = Sketch_1.setAngle(SketchLine_16.result(), SketchLine_17.result(), "180-Ang", type = "Supplementary")
+SketchConstraintAngle_16 = Sketch_1.setAngle(SketchLine_18.result(), SketchLine_17.result(), "180-Ang", type = "Supplementary")
+SketchConstraintAngle_17 = Sketch_1.setAngle(SketchLine_16.result(), SketchLine_19.result(), "180-Ang", type = "Supplementary")
+SketchConstraintAngle_18 = Sketch_1.setAngle(SketchLine_21.result(), SketchLine_20.result(), "180-Ang", type = "Supplementary")
+SketchConstraintAngle_19 = Sketch_1.setAngle(SketchLine_20.result(), SketchLine_19.result(), "180-Ang", type = "Supplementary")
+SketchConstraintAngle_20 = Sketch_1.setAngle(SketchLine_21.result(), SketchLine_22.result(), "180-Ang", type = "Supplementary")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_17.result(), 20)
+SketchConstraintEqual_12 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_16.result())
+SketchConstraintEqual_13 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_19.result())
+SketchConstraintEqual_14 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_20.result())
+SketchConstraintEqual_15 = Sketch_1.setEqual(SketchLine_17.result(), SketchLine_21.result())
+SketchLine_23 = Sketch_1.addLine(92.44909133742235, -46.11522988707736, 57.3302344261388, 2.533160520466375)
+SketchPoint_3 = Sketch_1.addPoint(80.74280570032784, -29.89909975122945)
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_18.result())
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_23.result())
+SketchConstraintDistance_12 = Sketch_1.setDistance(SketchLine_17.endPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_13 = Sketch_1.setDistance(SketchLine_23.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintDistance_14 = Sketch_1.setDistance(SketchPoint_3.coordinates(), SketchLine_18.endPoint(), 40, True)
+SketchConstraintEqual_16 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_23.result())
+SketchLine_24 = Sketch_1.addLine(97.289359083568, -41.13349208617944, 47.64969893384747, -7.430315081329468)
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_24.result())
+SketchConstraintEqual_17 = Sketch_1.setEqual(SketchLine_18.result(), SketchLine_24.result())
+SketchConstraintDistance_15 = Sketch_1.setDistance(SketchLine_24.startPoint(), SketchPoint_3.coordinates(), 20, True)
+SketchConstraintAngle_21 = Sketch_1.setAngle(SketchLine_18.result(), SketchLine_23.result(), "90+Ang/2", type = "Supplementary")
+SketchConstraintAngle_22 = Sketch_1.setAngle(SketchLine_24.result(), SketchLine_23.result(), "90+Ang/2", type = "Supplementary")
+SketchLine_25 = Sketch_1.addLine(81.65898287743471, -28.41422234660911, 29.27079119639352, 0.8343224443798635)
+SketchPoint_4 = Sketch_1.addPoint(64.19625231708766, -18.66470741627946)
+SketchConstraintCoincidence_27 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_25.result())
+SketchConstraintCoincidence_28 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_24.result())
+SketchConstraintDistance_16 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_25.startPoint(), 20, True)
+SketchConstraintDistance_17 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_24.endPoint(), 20, True)
+SketchConstraintEqual_18 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_25.result())
+SketchLine_26 = Sketch_1.addLine(95.51651619313817, -32.72404055044315, 45.95024650348294, -10.47426958610802)
+SketchConstraintCoincidence_29 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_26.result())
+SketchConstraintDistance_18 = Sketch_1.setDistance(SketchLine_26.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_23 = Sketch_1.setAngle(SketchLine_24.result(), SketchLine_25.result(), "dAng", type = "Supplementary")
+SketchConstraintAngle_24 = Sketch_1.setAngle(SketchLine_26.result(), SketchLine_25.result(), "dAng", type = "Supplementary")
+SketchLine_27 = Sketch_1.addLine(83.08667026246893, -25.23373396888348, 26.41541642632507, -5.526654311071399)
+SketchConstraintCoincidence_30 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_27.result())
+SketchConstraintEqual_19 = Sketch_1.setEqual(SketchLine_24.result(), SketchLine_27.result())
+SketchConstraintDistance_19 = Sketch_1.setDistance(SketchPoint_4.coordinates(), SketchLine_27.startPoint(), 20, True)
+SketchConstraintAngle_25 = Sketch_1.setAngle(SketchLine_27.result(), SketchLine_26.result(), "dAng", type = "Supplementary")
+SketchLine_28 = Sketch_1.addLine(102.9783774975822, -28.45994944924871, 44.80518972684035, -13.76708639979482)
+SketchConstraintCoincidence_31 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_28.result())
+SketchConstraintEqual_20 = Sketch_1.setEqual(SketchLine_27.result(), SketchLine_28.result())
+SketchConstraintDistance_20 = Sketch_1.setDistance(SketchLine_28.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_26 = Sketch_1.setAngle(SketchLine_27.result(), SketchLine_28.result(), "dAng", type = "Supplementary")
+SketchLine_29 = Sketch_1.addLine(103.6845113974033, -25.04259067061018, 44.45212277692985, -15.47576578911409)
+SketchConstraintCoincidence_32 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_29.result())
+SketchConstraintDistance_21 = Sketch_1.setDistance(SketchLine_29.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_27 = Sketch_1.setAngle(SketchLine_28.result(), SketchLine_29.result(), "180-dAng", type = "Supplementary")
+SketchConstraintEqual_21 = Sketch_1.setEqual(SketchLine_28.result(), SketchLine_29.result())
+SketchLine_30 = Sketch_1.addLine(104.0901158019603, -21.57669234933498, 44.24932057465131, -17.20871494975169)
+SketchConstraintCoincidence_33 = Sketch_1.setCoincident(SketchPoint_4.coordinates(), SketchLine_30.result())
+SketchConstraintEqual_22 = Sketch_1.setEqual(SketchLine_29.result(), SketchLine_30.result())
+SketchConstraintDistance_22 = Sketch_1.setDistance(SketchLine_30.endPoint(), SketchPoint_4.coordinates(), 20, True)
+SketchConstraintAngle_28 = Sketch_1.setAngle(SketchLine_30.result(), SketchLine_29.result(), "180-dAng", type = "Supplementary")
+SketchConstraintCoincidence_34 = Sketch_1.setCoincident(SketchLine_22.startPoint(), SketchLine_30.result())
+
+SketchLine_31 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 156.7284871354776, -69.4178124771163)
+SketchLine_32 = Sketch_1.addLine(156.7284871354776, -69.4178124771163, 164.8053019156854, -51.12122637461573)
+SketchConstraintCoincidence_35 = Sketch_1.setCoincident(SketchLine_31.endPoint(), SketchLine_32.startPoint())
+SketchLine_33 = Sketch_1.addLine(164.8053019156854, -51.12122637461573, 148.0844426183728, 6.501797360341752)
+SketchConstraintCoincidence_36 = Sketch_1.setCoincident(SketchLine_32.endPoint(), SketchLine_33.startPoint())
+SketchLine_34 = Sketch_1.addLine(138.7804692087479, -78.2421341225341, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_37 = Sketch_1.setCoincident(SketchLine_31.startPoint(), SketchLine_34.startPoint())
+SketchLine_35 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 119.3593251934135, -73.46519314156717)
+SketchConstraintCoincidence_38 = Sketch_1.setCoincident(SketchLine_34.endPoint(), SketchLine_35.endPoint())
+SketchLine_36 = Sketch_1.addLine(107.5524242162226, -57.32217330899532, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_39 = Sketch_1.setCoincident(SketchLine_35.startPoint(), SketchLine_36.startPoint())
+SketchLine_37 = Sketch_1.addLine(125.8708496231354, -19.66465768043951, 108.8843464634908, -37.36657301415998)
+SketchConstraintCoincidence_40 = Sketch_1.setCoincident(SketchLine_36.endPoint(), SketchLine_37.endPoint())
+SketchConstraintAngle_29 = Sketch_1.setAngle(SketchLine_31.result(), SketchLine_32.result(), "360-Ang", type = "Backward")
+SketchConstraintAngle_30 = Sketch_1.setAngle(SketchLine_33.result(), SketchLine_32.result(), "360-Ang", type = "Backward")
+SketchConstraintAngle_31 = Sketch_1.setAngle(SketchLine_31.result(), SketchLine_34.result(), "360-Ang", type = "Backward")
+SketchConstraintAngle_32 = Sketch_1.setAngle(SketchLine_36.result(), SketchLine_35.result(), "360-Ang", type = "Backward")
+SketchConstraintAngle_33 = Sketch_1.setAngle(SketchLine_35.result(), SketchLine_34.result(), "360-Ang", type = "Backward")
+SketchConstraintAngle_34 = Sketch_1.setAngle(SketchLine_36.result(), SketchLine_37.result(), "360-Ang", type = "Backward")
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_32.result(), 20)
+SketchConstraintEqual_23 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_31.result())
+SketchConstraintEqual_24 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_34.result())
+SketchConstraintEqual_25 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_35.result())
+SketchConstraintEqual_26 = Sketch_1.setEqual(SketchLine_32.result(), SketchLine_36.result())
+SketchLine_38 = Sketch_1.addLine(171.0385831271055, -48.05657162886843, 135.6178801955327, 0.3724878688471688)
+SketchPoint_5 = Sketch_1.addPoint(159.2316821499145, -31.91355179629657)
+SketchConstraintCoincidence_41 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_33.result())
+SketchConstraintCoincidence_42 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_38.result())
+SketchConstraintDistance_23 = Sketch_1.setDistance(SketchLine_32.endPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_24 = Sketch_1.setDistance(SketchLine_38.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintDistance_25 = Sketch_1.setDistance(SketchPoint_5.coordinates(), SketchLine_33.endPoint(), 40, True)
+SketchConstraintEqual_27 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_38.result())
+SketchLine_39 = Sketch_1.addLine(175.8477778293761, -43.04483044571408, 125.9994907909914, -9.650994497461493)
+SketchConstraintCoincidence_43 = Sketch_1.setCoincident(SketchPoint_5.coordinates(), SketchLine_39.result())
+SketchConstraintEqual_28 = Sketch_1.setEqual(SketchLine_33.result(), SketchLine_39.result())
+SketchConstraintDistance_26 = Sketch_1.setDistance(SketchLine_39.startPoint(), SketchPoint_5.coordinates(), 20, True)
+SketchConstraintAngle_35 = Sketch_1.setAngle(SketchLine_33.result(), SketchLine_38.result(), "360-(180-Ang)/2", type = "Backward")
+SketchConstraintAngle_36 = Sketch_1.setAngle(SketchLine_39.result(), SketchLine_38.result(), "360-(180-Ang)/2", type = "Backward")
+SketchLine_40 = Sketch_1.addLine(160.1386077477389, -30.42300575990098, 107.5695439158812, -1.500807920835093)
+SketchPoint_6 = Sketch_1.addPoint(142.615586470453, -20.78227314687903)
+SketchConstraintCoincidence_44 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_40.result())
+SketchConstraintCoincidence_45 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_39.result())
+SketchConstraintDistance_27 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_40.startPoint(), 20, True)
+SketchConstraintDistance_28 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_39.endPoint(), 20, True)
+SketchConstraintEqual_29 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_40.result())
+SketchLine_41 = Sketch_1.addLine(147.1612701207084, -22.78891223719074, 124.3190003679524, -12.70545836667124)
+SketchConstraintCoincidence_46 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_41.result())
+SketchConstraintDistance_29 = Sketch_1.setDistance(SketchLine_41.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_37 = Sketch_1.setAngle(SketchLine_39.result(), SketchLine_40.result(), "180+dAng", type = "Backward")
+SketchConstraintAngle_38 = Sketch_1.setAngle(SketchLine_41.result(), SketchLine_40.result(), "360-dAng", type = "Backward")
+SketchLine_42 = Sketch_1.addLine(161.5464893301474, -27.23370065688114, 104.7537807510641, -7.879418126874779)
+SketchConstraintCoincidence_47 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_42.result())
+SketchConstraintEqual_30 = Sketch_1.setEqual(SketchLine_39.result(), SketchLine_42.result())
+SketchConstraintDistance_30 = Sketch_1.setDistance(SketchPoint_6.coordinates(), SketchLine_42.startPoint(), 20, True)
+SketchConstraintAngle_39 = Sketch_1.setAngle(SketchLine_42.result(), SketchLine_41.result(), "360-dAng", type = "Backward")
+SketchLine_43 = Sketch_1.addLine(181.4578745011218, -30.33615510881286, 123.1944424551186, -16.0053321659121)
+SketchConstraintCoincidence_48 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_43.result())
+SketchConstraintEqual_31 = Sketch_1.setEqual(SketchLine_42.result(), SketchLine_43.result())
+SketchConstraintDistance_31 = Sketch_1.setDistance(SketchLine_43.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_40 = Sketch_1.setAngle(SketchLine_42.result(), SketchLine_43.result(), "180+dAng", type = "Backward")
+SketchLine_44 = Sketch_1.addLine(182.1427435468735, -26.91447124022047, 122.8520079322427, -17.71617410020831)
+SketchConstraintCoincidence_49 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_44.result())
+SketchConstraintDistance_32 = Sketch_1.setDistance(SketchLine_44.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_41 = Sketch_1.setAngle(SketchLine_43.result(), SketchLine_44.result(), "360-dAng", type = "Backward")
+SketchConstraintEqual_32 = Sketch_1.setEqual(SketchLine_43.result(), SketchLine_44.result())
+SketchLine_45 = Sketch_1.addLine(182.5267870601237, -23.44611764141531, 122.6599861756176, -19.45035089961089)
+SketchConstraintCoincidence_50 = Sketch_1.setCoincident(SketchPoint_6.coordinates(), SketchLine_45.result())
+SketchConstraintEqual_33 = Sketch_1.setEqual(SketchLine_44.result(), SketchLine_45.result())
+SketchConstraintDistance_33 = Sketch_1.setDistance(SketchLine_45.endPoint(), SketchPoint_6.coordinates(), 20, True)
+SketchConstraintAngle_42 = Sketch_1.setAngle(SketchLine_45.result(), SketchLine_44.result(), "360-dAng", type = "Backward")
+SketchConstraintCoincidence_51 = Sketch_1.setCoincident(SketchLine_37.startPoint(), SketchLine_45.result())
+model.do()
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_9f-SketchLine_15f-SketchLine_7f-SketchLine_6r-SketchLine_5f-SketchLine_4r"), model.selection("FACE", "Sketch_1/Face-SketchLine_16f-SketchLine_17f-SketchLine_18f-SketchLine_24f-SketchLine_30f-SketchLine_22f-SketchLine_21r-SketchLine_20f-SketchLine_19r"), model.selection("FACE", "Sketch_1/Face-SketchLine_31f-SketchLine_32f-SketchLine_33f-SketchLine_39f-SketchLine_45f-SketchLine_37f-SketchLine_36r-SketchLine_35f-SketchLine_34r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+model.do()
+
+model.end()
+
+from GeomAPI import *
+
+REF_VOLUME = 25018.7130187615
+
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [11, 11, 11])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [54, 54, 54])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [108, 108, 108])
+model.testResultsVolumes(Extrusion_1, [REF_VOLUME, REF_VOLUME, REF_VOLUME])
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-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 constraint coincidence applied for B-spline curve and its sub-results
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-21"
+
+class TestCoincidenceBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+
+ self.myPoles = [GeomAPI_Pnt2d(-10, -30), GeomAPI_Pnt2d(20, -15), GeomAPI_Pnt2d(-10, 0), GeomAPI_Pnt2d(20, 15), GeomAPI_Pnt2d(-10, 30)]
+ self.myWeights = [1, 3, 5, 3, 1]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = self.myWeights)
+ self.myControlPoles = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ self.myControlLines = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+
+ self.myDOF = len(self.myPoles) * 2
+ self.myOrigin = self.mySketch.addPoint("Origin")
+ self.myOX = self.mySketch.addLine("OX")
+ model.do()
+ self.myExpectFailure = False
+ self.myNbPoints = len(self.myPoles) + 1
+ self.myNbLines = len(self.myPoles)
+ self.myNbBSplines = 1
+ self.myNbInternalConstraints = len(self.myPoles) * 3 - 2
+ self.myNbCoincidences = 1
+
+ def tearDown(self):
+ model.end()
+ if self.myExpectFailure:
+ assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+ model.undo()
+ else:
+ self.checkDOF()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbBSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternalConstraints)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidences)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def setCoincidentWithOrigin(self, thePoint):
+ self.mySketch.setCoincident(thePoint, self.myOrigin.coordinates())
+ self.myDOF -= 2
+ model.do()
+
+ def setCoincidentWithOX(self, thePoint):
+ self.mySketch.setCoincident(thePoint, self.myOX.result())
+ self.myDOF -= 1
+ model.do()
+
+ def assertPoles(self):
+ poles = self.mySpline.poles()
+ assert(poles.size() == len(self.myPoles))
+ for index in range(0, len(self.myPoles)):
+ self.assertPoints(self.myPoles[index], poles.pnt(index))
+
+ def assertPoints(self, thePoint1, thePoint2):
+ self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+ self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+ def assertPointOnLine(self, thePoint, theLineStart, theLineEnd):
+ vecP = [thePoint.x() - theLineStart.x(), thePoint.y() - theLineStart.y()]
+ vecL = [theLineEnd.x() - theLineStart.x(), theLineEnd.y() - theLineStart.y()]
+ dist = math.fabs(vecP[0] * vecL[1] - vecP[1] * vecL[0]) / math.hypot(vecL[0], vecL[1])
+ self.assertAlmostEqual(dist, 0.0)
+
+ def assertPointOnSpline(self, thePoint, theSpline):
+ point = GeomAPI_Pnt(thePoint.x(), thePoint.y(), 0.0)
+ bspline = GeomAPI_Curve(theSpline.results()[-1].resultSubShapePair()[0].shape())
+ proj = bspline.project(point)
+ self.assertAlmostEqual(point.distance(proj), 0.0)
+
+
+ def test_origin_equal_start_point(self):
+ """ Test 1. Make start point of B-spline coincident with the Origin
+ """
+ self.setCoincidentWithOrigin(self.mySpline.startPoint())
+ self.myPoles[0].setX(0)
+ self.myPoles[0].setY(0)
+ self.assertPoles()
+
+ def test_origin_equal_end_point(self):
+ """ Test 2. Make end point of B-spline coincident with the Origin
+ """
+ self.setCoincidentWithOrigin(self.mySpline.endPoint())
+ self.myPoles[-1].setX(0)
+ self.myPoles[-1].setY(0)
+ self.assertPoles()
+
+ def test_origin_equal_pole(self):
+ """ Test 3. Make one of B-spline poles coincident with the Origin
+ """
+ self.setCoincidentWithOrigin(SketchAPI_Point(self.myControlPoles[1]).coordinates())
+ self.myPoles[1].setX(0)
+ self.myPoles[1].setY(0)
+ self.assertPoles()
+
+ def test_origin_on_bspline(self):
+ """ Test 4. (expected failure) Make Origin lying on the B-spline curve
+ """
+ self.mySketch.setCoincident(self.mySpline.defaultResult(), self.myOrigin.coordinates())
+ self.myDOF -= 1
+ model.do()
+ self.myExpectFailure = True
+
+ def test_point_on_bspline(self):
+ """ Test 5. Place free point on the B-spline curve
+ """
+ point = self.mySketch.addPoint(1, 0)
+ self.mySketch.setCoincident(self.myOX.defaultResult(), point.coordinates())
+ self.mySketch.setCoincident(self.mySpline.defaultResult(), point.coordinates())
+ model.do()
+ self.myNbPoints += 1
+ self.myNbCoincidences += 1
+ self.assertPointOnSpline(point.coordinates(), self.mySpline)
+
+
+ def test_start_point_on_axis(self):
+ """ Test 6. Make start point of B-spline coincident with the OX
+ """
+ self.setCoincidentWithOX(self.mySpline.startPoint())
+ self.myPoles[0].setY(0)
+ self.assertPoles()
+
+ def test_end_point_on_axis(self):
+ """ Test 7. Make end point of B-spline coincident with the OX
+ """
+ self.setCoincidentWithOX(self.mySpline.endPoint())
+ self.myPoles[-1].setY(0)
+ self.assertPoles()
+
+ def test_pole_on_axis(self):
+ """ Test 8. Make one of B-spline poles coincident with the OX
+ """
+ self.setCoincidentWithOX(SketchAPI_Point(self.myControlPoles[1]).coordinates())
+ self.myPoles[1].setY(0)
+ self.assertPoles()
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
self.checkPointOnEllipse(thePoint, anEllipse)
# check angles
TOLERANCE = 1.e-5
- startAngle = 0; startPoint = GeomAPI_Pnt(theArc.startPoint().x(), theArc.startPoint().y(), 0)
- startAngle = anEllipse.parameter(startPoint, TOLERANCE, startAngle)
- endAngle = 0; endPoint = GeomAPI_Pnt(theArc.endPoint().x(), theArc.endPoint().y(), 0)
- endAngle = anEllipse.parameter(endPoint, TOLERANCE, endAngle)
- midAngle = 0; midPoint = GeomAPI_Pnt(thePoint.x(), thePoint.y(), 0)
- midAngle = anEllipse.parameter(midPoint, TOLERANCE, midAngle)
+ startPoint = GeomAPI_Pnt(theArc.startPoint().x(), theArc.startPoint().y(), 0)
+ isCalculated, startAngle = anEllipse.parameter(startPoint, TOLERANCE)
+ endPoint = GeomAPI_Pnt(theArc.endPoint().x(), theArc.endPoint().y(), 0)
+ isCalculated, endAngle = anEllipse.parameter(endPoint, TOLERANCE)
+ midPoint = GeomAPI_Pnt(thePoint.x(), thePoint.y(), 0)
+ isCalculated, midAngle = anEllipse.parameter(midPoint, TOLERANCE)
diffMS = self.toPeriod(midAngle - startAngle)
diffEM = self.toPeriod(endAngle - midAngle)
self.assertAlmostEqual(diffMS, diffEM)
--- /dev/null
+# Copyright (C) 2019-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 constraint "Tangent" applied to B-spline and another entity
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from GeomAlgoAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-22"
+
+class TestTangentBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(-10, -30), GeomAPI_Pnt2d(20, -15), GeomAPI_Pnt2d(-10, 0), GeomAPI_Pnt2d(20, 15), GeomAPI_Pnt2d(-10, 30)]
+ self.myWeights = [1, 3, 5, 3, 1]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = self.myWeights)
+ self.myControlPoles = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ self.myControlLines = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.myExpectedFailure = False
+ self.myDOF = len(self.myPoles) * 2
+ self.myNbPoints = len(self.myPoles)
+ self.myNbLines = len(self.myPoles) - 1
+ self.myNbArcs = 0
+ self.myNbCircles = 0
+ self.myNbEllipses = 0
+ self.myNbEllipticArcs = 0
+ self.myNbBSplines = 1
+ self.myNbInternals = len(self.myPoles) * 3 - 2
+ self.myNbCoincidence = 0
+ self.myNbTangency = 0
+
+ def tearDown(self):
+ model.end()
+ if self.myExpectedFailure:
+ assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+ model.undo()
+ else:
+ self.checkDOF()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", self.myNbEllipticArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbBSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternals)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidence)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", self.myNbTangency)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def assertTangentFeatures(self, theFeature1, theFeature2):
+ shapes = [theFeature1.results()[-1].resultSubShapePair()[0].shape(),
+ theFeature2.results()[-1].resultSubShapePair()[0].shape()]
+ for s in shapes:
+ e = shapeToEdge(s)
+ if e.isLine() or e.isArc() or e.isEllipse():
+ params = e.getRange()
+ e.setRange(params[0] - 100, params[1] + 100)
+ # TODO (azv): complete checking the tangent curves
+
+ def assertPointLineDistance(self, thePoint, theLine, theExpectedDistance = 0):
+ dist = model.distancePointLine(thePoint, theLine)
+ self.assertAlmostEqual(dist, theExpectedDistance)
+
+ def assertTangentLineCircle(self, theLine, theCircle):
+ self.assertPointLineDistance(theCircle.center(), theLine, theCircle.radius().value())
+
+ def assertTangentLineEllipse(self, theLine, theEllipse):
+ aLine = GeomAPI_Lin2d(theLine.startPoint().pnt(), theLine.endPoint().pnt())
+ projF1 = aLine.project(theEllipse.firstFocus().pnt())
+ projF2 = aLine.project(theEllipse.secondFocus().pnt())
+
+ distF1P1 = model.distancePointPoint(theEllipse.firstFocus(), projF1)
+ distF2P2 = model.distancePointPoint(theEllipse.secondFocus(), projF2)
+
+ tgPoint = GeomAPI_Pnt2d((projF1.x() * distF2P2 + projF2.x() * distF1P1) / (distF1P1 + distF2P2), (projF1.y() * distF2P2 + projF2.y() * distF1P1) / (distF1P1 + distF2P2))
+ distF1T = model.distancePointPoint(theEllipse.firstFocus(), tgPoint)
+ distF2T = model.distancePointPoint(theEllipse.secondFocus(), tgPoint)
+ self.assertAlmostEqual(distF1T + distF2T, 2 * theEllipse.majorRadius().value())
+
+
+ def test_line_tangent(self):
+ """ Test 1. Set tangency between B-spline and a line
+ """
+ aLine = self.mySketch.addLine(10, -10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(aLine, self.mySpline)
+
+ def test_circle_tangent(self):
+ """ Test 2. Set tangency between B-spline and a circle
+ """
+ aCircle = self.mySketch.addCircle(10, 10, 20)
+ self.myNbCircles += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(aCircle, self.mySpline)
+
+ def test_arc_tangent(self):
+ """ Test 3. Set tangency between B-spline and an arc
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anArc, self.mySpline)
+
+ def test_ellipse_tangent(self):
+ """ Test 4. Set tangency between B-spline and an ellipse
+ """
+ anEllipse = self.mySketch.addEllipse(10, 10, 20, 10, 7)
+ self.myNbEllipses += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anEllipse, self.mySpline)
+
+ def test_elliptic_arc_tangent(self):
+ """ Test 5. Set tangency between B-spline and an elliptic arc
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, 10, 20, 10, 22.2065556157337, 10, 10, 17, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anEllipticArc, self.mySpline)
+
+ def test_spline_tangent(self):
+ """ Test 6. Set tangency between two B-spline curves
+ """
+ aSpline = self.mySketch.addSpline(poles = [(50, -20), (40, 0), (50, 20)])
+ self.myNbBSplines += 1
+ self.myDOF += aSpline.poles().size() * 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ #self.assertTangentFeatures(aSpline, self.mySpline)
+ self.myExpectedFailure = True
+
+
+ def test_line_tangent_coincident_by_pole(self):
+ """ Test 7. Set tangency between B-spline and a line coincident with B-spline start point
+ """
+ aLine = self.mySketch.addLine(-15, -25, 50, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aLine.result())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertPointLineDistance(self.mySpline.startPoint(), aLine)
+ self.assertTangentFeatures(aLine, self.mySpline)
+
+ def test_circle_tangent_coincident_by_pole(self):
+ """ Test 8. Set tangency between B-spline and a circle coincident with B-spline end point
+ """
+ aCircle = self.mySketch.addCircle(10, 10, 20)
+ self.myNbCircles += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aCircle.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(aCircle, self.mySpline)
+ dist = model.distancePointPoint(self.mySpline.startPoint(), aCircle.center())
+ self.assertAlmostEqual(dist, aCircle.radius().value())
+
+ def test_arc_tangent_coincident_by_pole(self):
+ """ Test 9. Set tangency between B-spline and an arc coincident with B-spline end point
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.endPoint(), anArc.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anArc, self.mySpline)
+ dist = model.distancePointPoint(self.mySpline.endPoint(), anArc.center())
+ self.assertAlmostEqual(dist, anArc.radius().value())
+
+ def test_ellipse_tangent_coincident_by_pole(self):
+ """ Test 10. Set tangency between B-spline and an ellipse coincident with B-spline start point
+ """
+ anEllipse = self.mySketch.addEllipse(10, 10, 20, 10, 7)
+ self.myNbEllipses += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anEllipse.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipse)
+
+ def test_elliptic_arc_tangent_coincident_by_pole(self):
+ """ Test 11. Set tangency between B-spline and an elliptic arc coincident with B-spline start point
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, 10, 20, 10, 22.2065556157337, 10, 10, 17, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anEllipticArc.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+
+
+ def test_line_tangent_coincident_by_boundaries(self):
+ """ Test 12. Set tangency between B-spline and a line, coincident by their start points
+ """
+ aLine = self.mySketch.addLine(10, -10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aLine.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertPointLineDistance(aLine.endPoint(), self.myControlLines[0])
+
+ def test_arc_tangent_coincident_by_boundaries(self):
+ """ Test 13. Set tangency between B-spline and an arc, coincident by their start points
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineCircle(SketchAPI_Line(self.myControlLines[0]), anArc)
+
+ def test_elliptic_arc_tangent_coincident_by_boundaries(self):
+ """ Test 14. Set tangency between B-spline and an elliptic arc, coincident by their start points
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, -10, 20, -10, 22.2065556157337, -10, 10, 3, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anEllipticArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+
+ def test_spline_tangent_coincident_by_boundaries(self):
+ """ Test 15. Set tangency between two B-spline curves coincident with B-spline start point
+ """
+ aSpline = self.mySketch.addSpline(poles = [(50, -20), (40, 0), (50, 20)])
+ self.myNbBSplines += 1
+ self.myDOF += aSpline.poles().size() * 2
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aSpline.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ #self.assertPointLineDistance(aSpline.poles()[1], self.myControlLines[0])
+ self.myExpectedFailure = True
+
+
+ def test_line_tangent_coincident_by_aux(self):
+ """ Test 16. Set tangency between B-spline and a line, coincident by their start points
+ """
+ aLine = self.mySketch.addLine(10, -10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), aLine.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertPointLineDistance(aLine.endPoint(), self.myControlLines[0])
+
+ def test_arc_tangent_coincident_by_aux(self):
+ """ Test 17. Set tangency between B-spline and an arc, coincident by their start points
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), anArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineCircle(SketchAPI_Line(self.myControlLines[0]), anArc)
+
+ def test_elliptic_arc_tangent_coincident_by_aux(self):
+ """ Test 18. Set tangency between B-spline and an elliptic arc, coincident by their start points
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, 10, 20, 10, 22.2065556157337, 10, 10, 17, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), anEllipticArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+
+ def test_spline_tangent_coincident_by_aux(self):
+ """ Test 19. Set tangency between two B-spline curves coincident with B-spline start point
+ """
+ aSpline = self.mySketch.addSpline(poles = [(50, -20), (40, 0), (50, 20)])
+ self.myNbBSplines += 1
+ self.myDOF += aSpline.poles().size() * 2
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), aSpline.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ #self.assertPointLineDistance(aSpline.poles().pnt(1), self.myControlLines[0])
+ self.myExpectedFailure = True
+
+
+
+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
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-17"
+
+class TestBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(50., 50.), GeomAPI_Pnt2d(70., 70.), GeomAPI_Pnt2d(80., 30.), GeomAPI_Pnt2d(50., 10.), GeomAPI_Pnt2d(10., -30.)]
+ self.myPolesCoordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ self.myDegree = 3;
+ self.myDOF = 0
+ self.myNbPoints = 0
+ self.myNbLines = 0
+ self.myNbSplines = 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)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+ def test_bspline_by_coordinates(self):
+ """ Test 1. Create B-spline curve by coordinates of its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPolesCoordinates)
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles(self):
+ """ Test 2. Create B-spline curve by poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_degree_and_poles(self):
+ """ Test 3. Create B-spline curve by poles and degree
+ """
+ self.myDegree = 4
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree, poles = self.myPoles)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles_and_weights(self):
+ """ Test 4. Create B-spline curve by poles and weights
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = [1, 2, 3, 2, 1])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_parametric(self):
+ """ Test 5. Create B-spline curve by whole set of parameters
+ """
+ self.myDegree = 5
+ self.myPolesCoordinates = [(-79.8578274581199, 75.5284518447357),
+ (-64.6205376770376, 62.7428476092882),
+ (-49.3832478959552, 49.9572433738407),
+ (-34.1459581148729, 37.1716391383932),
+ (-18.9086683337906, 24.3860349029457),
+ (-3.55842111132817, 11.5056481200973),
+ (-3.37993197286247, 11.42995541724),
+ (-3.1778022626919, 11.4565662984205),
+ (-3.02498570721059, 11.575876223351),
+ (8.46852511720001, 27.9903107977019),
+ (19.8774589601206, 44.2839569245217),
+ (31.2863928030413, 60.5776030513415),
+ (42.6953266459619, 76.8712491781612),
+ (54.1042604888826, 93.164895304981)
+ ]
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree,
+ poles = self.myPolesCoordinates,
+ weights = [1, 1, 1, 1, 1, 1, 0.957903314642061, 0.95790331464206, 1, 1, 1, 1, 1, 1],
+ knots = [-494.543457494654, 500, 507.372773368102, 1501.91623086297],
+ multiplicities = [6, 4, 4, 6])
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_linear(self):
+ """ Test 6. Create B-spline curve by 2 poles
+ """
+ self.myDegree = 1
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:2])
+ self.myDOF += 4
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_parabola(self):
+ """ Test 7. Create B-spline curve by 3 poles
+ """
+ self.myDegree = 2
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:3])
+ self.myDOF += 6
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_poles(self):
+ """ Test 8. Create B-spline curve and points coincident with its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.mySpline.controlPoles(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbPoints += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_polygon(self):
+ """ Test 9. Create B-spline curve and its control polygon
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.mySpline.controlPolygon(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbLines += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+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 periodic B-spline curve
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-24"
+
+class TestBSplinePeriodic(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(50., 50.), GeomAPI_Pnt2d(70., 70.), GeomAPI_Pnt2d(80., 30.), GeomAPI_Pnt2d(50., 10.), GeomAPI_Pnt2d(10., -30.)]
+ self.myPolesCoordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ self.myDegree = 3;
+ self.myDOF = 0
+ self.myNbPoints = 0
+ self.myNbLines = 0
+ self.myNbSplines = 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, "SketchBSplinePeriodic", self.myNbSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+ def test_bspline_by_coordinates(self):
+ """ Test 1. Create B-spline curve by coordinates of its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPolesCoordinates, periodic = True)
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles(self):
+ """ Test 2. Create B-spline curve by poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_degree_and_poles(self):
+ """ Test 3. Create B-spline curve by poles and degree
+ """
+ self.myDegree = 4
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree, poles = self.myPoles, periodic = True)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles_and_weights(self):
+ """ Test 4. Create B-spline curve by poles and weights
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = [1, 2, 3, 2, 1], periodic = True)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_parametric(self):
+ """ Test 5. Create B-spline curve by whole set of parameters
+ """
+ self.myDegree = 3
+ self.myPolesCoordinates = [(-10, 0), (-20, 20), (0, 10), (20, 20),
+ (10, 0), (20, -20), (0, -10), (-20, -20)
+ ]
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree,
+ poles = self.myPolesCoordinates,
+ weights = [1, 1, 1, 1, 1, 1, 1, 1],
+ knots = [0, 1, 2, 3, 4, 5, 6, 7, 8],
+ multiplicities = [1, 1, 1, 1, 1, 1, 1, 1, 1],
+ periodic = True)
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_linear(self):
+ """ Test 6. Create B-spline curve by 2 poles
+ """
+ self.myDegree = 1
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:2], periodic = True)
+ self.myDOF += 4
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_parabola(self):
+ """ Test 7. Create B-spline curve by 3 poles
+ """
+ self.myDegree = 2
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:3], periodic = True)
+ self.myDOF += 6
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_poles(self):
+ """ Test 8. Create B-spline curve and points coincident with its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.mySpline.controlPoles(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbPoints += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_polygon(self):
+ """ Test 9. Create B-spline curve and its control polygon
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.mySpline.controlPolygon(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbLines += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+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 by references to another features
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from GeomDataAPI import *
+from ModelAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-31"
+
+class TestMacroBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoint = self.mySketch.addPoint(50., 50.)
+ self.myLine = self.mySketch.addLine(30., -1., 70., 19.)
+
+ self.myPoles = [[GeomAPI_Pnt2d(50., 50.), self.myPoint.coordinates()],
+ GeomAPI_Pnt2d(70., 70.),
+ (80., 30.),
+ [GeomAPI_Pnt2d(50., 10.), self.myLine.result()],
+ GeomAPI_Pnt2d(20., 10.)
+ ]
+
+ self.myDegree = 3;
+ self.myDOF = 6
+ self.myNbPoints = 1
+ self.myNbLines = 1
+ self.myNbSplines = 0
+ self.myNbSplinesP = 0
+ self.myNbCoincidences = 0
+ self.myNbInternal = 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.myNbSplinesP)
+ model.testNbSubFeatures(self.mySketch, "SketchMacroBSpline", 0)
+ model.testNbSubFeatures(self.mySketch, "SketchMacroBSplinePeriodic", 0)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidences)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternal)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+ def test_bspline_non_periodic(self):
+ """ Test 1. Create B-spline curve by poles and references to other shapes
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.myDOF += len(self.myPoles) * 2 - 3
+ self.myNbSplines += 1
+ self.myNbPoints += len(self.myPoles)
+ self.myNbLines += len(self.myPoles) - 1
+ self.myNbCoincidences += 2
+ self.myNbInternal += len(self.myPoles) * 3 - 2
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_periodic(self):
+ """ Test 2. Create periodic B-spline curve by poles and references to other shapes
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.myDOF += len(self.myPoles) * 2 - 3
+ self.myNbSplinesP += 1
+ self.myNbPoints += len(self.myPoles)
+ self.myNbLines += len(self.myPoles)
+ self.myNbCoincidences += 2
+ self.myNbInternal += len(self.myPoles) * 3
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_lowlevel(self):
+ """ Test 3. Create macro B-spline on low-level to test attributeRefAttrList
+ """
+ model.end()
+ session = ModelAPI_Session.get()
+ sketch = featureToCompositeFeature(self.mySketch.feature())
+ session.startOperation()
+ bspline = sketch.addFeature("SketchMacroBSpline")
+ poles = geomDataAPI_Point2DArray(bspline.attribute("poles"))
+ weights = bspline.data().realArray("weights")
+ polesRef = bspline.data().refattrlist("poles_ref")
+ bspline.boolean("need_control_poly").setValue(False)
+
+ poles.setSize(3); weights.setSize(3)
+ poles.setPnt(0, GeomAPI_Pnt2d(50., 50.)); weights.setValue(0, 1.0); polesRef.append(self.myPoint.coordinates())
+ poles.setPnt(1, GeomAPI_Pnt2d(50., 10.)); weights.setValue(1, 1.0); polesRef.append(self.myLine.defaultResult())
+ poles.setPnt(2, GeomAPI_Pnt2d(20., 10.)); weights.setValue(2, 1.0); polesRef.append(None)
+
+ assert(polesRef.isInList(self.myPoint.coordinates()))
+ assert(not polesRef.isInList(self.myLine.startPoint()))
+ assert(polesRef.isInList(self.myLine.defaultResult()))
+ assert(not polesRef.isInList(self.myPoint.defaultResult()))
+
+ assert(polesRef.isAttribute(0))
+ assert(not polesRef.isAttribute(1))
+ assert(not polesRef.isAttribute(2))
+ assert(not polesRef.isAttribute(3))
+
+ assert(polesRef.attribute(0) is not None)
+ assert(polesRef.attribute(1) is None)
+ assert(polesRef.attribute(2) is None)
+ assert(polesRef.attribute(3) is None)
+ assert(polesRef.object(0) is not None)
+ assert(polesRef.object(1) is not None)
+ assert(polesRef.object(2) is None)
+ assert(polesRef.object(3) is None)
+
+ polesRef.remove(self.myPoint.coordinates())
+ polesRef.remove(self.myLine.defaultResult())
+ assert(polesRef.size() == 1)
+ polesRef.removeLast()
+
+ polesRef.append(self.myPoint.coordinates())
+ polesRef.append(None)
+ polesRef.append(self.myLine.defaultResult())
+ polesRef.removeLast()
+ polesRef.append(self.myLine.defaultResult())
+
+ session.finishOperation()
+ model.begin()
+ self.myDOF += 6
+ self.myNbSplines += 1
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019-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 movement of the B-spline curve
+"""
+
+import unittest
+import math
+from GeomAPI import *
+from GeomDataAPI import geomDataAPI_Point2DArray
+from SketchAPI import *
+from salome.shaper import model
+
+__updated__ = "2020-01-20"
+
+class TestMoveBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(20., 50.),
+ GeomAPI_Pnt2d(70., 70.),
+ GeomAPI_Pnt2d(80., 30.),
+ GeomAPI_Pnt2d(50., 10.),
+ GeomAPI_Pnt2d(90., -30.)]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.myDOF = len(self.myPoles) * 2
+ model.do()
+ self.checkDOF()
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointCoordinates(self, thePoint, theCoordinates):
+ aCoord = []
+ if issubclass(type(theCoordinates), GeomAPI_Pnt2d):
+ aCoord = [theCoordinates.x(), theCoordinates.y()]
+ else:
+ aCoord = theCoordinates
+ DIGITS = 7 - math.floor(math.log10(math.hypot(aCoord[0], aCoord[1])))
+ self.assertAlmostEqual(thePoint.x(), aCoord[0], DIGITS)
+ self.assertAlmostEqual(thePoint.y(), aCoord[1], DIGITS)
+
+ def checkPoles(self, theBSpline, theCoordinates):
+ poles = theBSpline.poles()
+ for index, point in zip(range(0, len(theCoordinates)), theCoordinates):
+ self.checkPointCoordinates(poles.pnt(index), point)
+
+ def fixPoint(self, thePoint):
+ self.mySketch.setFixed(thePoint)
+ self.myDOF -= 2
+ model.do()
+ self.checkDOF()
+
+
+ def test_move_free_bspline(self):
+ """ Test 1. Movement of a free B-spline dragging the edge
+ """
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point(self):
+ """ Test 2. Movement of start point of a free B-spline curve
+ """
+ newPoles = self.myPoles
+
+ newPoles[0].setX(newPoles[0].x() - 20.)
+ newPoles[0].setY(newPoles[0].y() + 10.)
+ self.mySketch.move(self.mySpline.startPoint(), newPoles[0])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_end_point(self):
+ """ Test 3. Movement of end point of a free B-spline curve
+ """
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_start_point_fixed(self):
+ """ Test 4. Movement of a B-spline dragging the edge when start point is fixed
+ """
+ self.fixPoint(self.mySpline.startPoint())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = [self.myPoles[0]]
+ for pole in self.myPoles[1:]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_start_point_fixed(self):
+ """ Test 5. Movement of start point of a free B-spline curve has no result if the first pole is fixed
+ """
+ self.fixPoint(self.mySpline.startPoint())
+ model.do()
+
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() - 10., self.myPoles[0].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_with_start_point_fixed(self):
+ """ Test 6. Movement of end point of a free B-spline curve when start point is fixed
+ """
+ self.fixPoint(self.mySpline.startPoint())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_end_point_fixed(self):
+ """ Test 7. Movement of a B-spline dragging the edge when end point is fixed
+ """
+ self.fixPoint(self.mySpline.endPoint())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles[:-1]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ newPoles.append(self.myPoles[-1])
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_end_point_fixed(self):
+ """ Test 8. Movement of start point of a free B-spline curve when end point is fixed
+ """
+ self.fixPoint(self.mySpline.endPoint())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[0].setX(newPoles[0].x() + 20.)
+ newPoles[0].setY(newPoles[0].y() + 10.)
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0])
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_with_end_point_fixed(self):
+ """ Test 9. Movement of end point of a free B-spline curve has no result if the last pole is fixed
+ """
+ self.fixPoint(self.mySpline.endPoint())
+ model.do()
+
+ self.mySketch.move(self.mySpline.endPoint(), self.myPoles[-1].x() + 10., self.myPoles[-1].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+
+ def test_move_fixed_bspline(self):
+ """ Test 10. Movement of a fully fixed B-spline
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_start_point_of_fixed_bspline(self):
+ """ Test 11. Movement of start point of a fully fixed B-spline curve
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() + 10., self.myPoles[0].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_of_fixed_bspline(self):
+ """ Test 12. Movement of end point of a fully fixed B-spline curve
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ self.mySketch.move(self.mySpline.endPoint(), self.myPoles[-1].x() + 10., self.myPoles[-1].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+
+ def test_move_bspline_with_fixed_pole(self):
+ """ Test 13. Movement of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ newPoles[1].setX(newPoles[1].x() - dx)
+ newPoles[1].setY(newPoles[1].y() - dy)
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_fixed_pole(self):
+ """ Test 14. Movement of start point of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[0].setX(newPoles[0].x() + 20.)
+ newPoles[0].setY(newPoles[0].y() + 10.)
+ self.mySketch.move(self.mySpline.startPoint(), newPoles[0])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_end_point_with_fixed_pole(self):
+ """ Test 15. Movement of end point of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_fixed_segment(self):
+ """ Test 16. Movement of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = [self.myPoles[0], self.myPoles[1]]
+ for pole in self.myPoles[2:]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_fixed_segment(self):
+ """ Test 17. Movement of start point of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() + 10., self.myPoles[0].y() - 20.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_with_fixed_segment(self):
+ """ Test 18. Movement of end point of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_pole_of_free_bspline(self):
+ """ Test 19. Movement of a pole of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[2].setX(newPoles[2].x() + 20.)
+ newPoles[2].setY(newPoles[2].y() + 20.)
+ self.mySketch.move(SketchAPI_Point(Point_3).coordinates(), newPoles[2])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_segment_of_free_bspline(self):
+ """ Test 20. Movement of a control segment of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ oldPosition = GeomAPI_Pnt2d(0.5 * (self.myPoles[2].x() + self.myPoles[3].x()),
+ 0.5 * (self.myPoles[2].y() + self.myPoles[3].y()))
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(SketchAPI_Line(Line_3).defaultResult(), newPosition)
+ model.do()
+
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = self.myPoles
+ newPoles[2].setX(newPoles[2].x() + dx)
+ newPoles[2].setY(newPoles[2].y() + dy)
+ newPoles[3].setX(newPoles[3].x() + dx)
+ newPoles[3].setY(newPoles[3].y() + dy)
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019-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 movement of the periodic B-spline curve
+"""
+
+import unittest
+import math
+from GeomAPI import *
+from GeomDataAPI import geomDataAPI_Point2DArray
+from SketchAPI import *
+from salome.shaper import model
+
+__updated__ = "2020-01-20"
+
+class TestMoveBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(20., 50.),
+ GeomAPI_Pnt2d(70., 70.),
+ GeomAPI_Pnt2d(80., 30.),
+ GeomAPI_Pnt2d(50., -10.),
+ GeomAPI_Pnt2d(90., -30.)]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.myDOF = len(self.myPoles) * 2
+ model.do()
+ self.checkDOF()
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointCoordinates(self, thePoint, theCoordinates):
+ aCoord = []
+ if issubclass(type(theCoordinates), GeomAPI_Pnt2d):
+ aCoord = [theCoordinates.x(), theCoordinates.y()]
+ else:
+ aCoord = theCoordinates
+ DIGITS = 7 - math.floor(math.log10(math.hypot(aCoord[0], aCoord[1])))
+ self.assertAlmostEqual(thePoint.x(), aCoord[0], DIGITS)
+ self.assertAlmostEqual(thePoint.y(), aCoord[1], DIGITS)
+
+ def checkPoles(self, theBSpline, theCoordinates):
+ poles = theBSpline.poles()
+ for index, point in zip(range(0, len(theCoordinates)), theCoordinates):
+ self.checkPointCoordinates(poles.pnt(index), point)
+
+ def fixPoint(self, thePoint):
+ self.mySketch.setFixed(thePoint)
+ self.myDOF -= 2
+ model.do()
+ self.checkDOF()
+
+
+ def test_move_free_bspline(self):
+ """ Test 1. Movement of a free B-spline dragging the edge
+ """
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_fixed_bspline(self):
+ """ Test 2. Movement of a fully fixed B-spline
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+
+ def test_move_bspline_with_fixed_pole(self):
+ """ Test 3. Movement of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ newPoles[1].setX(newPoles[1].x() - dx)
+ newPoles[1].setY(newPoles[1].y() - dy)
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_fixed_segment(self):
+ """ Test 4. Movement of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4, Line_5] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = [self.myPoles[0], self.myPoles[1]]
+ for pole in self.myPoles[2:]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_pole_of_free_bspline(self):
+ """ Test 5. Movement of a pole of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4, Line_5] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[2].setX(newPoles[2].x() + 20.)
+ newPoles[2].setY(newPoles[2].y() + 20.)
+ self.mySketch.move(SketchAPI_Point(Point_3).coordinates(), newPoles[2])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_segment_of_free_bspline(self):
+ """ Test 6. Movement of a control segment of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4, Line_5] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ oldPosition = GeomAPI_Pnt2d(0.5 * (self.myPoles[2].x() + self.myPoles[3].x()),
+ 0.5 * (self.myPoles[2].y() + self.myPoles[3].y()))
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(SketchAPI_Line(Line_3).defaultResult(), newPosition)
+ model.do()
+
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = self.myPoles
+ newPoles[2].setX(newPoles[2].x() + dx)
+ newPoles[2].setY(newPoles[2].y() + dy)
+ newPoles[3].setX(newPoles[3].x() + dx)
+ newPoles[3].setY(newPoles[3].y() + dy)
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
anEllipticArcPnt4.setValue(-10, 0)
assert(featureToPresentation(anEllipticArc).getAISObject(None) is not None)
aSession.finishOperation()
+
+# Test presentation for MacroBSpline on low-level
+aSession.startOperation()
+aBSpline = aSketchFeature.addFeature("SketchMacroBSpline")
+aPoles = geomDataAPI_Point2DArray(aBSpline.attribute("poles"))
+aPoles.setSize(4)
+aPoles.setPnt(0, 0, 0)
+aPoles.setPnt(1, 10, 0)
+aPoles.setPnt(2, 10, 10)
+aPoles.setPnt(3, 0, 10)
+aWeights = aBSpline.data().realArray("weights")
+aWeights.setSize(4)
+aWeights.setValue(0, 1)
+aWeights.setValue(1, 2)
+aWeights.setValue(2, 2)
+aWeights.setValue(3, 1)
+aBSpline.boolean("need_control_poly").setValue(True)
+assert(featureToPresentation(aBSpline).getAISObject(None) is not None)
+aSession.finishOperation()
+
+# Test presentation for MacroBSplinePeriodic on low-level
+aSession.startOperation()
+aBSplineP = aSketchFeature.addFeature("SketchMacroBSplinePeriodic")
+aPoles = geomDataAPI_Point2DArray(aBSplineP.attribute("poles"))
+aPoles.setSize(4)
+aPoles.setPnt(0, 0, 0)
+aPoles.setPnt(1, 10, 0)
+aPoles.setPnt(2, 10, 10)
+aPoles.setPnt(3, 0, 10)
+aWeights = aBSplineP.data().realArray("weights")
+aWeights.setSize(4)
+aWeights.setValue(0, 1)
+aWeights.setValue(1, 2)
+aWeights.setValue(2, 2)
+aWeights.setValue(3, 1)
+aBSplineP.boolean("need_control_poly").setValue(True)
+assert(featureToPresentation(aBSplineP).getAISObject(None) is not None)
+aSession.finishOperation()
--- /dev/null
+# Copyright (C) 2019-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()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_2 = model.addPoint(Part_1_doc, -10, 5, 10)
+Point_3 = model.addPoint(Part_1_doc, -5, 10, 15)
+Point_4 = model.addPoint(Part_1_doc, 10, 0, 20)
+Point_5 = model.addPoint(Part_1_doc, 10, -10, 15)
+Point_6 = model.addPoint(Part_1_doc, -5, -5, 12)
+Interpolation_1_objects = [model.selection("VERTEX", "Point_1"), model.selection("VERTEX", "Point_2"), model.selection("VERTEX", "Point_3"), model.selection("VERTEX", "Point_4"), model.selection("VERTEX", "Point_5")]
+Interpolation_1 = model.addInterpolation(Part_1_doc, Interpolation_1_objects, False, False)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("EDGE", "Interpolation_1_1"), True)
+SketchBSpline_1 = SketchProjection_1.createdFeature()
+model.do()
+
+Sketch_3 = model.addSketch(Part_1_doc, model.standardPlane("XOZ"))
+SketchProjection_2 = Sketch_3.addProjection(model.selection("EDGE", "Interpolation_1_1"), True)
+SketchBSpline_2 = SketchProjection_2.createdFeature()
+model.do()
+
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchProjection_3 = Sketch_4.addProjection(model.selection("EDGE", "Interpolation_1_1"), True)
+SketchBSpline_3 = SketchProjection_3.createdFeature()
+model.do()
+
+model.end()
+
+from GeomAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+def checkProjection(theBSpline3D, theBSpline2D, theFlags):
+ assert(theBSpline2D.isEdge() and theBSpline2D.edge().isBSpline())
+ poles2D = GeomAPI_BSpline(GeomAPI_Curve(theBSpline2D)).poles()
+ poles3D = theBSpline3D.poles()
+ assert(poles2D.size() == poles3D.size())
+ for p2d, p3d in zip(poles2D, poles3D):
+ assert(math.fabs((p2d.x() - p3d.x()) * theFlags.x()) < TOLERANCE and
+ math.fabs((p2d.y() - p3d.y()) * theFlags.y()) < TOLERANCE and
+ math.fabs((p2d.z() - p3d.z()) * theFlags.z()) < TOLERANCE)
+
+
+bspline0 = GeomAPI_BSpline(GeomAPI_Curve(Interpolation_1.results()[-1].resultSubShapePair()[0].shape()))
+
+bsplineShape1 = SketchBSpline_1.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape1, GeomAPI_Pnt(1, 1, 0))
+
+bsplineShape2 = SketchBSpline_2.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape2, GeomAPI_Pnt(1, 0, 1))
+
+bsplineShape3 = SketchBSpline_3.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape3, GeomAPI_Pnt(0, 1, 1))
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-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()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_2 = model.addPoint(Part_1_doc, -10, 5, 10)
+Point_3 = model.addPoint(Part_1_doc, -5, 10, 15)
+Point_4 = model.addPoint(Part_1_doc, 10, 0, 20)
+Point_5 = model.addPoint(Part_1_doc, 10, -10, 15)
+Point_6 = model.addPoint(Part_1_doc, -5, -5, 12)
+Interpolation_1_objects = [model.selection("VERTEX", "Point_1"), model.selection("VERTEX", "Point_2"), model.selection("VERTEX", "Point_3"), model.selection("VERTEX", "Point_4"), model.selection("VERTEX", "Point_5")]
+Interpolation_1 = model.addInterpolation(Part_1_doc, Interpolation_1_objects, True, False)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("EDGE", "Interpolation_1_1"), True)
+SketchBSpline_1 = SketchProjection_1.createdFeature()
+model.do()
+
+Sketch_3 = model.addSketch(Part_1_doc, model.standardPlane("XOZ"))
+SketchProjection_2 = Sketch_3.addProjection(model.selection("EDGE", "Interpolation_1_1"), True)
+SketchBSpline_2 = SketchProjection_2.createdFeature()
+model.do()
+
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchProjection_3 = Sketch_4.addProjection(model.selection("EDGE", "Interpolation_1_1"), True)
+SketchBSpline_3 = SketchProjection_3.createdFeature()
+model.do()
+
+model.end()
+
+from GeomAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+def checkProjection(theBSpline3D, theBSpline2D, theFlags):
+ assert(theBSpline2D.isEdge() and theBSpline2D.edge().isBSpline())
+ poles2D = GeomAPI_BSpline(GeomAPI_Curve(theBSpline2D)).poles()
+ poles3D = theBSpline3D.poles()
+ assert(poles2D.size() == poles3D.size())
+ for p2d, p3d in zip(poles2D, poles3D):
+ assert(math.fabs((p2d.x() - p3d.x()) * theFlags.x()) < TOLERANCE and
+ math.fabs((p2d.y() - p3d.y()) * theFlags.y()) < TOLERANCE and
+ math.fabs((p2d.z() - p3d.z()) * theFlags.z()) < TOLERANCE)
+
+
+bspline0 = GeomAPI_BSpline(GeomAPI_Curve(Interpolation_1.results()[-1].resultSubShapePair()[0].shape()))
+
+bsplineShape1 = SketchBSpline_1.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape1, GeomAPI_Pnt(1, 1, 0))
+
+bsplineShape2 = SketchBSpline_2.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape2, GeomAPI_Pnt(1, 0, 1))
+
+bsplineShape3 = SketchBSpline_3.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape3, GeomAPI_Pnt(0, 1, 1))
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-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 removing B-spline curve and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbSplines, theNbInternalConstraints):
+ model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+ model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+ model.testNbSubFeatures(theSketch, "SketchBSpline", theNbSplines)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_1_poles = [(-30, -10), (-15, 20), (0, -10), (15, 20), (30, -10)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+controlPoles = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+model.do()
+model.end()
+
+DEFAULT_DOF = len(SketchBSpline_1_poles) * 2
+DEFAULT_POINTS = len(SketchBSpline_1_poles)
+DEFAULT_LINES = len(SketchBSpline_1_poles) - 1
+DEFAULT_BSPLINES = 1
+DEAFULT_INTERNALS = len(controlPoles) + len(controlLines) * 2
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+for pnt in controlPoles:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 1)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary lines one by one.
+for ln in controlLines:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 2)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3. Remove the B-spline curve.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchBSpline_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+partSet = model.moduleDocument()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_2_poles = [(-30, -10), (-15, -40), (0, -10), (15, -40), (30, -10)]
+SketchBSpline_2 = Sketch_2.addSpline(poles = SketchBSpline_2_poles)
+controlPoles2 = SketchBSpline_2.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines2 = SketchBSpline_2.controlPolygon(auxiliary = [0, 1, 2, 3])
+model.do()
+model.end()
+
+model.begin()
+controlPoles2[1].setAuxiliary(False)
+controlLines2[2].setAuxiliary(False)
+removeFeaturesAndReferences(FeatureSet([controlPoles2[2].feature(), controlLines2[0].feature()]))
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 3)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-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 removing peridoc B-spline curve and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbSplines, theNbInternalConstraints):
+ model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+ model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+ model.testNbSubFeatures(theSketch, "SketchBSplinePeriodic", theNbSplines)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_1_poles = [(-30, -10), (-15, 20), (0, -10), (15, 20), (30, -10)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles, periodic = True)
+controlPoles = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+model.do()
+model.end()
+
+DEFAULT_DOF = len(SketchBSpline_1_poles) * 2
+DEFAULT_POINTS = len(SketchBSpline_1_poles)
+DEFAULT_LINES = len(SketchBSpline_1_poles)
+DEFAULT_BSPLINES = 1
+DEAFULT_INTERNALS = len(controlPoles) + len(controlLines) * 2
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+for pnt in controlPoles:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 1)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary lines one by one.
+for ln in controlLines:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 2)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3. Remove the B-spline curve.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchBSpline_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+partSet = model.moduleDocument()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_2_poles = [(-30, -10), (-15, -40), (0, -10), (15, -40), (30, -10)]
+SketchBSpline_2 = Sketch_2.addSpline(poles = SketchBSpline_2_poles, periodic = True)
+controlPoles2 = SketchBSpline_2.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines2 = SketchBSpline_2.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+model.do()
+model.end()
+
+model.begin()
+controlPoles2[1].setAuxiliary(False)
+controlLines2[2].setAuxiliary(False)
+removeFeaturesAndReferences(FeatureSet([controlPoles2[2].feature(), controlLines2[0].feature()]))
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 3)
+
+assert(model.checkPythonDump())
arcFeature.rst
ellipseFeature.rst
arcEllipseFeature.rst
+ bsplineFeature.rst
.. _sketch_constraints:
.. centered::
Overconstrained Sketch
-When Sketcher becomes into the state then:
+When Sketcher gets this state then:
- buttons Apply and Cancel for the whole Sketcher are blocked;
- a constraint which causes the overconstraint state is highlightid by red color;
- a warning message in sketcher Property Panel is shown with recomendation what to do in this case;
- an additional Undo button is shown under the warning messages;
-After undoing the last operation or deletion of a conflicting constraint Sketcher will become into a normal state.
+After undoing the last operation or deletion of a conflicting constraint Sketcher will be reverted into a normal state.
Operations
----------
--- /dev/null
+
+ .. _tui_create_bspline:
+
+Create Sketch B-spline
+======================
+
+.. literalinclude:: examples/bspline.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/bspline.py>`
--- /dev/null
+.. |bspline.icon| image:: images/bspline.png
+.. |bspline_p.icon| image:: images/bspline_p.png
+.. |add_pole.icon| image:: images/bspline_add_pole.png
+
+B-spline and periodic B-spline
+==============================
+
+The feature creates a free form spline curve in the current Sketch.
+
+To add a new B-spline to the Sketch:
+
+#. select in the Main Menu *Sketch - > B-spline* item or
+#. click |bspline.icon| **B-spline** button in the Sketch toolbar.
+
+To add a periodic B-spline to the Sketch:
+
+#. select in the Main Menu *Sketch - > Periodic B-spline* item or
+#. click |bspline_p.icon| **Periodic B-spline** button in the Sketch toolbar.
+
+
+Creation of B-spline curve
+""""""""""""""""""""""""""
+
+.. image:: images/bspline_creation_panel.png
+ :align: center
+
+Click in the view to specify the control polygon of B-spline curve. The curve will be shown after the second point is initialized. To stop adding new poles, click **Esc** button or **Apply** the operation.
+
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addSpline(degree, poles, weights, knots, multiplicities, periodic)
+
+ :param integer: degree of B-spline.
+ :param array: list of poles [(x1, y1), (x2, y2), ...].
+ :param array: list of weights for corresponding poles.
+ :param array: parametric knots of B-spline curve.
+ :param array: multiplicity of each knot.
+ :param boolean: True mentions that the B-spline curve is periodic.
+ :return: Result object.
+
+Each parameter is optional.
+
+Result
+""""""
+
+Created B-spline curve appears in the view.
+
+.. image:: images/bspline_result.png
+ :align: center
+
+.. centered::
+ Non-periodic B-spline created
+
+
+.. image:: images/bspline_periodic_result.png
+ :align: center
+
+.. centered::
+ Periodic B-spline created
+
+**See Also** a sample TUI Script of :ref:`tui_create_bspline` operation.
+
+
+Modification of B-spline curve
+""""""""""""""""""""""""""""""
+
+.. image:: images/bspline_modification_panel.png
+ :align: center
+
+.. centered::
+ Modification panel for B-spline curve
+
+The following options are provided to modify the already created B-spline curve:
+
+#. Change weight of each pole.
+#. Add new pole.
+
+The new pole is added after the current by pressing on the corresponding |add_pole.icon| button. The default weight for the new pole is 1.
+
+**Note:** adding the new pole after the last for non-periodic B-spline will not change the last point of the curve to avoid modification of full sketch.
--- /dev/null
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+SketchBSpline_1_poles = [(-70, -5), (-50, 30), (-40, 3), (-20, 20), (-10, -5)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles, weights = [1, 2, 2, 2, 1])
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5] = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4] = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+
+SketchBSplinePeriodic_1_poles = [(10, -5), (30, 30), (40, 3), (60, 20), (70, -5)]
+SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, weights = [3, 2, 1, 1, 1], periodic = True)
+[SketchPoint_6, SketchPoint_7, SketchPoint_8, SketchPoint_9, SketchPoint_10] = SketchBSplinePeriodic_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+[SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8, SketchLine_9] = SketchBSplinePeriodic_1.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+
+model.do()
+model.end()
nested="SketchPoint SketchIntersectionPoint SketchLine
SketchCircle SketchMacroCircle SketchArc SketchMacroArc
SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
+ SketchBSpline SketchMacroBSpline SketchMacroBSplinePeriodic SketchBSplinePeriodic
SketchRectangle
SketchProjection
SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
tooltip="Passed point coordinates"
accept_expressions="0"
enable_value="enable_by_preferences"/>
+ <validator id="GeomValidators_Different" parameters="first_point,second_point,passed_point"/>
+ <validator id="SketchPlugin_DifferentPointReference" parameters="first_point_ref,second_point_ref"/>
</box>
<box id="by_major_axis_and_point"
icon="icons/Sketch/ellipse_axes_32x32.png"
tooltip="Passed point coordinates"
accept_expressions="0"
enable_value="enable_by_preferences"/>
+ <validator id="GeomValidators_Different" parameters="first_point_1,second_point_1,passed_point_1"/>
+ <validator id="SketchPlugin_DifferentPointReference" parameters="first_point_ref_1,second_point_ref_1"/>
</box>
</toolbox>
<labelvalue id="major_radius"
default="false"
obligatory="0"
change_visual_attributes="true"/>
+ <validator id="GeomValidators_Different" parameters="center,major_axis_point"/>
+ <validator id="SketchPlugin_DifferentPointReference" parameters="center_ref,major_axis_point_ref"/>
+ <validator id="GeomValidators_Different" parameters="start_point,end_point"/>
+ <validator id="SketchPlugin_DifferentPointReference" parameters="start_point_ref,end_point_ref"/>
+ </feature>
+ </group>
+
+ <group id="Parametric curves">
+ <!-- SketchBSpline is a hidden feature. It is created inside SketchMacroBSpline. -->
+ <feature id="SketchBSpline"
+ title="B-spline"
+ tooltip="Create B-spline curve"
+ icon="icons/Sketch/bspline.png"
+ helpfile="bsplineFeature.html"
+ internal="1">
+ <bspline-panel id="poles"
+ weights="weights"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </bspline-panel>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchBSplinePeriodic is a hidden feature. It is created inside SketchMacroBSplinePeriodic. -->
+ <feature id="SketchBSplinePeriodic"
+ title="Periodic B-spline"
+ tooltip="Create periodic B-spline curve"
+ icon="icons/Sketch/bspline_p.png"
+ helpfile="bsplineFeature.html"
+ internal="1">
+ <bspline-panel id="poles"
+ weights="weights"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </bspline-panel>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchMacroBSpline -->
+ <feature id="SketchMacroBSpline"
+ title="B-spline"
+ tooltip="Create B-spline curve"
+ icon="icons/Sketch/bspline.png"
+ helpfile="bsplineFeature.html">
+ <sketch-bspline_selector id="poles"
+ weights="weights"
+ reference_attribute="poles_ref"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </sketch-bspline_selector>
+ <boolvalue id="need_control_poly"
+ label="Create control polygon"
+ default="true"
+ tooltip="Specify if the control polygon should be created"/>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchMacroBSplinePeriodic -->
+ <feature id="SketchMacroBSplinePeriodic"
+ title="Periodic B-spline"
+ tooltip="Create periodic B-spline curve"
+ icon="icons/Sketch/bspline_p.png"
+ helpfile="bsplineFeature.html">
+ <sketch-bspline_selector id="poles"
+ weights="weights"
+ reference_attribute="poles_ref"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </sketch-bspline_selector>
+ <boolvalue id="need_control_poly"
+ label="Create control polygon"
+ default="true"
+ tooltip="Specify if the control polygon should be created"/>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
</feature>
</group>
buttons_dir="horizontal"
label="Angle type"
tooltip="Type of angle"
- string_list="Direct Complementary Additional"
+ string_list="Direct Supplementary Additional"
icons_list="icons/Sketch/angle_direct.png icons/Sketch/angle_complementary.png icons/Sketch/angle_backward.png"
default="0"
/>
PlaneGCSSolver_EdgeWrapper.h
PlaneGCSSolver_EntityWrapper.h
PlaneGCSSolver_PointWrapper.h
+ PlaneGCSSolver_PointArrayWrapper.h
PlaneGCSSolver_ScalarWrapper.h
+ PlaneGCSSolver_ScalarArrayWrapper.h
PlaneGCSSolver_AngleWrapper.h
PlaneGCSSolver_BooleanWrapper.h
PlaneGCSSolver_Tools.h
+ PlaneGCSSolver_GeoExtensions.h
)
SET(PLANEGCSSOLVER_SOURCES
PlaneGCSSolver_ConstraintWrapper.cpp
PlaneGCSSolver_EdgeWrapper.cpp
PlaneGCSSolver_PointWrapper.cpp
+ PlaneGCSSolver_PointArrayWrapper.cpp
PlaneGCSSolver_ScalarWrapper.cpp
+ PlaneGCSSolver_ScalarArrayWrapper.cpp
PlaneGCSSolver_AngleWrapper.cpp
PlaneGCSSolver_BooleanWrapper.cpp
PlaneGCSSolver_Tools.cpp
+ PlaneGCSSolver_GeoExtensions.cpp
)
SET(PLANEGCSSOLVER_BUILDER_HEADERS
#include <PlaneGCSSolver_AngleWrapper.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_MultiRotation.h>
static EntityWrapperPtr createScalar(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (!aScalar)
- return EntityWrapperPtr();
+ double aValue = 0.0;
+ AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aDouble)
+ aValue = aDouble->isInitialized() ? aDouble->value() : 0.0;
+ else {
+ AttributeIntegerPtr anInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
+ if (anInt)
+ aValue = anInt->isInitialized() ? anInt->value() : 0.0;
+ else
+ return EntityWrapperPtr();
+ }
ScalarWrapperPtr aWrapper;
// following attributes should be converted from degrees to radians
(theAttribute->id() == SketchPlugin_MultiRotation::ANGLE_ID() &&
anOwner->getKind() == SketchPlugin_MultiRotation::ID()))
aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_AngleWrapper(createParameter(theStorage)));
+ else if ((anOwner->getKind() == SketchPlugin_BSpline::ID() ||
+ anOwner->getKind() == SketchPlugin_BSplinePeriodic::ID()) &&
+ theAttribute->id() == SketchPlugin_BSplineBase::DEGREE_ID())
+ // Degree of B-spline is not processed by the solver
+ aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(nullptr)));
else
aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage)));
- if (aScalar->isInitialized())
- aWrapper->setValue(aScalar->value());
+ aWrapper->setValue(aValue);
return aWrapper;
}
+template <typename TYPE>
+static bool nonSolverAttribute(const FeaturePtr theOwner, const std::string& theAttrId)
+{
+ return theOwner->getKind() == TYPE::ID() && (theAttrId == TYPE::WEIGHTS_ID()
+ || theAttrId == TYPE::KNOTS_ID() || theAttrId == TYPE::MULTS_ID());
+}
+
+static EntityWrapperPtr createScalarArray(const AttributePtr& theAttribute,
+ PlaneGCSSolver_Storage* theStorage)
+{
+ PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
+
+ if (!anArray.isInitialized())
+ return EntityWrapperPtr();
+
+ PlaneGCSSolver_Storage* aStorage = theStorage;
+ // Weights, knots and multiplicities of B-spline curve are not processed by the solver
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+ if (nonSolverAttribute<SketchPlugin_BSpline>(anOwner, theAttribute->id()) ||
+ nonSolverAttribute<SketchPlugin_BSplinePeriodic>(anOwner, theAttribute->id()))
+ aStorage = 0;
+
+ int aSize = anArray.size();
+ GCS::VEC_pD aParameters;
+ aParameters.reserve(aSize);
+ for (int index = 0; index < aSize; ++index) {
+ double* aParam = createParameter(aStorage);
+ *aParam = anArray.value(index);
+ aParameters.push_back(aParam);
+ }
+
+ return EntityWrapperPtr(new PlaneGCSSolver_ScalarArrayWrapper(aParameters));
+}
+
+static PointWrapperPtr createPoint(const GeomPnt2dPtr& thePoint, PlaneGCSSolver_Storage* theStorage)
+{
+ GCSPointPtr aNewPoint(new GCS::Point);
+
+ aNewPoint->x = createParameter(theStorage);
+ aNewPoint->y = createParameter(theStorage);
+ if (thePoint) {
+ *(aNewPoint->x) = thePoint->x();
+ *(aNewPoint->y) = thePoint->y();
+ }
+
+ return PointWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+}
+
static EntityWrapperPtr createPoint(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
if (!aPoint2D)
return EntityWrapperPtr();
- GCSPointPtr aNewPoint(new GCS::Point);
+ GeomPnt2dPtr aPnt;
+ if (aPoint2D->isInitialized())
+ aPnt = aPoint2D->pnt();
- aNewPoint->x = createParameter(theStorage);
- aNewPoint->y = createParameter(theStorage);
- if (aPoint2D->isInitialized()) {
- *(aNewPoint->x) = aPoint2D->x();
- *(aNewPoint->y) = aPoint2D->y();
- }
+ return createPoint(aPnt, theStorage);
+}
+
+static EntityWrapperPtr createPointArray(const AttributePtr& theAttribute,
+ PlaneGCSSolver_Storage* theStorage)
+{
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPointArray)
+ return EntityWrapperPtr();
+
+ int aSize = aPointArray->size();
- return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+ std::vector<PointWrapperPtr> aPointWrappers;
+ aPointWrappers.reserve(aSize);
+ for (int index = 0; index < aSize; ++index)
+ aPointWrappers.push_back(createPoint(aPointArray->pnt(index), theStorage));
+
+ return EntityWrapperPtr(new PlaneGCSSolver_PointArrayWrapper(aPointWrappers));
}
EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
aResult = createScalar(theAttribute, myStorage);
if (!aResult)
aResult = createBoolean(theAttribute);
+ if (!aResult)
+ aResult = createPointArray(theAttribute, myStorage);
+ if (!aResult)
+ aResult = createScalarArray(theAttribute, myStorage);
if (aResult && !myStorage)
aResult->setExternal(true);
return aResult;
}
+
+bool PlaneGCSSolver_AttributeBuilder::updateAttribute(
+ AttributePtr theAttribute,
+ EntityWrapperPtr theEntity)
+{
+ bool isUpdated = false;
+ GCS::SET_pD aParamsToRemove;
+ // rebuild array if its size is changed
+ if (theEntity->type() == ENTITY_POINT_ARRAY) {
+ std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> aWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theEntity);
+ std::shared_ptr<GeomDataAPI_Point2DArray> anAttribute =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+
+ std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
+ std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
+ if (aWrapper->size() != anAttribute->size()) {
+ while (anAttribute->size() > (int)aPointsArray.size()) {
+ // add points to the middle of array
+ GeomPnt2dPtr aValue;
+ for (; aPos != aPointsArray.end(); ++aPos) {
+ aValue = anAttribute->pnt(aPos - aPointsArray.begin());
+ if (aValue->distance(PlaneGCSSolver_Tools::point(*aPos)) > tolerance)
+ break;
+ }
+ int aShift = aPos - aPointsArray.begin();
+ aPointsArray.insert(aPos, createPoint(aValue, myStorage));
+ aPos = aPointsArray.begin() + aShift;
+ }
+
+ while (anAttribute->size() < (int)aPointsArray.size()) {
+ // remove middle points
+ std::vector<PointWrapperPtr>::iterator anIt = --aPointsArray.end();
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(*anIt);
+ aParamsToRemove.insert(aParams.begin(), aParams.end());
+ aPointsArray.erase(anIt);
+ }
+
+ aWrapper->setArray(aPointsArray);
+ }
+ else {
+ // update coordinates of points
+ for (int anIndex = 0; aPos != aPointsArray.end(); ++aPos, ++anIndex) {
+ const GCSPointPtr& aGCSPoint = (*aPos)->point();
+ GeomPnt2dPtr aCoord = anAttribute->pnt(anIndex);
+ *aGCSPoint->x = aCoord->x();
+ *aGCSPoint->y = aCoord->y();
+ }
+ }
+ }
+ else if (theEntity->type() == ENTITY_SCALAR_ARRAY) {
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(theEntity);
+ if (aWrapper->size() != PlaneGCSSolver_Tools::AttributeArray(theAttribute).size()) {
+ aParamsToRemove = PlaneGCSSolver_Tools::parameters(aWrapper);
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aNewArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(
+ createScalarArray(theAttribute, myStorage));
+ aWrapper->setArray(aNewArray->array());
+ isUpdated = true;
+ }
+ }
+
+ if (!aParamsToRemove.empty()) {
+ if (myStorage)
+ myStorage->removeParameters(aParamsToRemove);
+ else {
+ std::for_each(aParamsToRemove.begin(), aParamsToRemove.end(),
+ [](double* theParam) { delete theParam; });
+ }
+ }
+
+ return isUpdated || theEntity->update(theAttribute);
+}
/// \return Created wrapper of the attribute applicable for specific solver
virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute);
+ /// \brief Update entity by the attribute values.
+ /// \return \c true if any value is updated.
+ virtual bool updateAttribute(AttributePtr theAttribute, EntityWrapperPtr theEntity);
+
/// \brief Blank. To be defined in derived class.
virtual EntityWrapperPtr createFeature(FeaturePtr)
{ return EntityWrapperPtr(); }
#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <ModelAPI_AttributeBoolean.h>
+
PlaneGCSSolver_BooleanWrapper::PlaneGCSSolver_BooleanWrapper(bool theParam)
: myValue(theParam)
{
}
+
+bool PlaneGCSSolver_BooleanWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ AttributeBooleanPtr aBoolean =
+ std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
+ if (aBoolean) {
+ isUpdated = value() != aBoolean->value();
+ setValue(aBoolean->value());
+ }
+ return isUpdated;
+}
virtual SketchSolver_EntityType type() const
{ return ENTITY_BOOLEAN; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
protected:
bool myValue;
};
#include <PlaneGCSSolver_Defs.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <list>
+
/**
* Wrapper providing operations with PlaneGCS constraints.
*/
ENTITY_UNKNOWN = 0,
ENTITY_BOOLEAN,
ENTITY_SCALAR,
+ ENTITY_SCALAR_ARRAY,
ENTITY_ANGLE,
ENTITY_POINT,
+ ENTITY_POINT_ARRAY,
ENTITY_LINE,
ENTITY_CIRCLE,
ENTITY_ARC,
ENTITY_ELLIPSE,
- ENTITY_ELLIPTIC_ARC
+ ENTITY_ELLIPTIC_ARC,
+ ENTITY_BSPLINE
};
/// Types of constraints
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <cmath>
-static bool isLine(const GCSCurvePtr& theEntity)
+template <typename TYPE>
+static bool isCurve(const GCSCurvePtr& theEntity)
{
- return std::dynamic_pointer_cast<GCS::Line>(theEntity).get();
-}
-
-static bool isCircle(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Circle>(theEntity).get();
-}
-
-static bool isArc(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Arc>(theEntity).get();
-}
-
-static bool isEllipse(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Ellipse>(theEntity).get();
-}
-
-static bool isEllipticArc(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity).get();
+ return std::dynamic_pointer_cast<TYPE>(theEntity).get();
}
PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
: myEntity(theEntity)
{
- if (isLine(myEntity))
+ if (isCurve<GCS::Line>(myEntity))
myType = ENTITY_LINE;
- else if (isArc(myEntity))
+ else if (isCurve<GCS::Arc>(myEntity))
myType = ENTITY_ARC;
- else if (isCircle(myEntity))
+ else if (isCurve<GCS::Circle>(myEntity))
myType = ENTITY_CIRCLE;
- else if (isEllipticArc(myEntity))
+ else if (isCurve<GCS::ArcOfEllipse>(myEntity))
myType = ENTITY_ELLIPTIC_ARC;
- else if (isEllipse(myEntity))
+ else if (isCurve<GCS::Ellipse>(myEntity))
myType = ENTITY_ELLIPSE;
+ else if (isCurve<GCS::BSpline>(myEntity))
+ myType = ENTITY_BSPLINE;
}
static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
#include <PlaneGCSSolver_Defs.h>
-#include <ModelAPI_Attribute.h>
-#include <ModelAPI_Feature.h>
-
-#include <list>
+#include <map>
#include <memory>
+class ModelAPI_Attribute;
+
class PlaneGCSSolver_EntityWrapper;
typedef std::shared_ptr<PlaneGCSSolver_EntityWrapper> EntityWrapperPtr;
const std::map<std::string, EntityWrapperPtr>& additionalAttributes() const
{ return myAdditionalAttributes; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute)
+ { return false; }
+
+ friend class PlaneGCSSolver_AttributeBuilder;
+
private:
bool myExternal;
std::map<std::string, EntityWrapperPtr> myAdditionalAttributes;
//
#include <PlaneGCSSolver_FeatureBuilder.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_GeoExtensions.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
-#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
-static bool isAttributeApplicable(const std::string& theAttrName,
- const std::string& theOwnerName);
static EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
PlaneGCSSolver_Storage* theStorage);
+template <typename TYPE>
+static EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes);
PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
{
FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
EntityWrapperPtr anAttr;
- if (isAttributeApplicable(theAttribute->id(), anOwner->getKind()))
+ if (PlaneGCSSolver_Tools::isAttributeApplicable(theAttribute->id(), anOwner->getKind()))
anAttr = PlaneGCSSolver_AttributeBuilder::createAttribute(theAttribute);
if (anAttr)
myAttributes[theAttribute] = anAttr;
// Arc of ellipse
else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
aResult = createEllipticArc(myAttributes, myStorage);
+ // B-spline curve
+ else if (aFeatureKind == SketchPlugin_BSpline::ID())
+ aResult = createBSpline<SketchPlugin_BSpline>(myAttributes);
+ else if (aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
+ aResult = createBSpline<SketchPlugin_BSplinePeriodic>(myAttributes);
// Point (it has low probability to be an attribute of constraint, so it is checked at the end)
else if (aFeatureKind == SketchPlugin_Point::ID() ||
aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
return anEllipseWrapper;
}
-bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
+template <typename TYPE>
+EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
{
- if (theOwnerName == SketchPlugin_Arc::ID()) {
- return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
- theAttrName == SketchPlugin_Arc::START_ID() ||
- theAttrName == SketchPlugin_Arc::END_ID() ||
- theAttrName == SketchPlugin_Arc::REVERSED_ID();
- }
- else if (theOwnerName == SketchPlugin_Circle::ID()) {
- return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
- theAttrName == SketchPlugin_Circle::RADIUS_ID();
- }
- else if (theOwnerName == SketchPlugin_Line::ID()) {
- return theAttrName == SketchPlugin_Line::START_ID() ||
- theAttrName == SketchPlugin_Line::END_ID();
- }
- else if (theOwnerName == SketchPlugin_Ellipse::ID()) {
- return theAttrName == SketchPlugin_Ellipse::CENTER_ID() ||
- theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() ||
- theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() ||
- theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
- theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
- }
- else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
- return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
- theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
- theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
- theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
+ std::shared_ptr<GCS::BSplineImpl> aNewSpline(new GCS::BSplineImpl);
+
+ aNewSpline->degree = 3;
+ aNewSpline->periodic = std::is_same<TYPE, SketchPlugin_BSplinePeriodic>();
+
+ std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
+
+ AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+ for (; anIt != theAttributes.end(); ++anIt) {
+ const std::string& anAttrID = anIt->first->id();
+ if (anAttrID == TYPE::POLES_ID()) {
+ PointArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+
+ int aSize = anArray->size();
+ aNewSpline->poles.reserve(aSize);
+ for (int anIndex = 0; anIndex < aSize; ++anIndex)
+ aNewSpline->poles.push_back(*anArray->value(anIndex)->point());
+
+ aNewSpline->start = aNewSpline->poles.front();
+ aNewSpline->end = aNewSpline->poles.back();
+ }
+ else if (anAttrID == TYPE::DEGREE_ID()) {
+ ScalarWrapperPtr aScalar =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+ aNewSpline->degree = (int)aScalar->value();
+ }
+ else if (anAttrID == SketchPlugin_BSpline::START_ID() ||
+ anAttrID == SketchPlugin_BSpline::END_ID()) {
+ anAdditionalAttributes[anAttrID] = anIt->second;
+ }
+ else {
+ ScalarArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ if (anAttrID == TYPE::WEIGHTS_ID())
+ aNewSpline->weights = anArray->array();
+ else if (anAttrID == TYPE::KNOTS_ID())
+ aNewSpline->knots = anArray->array();
+ else if (anAttrID == TYPE::MULTS_ID()) {
+ const GCS::VEC_pD& aValues = anArray->array();
+ aNewSpline->mult.reserve(aValues.size());
+ for (GCS::VEC_pD::const_iterator anIt = aValues.begin(); anIt != aValues.end(); ++anIt)
+ aNewSpline->mult.push_back((int)(**anIt));
+ }
+ }
}
- // suppose that all remaining features are points
- return theAttrName == SketchPlugin_Point::COORD_ID();
+ EdgeWrapperPtr aWrapper(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
+ aWrapper->setAdditionalAttributes(anAdditionalAttributes);
+ return aWrapper;
}
--- /dev/null
+// Copyright (C) 2019-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 <PlaneGCSSolver_GeoExtensions.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#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);
+
+ return DeriVector2(aValue->x(), aValue->y(), aDeriv->x() * du, aDeriv->y() * 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)) {
+ // Sometimes OCCT's Extrema algorithm cannot find the parameter on B-spline curve
+ // (usually, if the point is near the curve extremity).
+ // Workaround: compute distance to each boundary point
+ double aDistPS = PlaneGCSSolver_Tools::distance(p, poles.front());
+ double aDistPE = PlaneGCSSolver_Tools::distance(p, poles.back());
+ static const double THE_TOLERANCE = 1.e-6;
+ if (aDistPS < aDistPE && aDistPS < THE_TOLERANCE)
+ u = *knots.front();
+ else if (aDistPE < aDistPS && aDistPE < THE_TOLERANCE)
+ u = *knots.back();
+ else
+ 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();
+}
+
+BSplineImpl* BSplineImpl::Copy()
+{
+ return new BSplineImpl(*this);
+}
+
+
+bool BSplineImpl::isCacheValid() const
+{
+ // 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;
+ }
+
+ // 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;
+
+ return isValid;
+}
+
+void BSplineImpl::rebuildCache()
+{
+ 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));
+}
+
+} // namespace GCS
--- /dev/null
+// Copyright (C) 2019-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 PlaneGCSSolver_GeomExtensions_H_
+#define PlaneGCSSolver_GeomExtensions_H_
+
+#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
+ {
+ public:
+ virtual DeriVector2 Value(double u, double du, double* derivparam = 0);
+ virtual DeriVector2 CalculateNormal(Point &p, double* derivparam = 0);
+
+ 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();
+
+ 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
+ };
+}
+
+#endif
--- /dev/null
+// Copyright (C) 2019-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 <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+PlaneGCSSolver_PointArrayWrapper::PlaneGCSSolver_PointArrayWrapper(
+ const std::vector<PointWrapperPtr>& thePoints)
+ : myPoints(thePoints)
+{
+}
+
+bool PlaneGCSSolver_PointArrayWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (aPointArray && aPointArray->size() == (int)myPoints.size()) {
+ std::vector<PointWrapperPtr>::iterator aPIt = myPoints.begin();
+ for (int anIndex = 0; aPIt != myPoints.end(); ++aPIt, ++anIndex) {
+ GeomPnt2dPtr aPnt = aPointArray->pnt(anIndex);
+
+ const GCSPointPtr& aGCSPoint = (*aPIt)->point();
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPnt->x(), *(aGCSPoint->x)) || isUpdated;
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPnt->y(), *(aGCSPoint->y)) || isUpdated;
+ }
+ }
+ return isUpdated;
+}
--- /dev/null
+// Copyright (C) 2019-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 PlaneGCSSolver_PointArrayWrapper_H_
+#define PlaneGCSSolver_PointArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+
+/**
+ * Wrapper providing operations with arrays of PlaneGCS points.
+ */
+class PlaneGCSSolver_PointArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_PointArrayWrapper(const std::vector<PointWrapperPtr>& thePoints);
+
+ /// \brief Return wrapper of PlaneGCS point
+ const PointWrapperPtr& value(const int theIndex) const
+ { return myPoints[theIndex]; }
+
+ /// \breif Size of array
+ int size() const { return (int)myPoints.size(); }
+
+ /// \brief Return array of points
+ const std::vector<PointWrapperPtr>& array() const { return myPoints; }
+ /// \breif Set points
+ void setArray(const std::vector<PointWrapperPtr>& thePoints) { myPoints = thePoints; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_POINT_ARRAY; }
+
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
+private:
+ std::vector<PointWrapperPtr> myPoints;
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> PointArrayWrapperPtr;
+
+#endif
//
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <GeomDataAPI_Point2D.h>
PlaneGCSSolver_PointWrapper::PlaneGCSSolver_PointWrapper(const GCSPointPtr thePoint)
: myPoint(thePoint)
{
}
+
+bool PlaneGCSSolver_PointWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ if (aPoint2D) {
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPoint2D->x(), *(myPoint->x)) || isUpdated;
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPoint2D->y(), *(myPoint->y)) || isUpdated;
+ }
+ return isUpdated;
+}
virtual SketchSolver_EntityType type() const
{ return ENTITY_POINT; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
private:
GCSPointPtr myPoint;
};
--- /dev/null
+// Copyright (C) 2019-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 <PlaneGCSSolver_ScalarArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+PlaneGCSSolver_ScalarArrayWrapper::PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam)
+ : myValue(theParam)
+{
+}
+
+bool PlaneGCSSolver_ScalarArrayWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
+ if (anArray.isInitialized() && anArray.size() == (int)myValue.size()) {
+ for (int anIndex = 0; anIndex < anArray.size(); ++anIndex) {
+ isUpdated = PlaneGCSSolver_Tools::updateValue(anArray.value(anIndex), *(myValue[anIndex]))
+ || isUpdated;
+ }
+ }
+ return isUpdated;
+}
--- /dev/null
+// Copyright (C) 2019-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 PlaneGCSSolver_ScalarArrayWrapper_H_
+#define PlaneGCSSolver_ScalarArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+
+/**
+ * Wrapper providing operations with array of PlaneGCS scalars.
+ */
+class PlaneGCSSolver_ScalarArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam);
+
+ /// \breif Size of array
+ int size() const { return (int)myValue.size(); }
+
+ /// \brief Return array of PlaneGCS parameters
+ const GCS::VEC_pD& array() const { return myValue; }
+ /// \breif Set array of parameters
+ void setArray(const GCS::VEC_pD& theParams) { myValue = theParams; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_SCALAR_ARRAY; }
+
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
+protected:
+ GCS::VEC_pD myValue; ///< list of pointers to values provided by the storage
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> ScalarArrayWrapperPtr;
+
+#endif
//
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
-#include <cmath>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper(double *const theParam)
: myValue(theParam)
{
return *myValue;
}
+
+bool PlaneGCSSolver_ScalarWrapper::update(AttributePtr theAttribute)
+{
+ double anAttrValue = 0.0;
+ AttributeDoublePtr aDouble =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aDouble)
+ anAttrValue = aDouble->value();
+ else {
+ AttributeIntegerPtr anInt =
+ std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
+ if (anInt)
+ anAttrValue = anInt->value();
+ else
+ return false;
+ }
+
+ // There is possible an angular value, which is converted between degrees and radians.
+ // So, we use its value instead of using direct pointer to variable.
+ double aCurrentValue = value();
+
+ bool isUpdated = PlaneGCSSolver_Tools::updateValue(anAttrValue, aCurrentValue);
+ if (isUpdated)
+ setValue(aCurrentValue);
+ return isUpdated;
+}
virtual SketchSolver_EntityType type() const
{ return ENTITY_SCALAR; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
protected:
double* myValue; ///< pointer to value provided by the storage
};
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_Projection.h>
return aResult;
}
-/// \brief Update value
-static bool updateValue(const double& theSource, double& theDest)
-{
- static const double aTol = 1.e4 * tolerance;
- bool isUpdated = fabs(theSource - theDest) > aTol;
- if (isUpdated)
- theDest = theSource;
- return isUpdated;
-}
-
-/// \brief Update coordinates of the point or scalar using its base attribute
-static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
-{
- bool isUpdated = false;
-
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
- if (aPoint2D) {
- const GCSPointPtr& aGCSPoint =
- std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
- isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
- isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
- } else {
- AttributeDoublePtr aScalar =
- std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (aScalar) {
- ScalarWrapperPtr aWrapper =
- std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
- // There is possible angular value, which is converted between degrees and radians.
- // So, we use its value instead of using direct pointer to value.
- double aValue = aWrapper->value();
- isUpdated = updateValue(aScalar->value(), aValue);
- if (isUpdated)
- aWrapper->setValue(aValue);
- } else {
- AttributeBooleanPtr aBoolean =
- std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
- if (aBoolean) {
- BooleanWrapperPtr aWrapper =
- std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(theEntity);
- isUpdated = aWrapper->value() != aBoolean->value();
- aWrapper->setValue(aBoolean->value());
- }
- }
- }
-
- return isUpdated;
-}
-
static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
const std::string& theFeatureKind)
{
std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
for (; anAttrIt != anAttributes.end(); ++anAttrIt)
- if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
- (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() ||
- (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId())
+ if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
isUpdated = update(*anAttrIt) || isUpdated;
// check external attribute is changed
return aRelated.get() != 0;
}
- bool isUpdated = updateValues(anAttribute, aRelated);
+ PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
+ bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
if (isUpdated) {
setNeedToResolve(true);
notify(aFeature);
constraintsToSolver(aConstraint, theSolver);
}
+static void createBSplineConstraints(
+ const EntityWrapperPtr& theCurve,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+ // set start and end point of B-spline equal to first and last pole correspondingly
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+ if (aBSpline->periodic)
+ return; // additional constraints are not necessary
+
+ std::list<GCSConstraintPtr> aBSplineConstraints;
+
+ const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
+ PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+ anAdditional.at(SketchPlugin_BSpline::START_ID()));
+
+ const GCS::Point& sp = *aStartPoint->point();
+ const GCS::Point& p0 = aBSpline->poles.front();
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x)));
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y)));
+
+ PointWrapperPtr aEndPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+ anAdditional.at(SketchPlugin_BSpline::END_ID()));
+
+ const GCS::Point& ep = *aEndPoint->point();
+ const GCS::Point& pN = aBSpline->poles.back();
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x)));
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y)));
+
+ ConstraintWrapperPtr aWrapper(
+ new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN));
+ aWrapper->setId(theConstraintID);
+ if (theSolver)
+ constraintsToSolver(aWrapper, theSolver);
+
+ theConstraints[theCurve] = aWrapper;
+}
+
void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
{
if (!theEntity || theEntity->isExternal())
createEllipticArcConstraints(theEntity, mySketchSolver,
++myConstraintLastID, myAuxConstraintMap);
}
+ else if (theEntity->type() == ENTITY_BSPLINE)
+ createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
}
void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
{
mySketchSolver->removeParameters(theParams);
+ //for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it)
+ // delete *it;
}
// indicates attribute containing in the external feature
}
continue;
}
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
+ if (aPointArray) {
+ std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+ int aSize = aPointArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
+ GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
+ if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
+ fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
+ aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
if (aScalar) {
ScalarWrapperPtr aScalarWrapper =
}
continue;
}
+ AttributeDoubleArrayPtr aRealArray =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
+ if (aRealArray) {
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ int aSize = aRealArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
+ aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
}
// notify listeners about features update
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <SketchSolver_ConstraintMultiRotation.h>
#include <SketchSolver_ConstraintMultiTranslation.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+#include <SketchPlugin_Circle.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintRigid.h>
#include <SketchPlugin_ConstraintPerpendicular.h>
#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
+#include <SketchPlugin_Point.h>
#include <GeomAPI_Circ2d.h>
#include <GeomAPI_Dir2d.h>
#include <GeomAPI_Lin2d.h>
#include <GeomAPI_Pnt2d.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeIntArray.h>
+
#include <cmath>
static ConstraintWrapperPtr
createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+ std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue);
static ConstraintWrapperPtr
createConstraintPointsCollinear(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity2);
static GCS::SET_pD scalarParameters(const ScalarWrapperPtr& theScalar);
+static GCS::SET_pD scalarArrayParameters(const EntityWrapperPtr& theArray);
static GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint);
+static GCS::SET_pD pointArrayParameters(const EntityWrapperPtr& theArray);
static GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine);
static GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle);
static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc);
static GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse);
static GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc);
-
-static double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
-
+static GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge);
new SketchSolver_ConstraintMovement(theMovedAttribute));
}
+std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMovementConstraint(
+ const std::pair<AttributePtr, int>& theMovedPointInArray)
+{
+ return std::shared_ptr<SketchSolver_ConstraintMovement>(
+ new SketchSolver_ConstraintMovement(theMovedPointInArray.first, theMovedPointInArray.second));
+}
+
ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
aResult = createConstraintCoincidence(aPoint1, aPoint2);
break;
case CONSTRAINT_PT_ON_CURVE:
- aResult = anEntity1 ? createConstraintPointOnEntity(theType, aPoint1, anEntity1):
- createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1));
+ aResult = anEntity1 ?
+ createConstraintPointOnEntity(theType, aPoint1, anEntity1, GCS_SCALAR_WRAPPER(theValue)) :
+ createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1));
break;
case CONSTRAINT_MIDDLE_POINT:
aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2);
case ENTITY_SCALAR:
case ENTITY_ANGLE:
return scalarParameters(GCS_SCALAR_WRAPPER(theEntity));
+ case ENTITY_SCALAR_ARRAY:
+ return scalarArrayParameters(theEntity);
case ENTITY_POINT:
return pointParameters(GCS_POINT_WRAPPER(theEntity));
+ case ENTITY_POINT_ARRAY:
+ return pointArrayParameters(theEntity);
case ENTITY_LINE:
return lineParameters(GCS_EDGE_WRAPPER(theEntity));
case ENTITY_CIRCLE:
return ellipseParameters(GCS_EDGE_WRAPPER(theEntity));
case ENTITY_ELLIPTIC_ARC:
return ellipticArcParameters(GCS_EDGE_WRAPPER(theEntity));
+ case ENTITY_BSPLINE:
+ return bsplineParameters(GCS_EDGE_WRAPPER(theEntity));
default: break;
}
return GCS::SET_pD();
}
+bool PlaneGCSSolver_Tools::isAttributeApplicable(const std::string& theAttrName,
+ const std::string& theOwnerName)
+{
+ if (theOwnerName == SketchPlugin_Arc::ID()) {
+ return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
+ theAttrName == SketchPlugin_Arc::START_ID() ||
+ theAttrName == SketchPlugin_Arc::END_ID() ||
+ theAttrName == SketchPlugin_Arc::REVERSED_ID();
+ }
+ else if (theOwnerName == SketchPlugin_Circle::ID()) {
+ return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
+ theAttrName == SketchPlugin_Circle::RADIUS_ID();
+ }
+ else if (theOwnerName == SketchPlugin_Line::ID()) {
+ return theAttrName == SketchPlugin_Line::START_ID() ||
+ theAttrName == SketchPlugin_Line::END_ID();
+ }
+ else if (theOwnerName == SketchPlugin_Ellipse::ID()) {
+ return theAttrName == SketchPlugin_Ellipse::CENTER_ID() ||
+ theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() ||
+ theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
+ }
+ else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
+ return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
+ }
+ else if (theOwnerName == SketchPlugin_BSpline::ID()) {
+ return theAttrName == SketchPlugin_BSpline::POLES_ID() ||
+ theAttrName == SketchPlugin_BSpline::WEIGHTS_ID() ||
+ theAttrName == SketchPlugin_BSpline::KNOTS_ID() ||
+ theAttrName == SketchPlugin_BSpline::MULTS_ID() ||
+ theAttrName == SketchPlugin_BSpline::DEGREE_ID() ||
+ theAttrName == SketchPlugin_BSpline::START_ID() ||
+ theAttrName == SketchPlugin_BSpline::END_ID();
+ }
+ else if (theOwnerName == SketchPlugin_BSplinePeriodic::ID()) {
+ return theAttrName == SketchPlugin_BSplinePeriodic::POLES_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::WEIGHTS_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::KNOTS_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::MULTS_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::DEGREE_ID();
+ }
+
+ // suppose that all remaining features are points
+ return theAttrName == SketchPlugin_Point::COORD_ID();
+}
+
+/// \brief Update value
+bool PlaneGCSSolver_Tools::updateValue(const double& theSource, double& theDest,
+ const double theTolerance)
+{
+ bool isUpdated = fabs(theSource - theDest) > theTolerance;
+ if (isUpdated)
+ theDest = theSource;
+ return isUpdated;
+}
+
+
+double PlaneGCSSolver_Tools::distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
+{
+ double x = *thePnt1.x - *thePnt2.x;
+ double y = *thePnt1.y - *thePnt2.y;
+ return sqrt(x*x + y*y);
+}
+
+
+
+
+// ================ AttributeArray methods ==========================
+PlaneGCSSolver_Tools::AttributeArray::AttributeArray(AttributePtr theAttribute)
+{
+ myDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(theAttribute);
+ myInteger = std::dynamic_pointer_cast<ModelAPI_AttributeIntArray>(theAttribute);
+}
+
+bool PlaneGCSSolver_Tools::AttributeArray::isInitialized() const
+{
+ return (myDouble && myDouble->isInitialized()) || (myInteger && myInteger->isInitialized());
+}
+
+int PlaneGCSSolver_Tools::AttributeArray::size() const
+{
+ return myDouble.get() ? myDouble->size() : myInteger->size();
+}
+
+double PlaneGCSSolver_Tools::AttributeArray::value(const int theIndex) const
+{
+ return myDouble.get() ? myDouble->value(theIndex) : myInteger->value(theIndex);
+}
+
ConstraintWrapperPtr createConstraintPointOnEntity(
const SketchSolver_ConstraintType& theType,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+ std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue)
{
GCSConstraintPtr aNewConstr;
new GCS::ConstraintPointOnEllipse(*(thePoint->point()), *anEllipse));
break;
}
+ case ENTITY_BSPLINE: {
+ std::list<GCSConstraintPtr> aConstraints;
+ aConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+ *thePoint->point(), thePoint->point()->x, *theEntity->entity(), theValue->scalar())));
+ aConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+ *thePoint->point(), thePoint->point()->y, *theEntity->entity(), theValue->scalar())));
+ return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aConstraints, theType));
+ }
default:
return ConstraintWrapperPtr();
}
std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity2)
{
std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
- bool isLine1Rev = theConstraint->boolean(
- SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID())->value();
- GCS::Point aLine1Pt1 = isLine1Rev ? aLine1->p2 : aLine1->p1;
- GCS::Point aLine1Pt2 = isLine1Rev ? aLine1->p1 : aLine1->p2;
-
std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
- bool isLine2Rev = theConstraint->boolean(
- SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID())->value();
- GCS::Point aLine2Pt1 = isLine2Rev ? aLine2->p2 : aLine2->p1;
- GCS::Point aLine2Pt2 = isLine2Rev ? aLine2->p1 : aLine2->p2;
GCSConstraintPtr aNewConstr(new GCS::ConstraintL2LAngle(
- aLine1Pt1, aLine1Pt2, aLine2Pt1, aLine2Pt2, theValue->scalar()));
+ aLine1->p1, aLine1->p2, aLine2->p1, aLine2->p2, theValue->scalar()));
std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_ANGLE));
aConstrList.push_back(GCSConstraintPtr(
new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->scalar())));
// update value of intermediate parameter
- theIntermed->setValue(distance(aLine1->p1, aLine1->p2));
+ theIntermed->setValue(PlaneGCSSolver_Tools::distance(aLine1->p1, aLine1->p2));
}
else if (theType == CONSTRAINT_EQUAL_ELLIPSES) {
std::shared_ptr<GCS::Ellipse> anEllipse1 =
aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
anEllipse2->center, anEllipse2->focus1, theIntermed->scalar())));
// update value of intermediate parameter
- theIntermed->setValue(distance(anEllipse1->center, anEllipse1->focus1));
+ theIntermed->setValue(PlaneGCSSolver_Tools::distance(anEllipse1->center, anEllipse1->focus1));
}
else {
std::shared_ptr<GCS::Circle> aCirc1 =
return aParams;
}
+GCS::SET_pD scalarArrayParameters(const EntityWrapperPtr& theArray)
+{
+ ScalarArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(theArray);
+ return GCS::SET_pD(anArray->array().begin(), anArray->array().end());
+}
+
GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint)
{
GCS::SET_pD aParams;
return aParams;
}
+GCS::SET_pD pointArrayParameters(const EntityWrapperPtr& theArray)
+{
+ GCS::SET_pD aParams;
+ PointArrayWrapperPtr aPoints =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theArray);
+ for (std::vector<PointWrapperPtr>::const_iterator anIt = aPoints->array().begin();
+ anIt != aPoints->array().end(); ++anIt) {
+ GCS::SET_pD aPointParams = PlaneGCSSolver_Tools::parameters(*anIt);
+ aParams.insert(aPointParams.begin(), aPointParams.end());
+ }
+ return aParams;
+}
+
GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine)
{
GCS::SET_pD aParams;
return aParams;
}
-double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
+GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge)
{
- double x = *thePnt1.x - *thePnt2.x;
- double y = *thePnt1.y - *thePnt2.y;
- return sqrt(x*x + y*y);
+ GCS::SET_pD aParams;
+
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(theEdge->entity());
+
+ for (GCS::VEC_P::iterator it = aBSpline->poles.begin(); it != aBSpline->poles.end(); ++it) {
+ aParams.insert(it->x);
+ aParams.insert(it->y);
+ }
+ for (GCS::VEC_pD::iterator it = aBSpline->weights.begin(); it != aBSpline->weights.end(); ++it)
+ aParams.insert(*it);
+
+ return aParams;
}
class GeomAPI_Lin2d;
class GeomAPI_Pnt2d;
+class ModelAPI_AttributeDoubleArray;
+class ModelAPI_AttributeIntArray;
+
/** \namespace PlaneGCSSolver_Tools
* \ingroup Plugins
* \brief Converter tools
/// \brief Creates temporary constraint to fix the attribute after movement
std::shared_ptr<SketchSolver_ConstraintMovement>
createMovementConstraint(AttributePtr theMovedAttribute);
+ /// \brief Creates temporary constraint to fix the point in array after movement
+ std::shared_ptr<SketchSolver_ConstraintMovement>
+ createMovementConstraint(const std::pair<AttributePtr, int>& theMovedPointInArray);
/// \brief Creates new constraint using given parameters
/// \param theConstraint [in] original constraint
const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(),
const EntityWrapperPtr& theEntity4 = EntityWrapperPtr());
+ /// \brief Return \c true if the attribute is used in PlaneGCS solver
+ /// \param[in] theAttrName name of the attribute
+ /// \param[in] theOwnerName name of the parent feature
+ bool isAttributeApplicable(const std::string& theAttrName,
+ const std::string& theOwnerName);
+
/// \brief Convert entity to point
/// \return empty pointer if the entity is not a point
std::shared_ptr<GeomAPI_Pnt2d> point(EntityWrapperPtr theEntity);
/// brief Return list of parameters for the given entity
GCS::SET_pD parameters(const EntityWrapperPtr& theEntity);
+
+ /// \brief Update value in theDest if theSource is differ more than theTolerance
+ /// \return \c true if the value was updated.
+ bool updateValue(const double& theSource, double& theDest,
+ const double theTolerance = 1.e4 * tolerance);
+
+ double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
+
+ /// \brief Provide an interface to access values in attribute which is an array of values
+ class AttributeArray
+ {
+ public:
+ AttributeArray(AttributePtr theAttribute);
+
+ bool isInitialized() const;
+
+ int size() const;
+
+ double value(const int theIndex) const;
+
+ private:
+ std::shared_ptr<ModelAPI_AttributeDoubleArray> myDouble;
+ std::shared_ptr<ModelAPI_AttributeIntArray> myInteger;
+ };
};
#endif
SketchSolver_EntityType aType = anEntity->type();
if (aType == ENTITY_UNKNOWN)
continue;
- else if (aType == ENTITY_POINT)
+ else if (aType == ENTITY_POINT || aType == ENTITY_POINT_ARRAY)
theAttributes[aPtInd++] = anEntity; // the point is created
else { // another entity (not a point) is created
if (aEntInd < anInitNbOfAttr)
#include <SketchSolver_ConstraintCoincidence.h>
#include <SketchSolver_Error.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_UpdateCoincidence.h>
#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeInteger.h>
+
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
#include <SketchPlugin_Ellipse.h>
}
}
+static void getPointFromArray(EntityWrapperPtr& theArray,
+ const ConstraintPtr& theConstraint,
+ const std::string& theIndexAttrId)
+{
+ if (theArray && theArray->type() == ENTITY_POINT_ARRAY) {
+ AttributeIntegerPtr anIndexAttr = theConstraint->integer(theIndexAttrId);
+ if (anIndexAttr) {
+ PointArrayWrapperPtr aPointsArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theArray);
+ theArray = aPointsArray->value(anIndexAttr->value());
+ }
+ }
+}
+
void SketchSolver_ConstraintCoincidence::process()
{
mySolverConstraint = PlaneGCSSolver_Tools::createConstraint(
myBaseConstraint, getType(),
- aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+ myAuxValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
myStorage->notify(myBaseConstraint);
myInSolver = false;
myFeatureExtremities[0] = EntityWrapperPtr();
myFeatureExtremities[1] = EntityWrapperPtr();
+ if (myAuxValue) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+ GCS::SET_pD aParams;
+ aParams.insert(myAuxValue->scalar());
+ aStorage->removeParameters(aParams);
+ }
return SketchSolver_Constraint::remove();
}
theAttributes, myFeatureExtremities);
} else if (theAttributes[2]) {
myType = CONSTRAINT_PT_ON_CURVE;
- // obtain extremity points of the coincident feature for further checking of multi-coincidence
- getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
+ // point-on-bspline requires additional parameter
+ if (theAttributes[2]->type() == ENTITY_BSPLINE) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+ myAuxValue.reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
+ }
+ else {
+ // obtain extremity points of the coincident feature for further checking of multi-coincidence
+ getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
+ }
} else
myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+
+ // process internal coincidence with a point in the array of points
+ getPointFromArray(theAttributes[0], myBaseConstraint,
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ getPointFromArray(theAttributes[1], myBaseConstraint,
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
}
void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr& theFeature,
}
}
}
+
+void SketchSolver_ConstraintCoincidence::adjustConstraint()
+{
+ if (myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+ AttributeIntegerPtr anIndexA = myBaseConstraint->integer(
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ AttributeIntegerPtr anIndexB = myBaseConstraint->integer(
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ if ((anIndexA && anIndexA->isInitialized()) ||
+ (anIndexB && anIndexB->isInitialized())) {
+ remove();
+ process();
+ }
+ }
+}
virtual void getAttributes(EntityWrapperPtr& theValue,
std::vector<EntityWrapperPtr>& theAttributes);
+ /// \brief This method is used in derived objects to check consistency of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint();
+
protected:
bool myInSolver; ///< shows the constraint is added to the solver
EntityWrapperPtr myFeatureExtremities[2]; ///< extremities of a feature, a point is coincident to
+ ScalarWrapperPtr myAuxValue; ///< parameter on B-spline curve
};
#endif
aParameters.push_back(anEllArc->endAngle);
break;
}
+ case ENTITY_BSPLINE: {
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEntity->entity());
+ for (GCS::VEC_P::iterator anIt = aBSpline->poles.begin();
+ anIt != aBSpline->poles.end(); ++anIt) {
+ aParameters.push_back(anIt->x);
+ aParameters.push_back(anIt->y);
+ }
+ break;
+ }
default:
break;
}
#include <SketchSolver_Manager.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <SketchPlugin_Arc.h>
{
}
-SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr thePoint)
+SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr theAttribute,
+ const int thePointIndex)
: SketchSolver_ConstraintFixed(ConstraintPtr()),
- myDraggedPoint(thePoint),
+ myDraggedAttribute(theAttribute),
+ myDraggedPointIndex(thePointIndex),
mySimpleMove(true)
{
- myMovedFeature = ModelAPI_Feature::feature(thePoint->owner());
+ myMovedFeature = ModelAPI_Feature::feature(theAttribute->owner());
}
void SketchSolver_ConstraintMovement::blockEvents(bool isBlocked)
return aConstraint;
}
- EntityWrapperPtr anEntity =
- myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+ EntityWrapperPtr anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+ : myStorage->entity(myMovedFeature);
if (!anEntity) {
myStorage->update(myMovedFeature, true);
- anEntity =
- myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+ anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+ : myStorage->entity(myMovedFeature);
if (!anEntity)
return aConstraint;
}
- mySimpleMove = isSimpleMove(myMovedFeature, myDraggedPoint);
+ mySimpleMove = isSimpleMove(myMovedFeature, myDraggedAttribute);
- if (mySimpleMove)
+ if (mySimpleMove) {
+ if (anEntity->type() == ENTITY_POINT_ARRAY) {
+ anEntity = std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anEntity)
+ ->value(myDraggedPointIndex);
+ }
aConstraint = fixFeature(anEntity);
+ }
else {
- if (myDraggedPoint) // start or end point of arc has been moved
+ if (myDraggedAttribute) // start or end point of arc has been moved
aConstraint = fixArcExtremity(anEntity);
else if (anEntity->type() == ENTITY_CIRCLE || anEntity->type() == ENTITY_ARC) {
// arc or circle has been moved
#ifdef CHANGE_RADIUS_WHILE_MOVE
int aMaxSize = mySimpleMove ? (int)myFixedValues.size() : 2;
#else
- int aMaxSize = myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedPoint ? 4 : 2;
+ int aMaxSize =
+ myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedAttribute ? 4 : 2;
#endif
for (int i = 0; i < aMaxSize; ++i)
myFixedValues[i] += aDelta[i % 2];
SketchSolver_ConstraintMovement(FeaturePtr theFeature);
/// Creates movement constraint based on point
- SketchSolver_ConstraintMovement(AttributePtr thePoint);
+ SketchSolver_ConstraintMovement(AttributePtr theMovedAttribute, const int thePointIndex = -1);
/// \brief Set coordinates of the start point of the movement
void startPoint(const std::shared_ptr<GeomAPI_Pnt2d>& theStartPoint);
private:
FeaturePtr myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL)
- AttributePtr myDraggedPoint; ///< one of the feature points which has been moved
+ AttributePtr myDraggedAttribute; ///< one of the feature points which has been moved
+ int myDraggedPointIndex; ///< index of the point if the moved attribute is an array
std::shared_ptr<GeomAPI_Pnt2d> myStartPoint; ///< start point of the movement
bool mySimpleMove; ///< simple move, thus all parameters should be increased by movement delta
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Ellipse2d.h>
+#include <ModelAPI_AttributeInteger.h>
+
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
mySharedPoint = AttributePtr();
if (myAuxPoint) {
GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+ if (myAuxParameters[0])
+ aParams.insert(myAuxParameters[0]->scalar());
+ if (myAuxParameters[1])
+ aParams.insert(myAuxParameters[1]->scalar());
aStorage->removeParameters(aParams);
myAuxPoint = EntityWrapperPtr();
+ myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
}
// Check the quantity of entities of each type and their order (arcs first)
int aNbLines = 0;
int aNbCircles = 0;
int aNbEllipses = 0;
+ int aNbSplines = 0;
std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
for (; anEntIt != myAttributes.end(); ++anEntIt) {
if (!(*anEntIt).get())
++aNbCircles;
else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC)
++aNbEllipses;
+ else if ((*anEntIt)->type() == ENTITY_BSPLINE)
+ ++aNbSplines;
}
- if (aNbCircles + aNbEllipses < 1) {
+ if (aNbCircles + aNbEllipses + aNbSplines < 1) {
myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
return;
}
if (aNbLines == 1 && aNbCircles == 1) {
myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
}
- else if (aNbLines + aNbCircles + aNbEllipses == 2) {
+ else if (aNbLines + aNbCircles + aNbEllipses + aNbSplines == 2) {
myType = CONSTRAINT_TANGENT_CURVE_CURVE;
isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
}
return;
}
- FeaturePtr aFeature1, aFeature2;
- getTangentFeatures(myBaseConstraint, aFeature1, aFeature2);
+ FeaturePtr aFeatures[2];
+ getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]);
// check number of coincident points
- std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeature1, aFeature2);
+ std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]);
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
return;
}
- // Try to find non-boundary points coincident with both features.
- // It is necesasry to create tangency with ellipse
- if (aCoincidentPoints.empty() && aNbEllipses > 0)
- aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
+ EntityWrapperPtr aTgEntities[2] = { myAttributes.front(), myAttributes.back() };
+
+ if (aCoincidentPoints.empty()) {
+ // Try to find non-boundary points coincident with both features.
+ // It is necesasry to create tangency with ellipse.
+ if (aNbEllipses > 0)
+ aCoincidentPoints = coincidentPoints(aFeatures[0], aFeatures[1]);
+ }
+ else if (aNbSplines > 0) {
+ // General approach applying tangency to B-spline leads to hang-up in PlaneGCS.
+ // So, the tangency will be applied for the construction segment instead of B-spline curve.
+ for (int i = 0; i < 2; ++i) {
+ if (aTgEntities[i]->type() == ENTITY_BSPLINE) {
+ EdgeWrapperPtr anEdge =
+ std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aTgEntities[i]);
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+
+ // which boundary is coincident?
+ GCS::Point aPoint1, aPoint2;
+ for (std::set<AttributePtr>::iterator aPIt = aCoincidentPoints.begin();
+ aPIt != aCoincidentPoints.end(); ++aPIt) {
+ if ((*aPIt)->owner() == aFeatures[i]) {
+ if ((*aPIt)->id() == SketchPlugin_BSpline::START_ID()) {
+ aPoint1 = aBSpline->poles[0];
+ aPoint2 = aBSpline->poles[1];
+ }
+ else if ((*aPIt)->id() == SketchPlugin_BSpline::END_ID()) {
+ aPoint1 = aBSpline->poles[aBSpline->poles.size() - 2];
+ aPoint2 = aBSpline->poles[aBSpline->poles.size() - 1];
+ }
+ break;
+ }
+ }
+
+ // substitute B-spline by its boundary segment
+ std::shared_ptr<GCS::Line> aSegment(new GCS::Line);
+ aSegment->p1 = aPoint1;
+ aSegment->p2 = aPoint2;
+ aTgEntities[i] = EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aSegment));
+ --aNbSplines;
+ ++aNbLines;
+ }
+ }
+ }
EntityWrapperPtr aSharedPointEntity;
std::list<GCSConstraintPtr> anAuxConstraints;
mySharedPoint = *aCoincidentPoints.begin();
aSharedPointEntity = myStorage->entity(mySharedPoint);
}
- else if (aNbEllipses > 0) {
+ else if (aNbEllipses + aNbSplines > 0) {
// create auxiliary point
GCSPointPtr aPoint(new GCS::Point);
aPoint->x = aStorage->createParameter();
aPoint->y = aStorage->createParameter();
- calculateTangencyPoint(myAttributes.front(), myAttributes.back(), aPoint);
+ calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint);
myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
aSharedPointEntity = myAuxPoint;
- // create auxiliary coincident constraints for tangency with ellipse
EntityWrapperPtr aDummy;
- ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
- CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
- anAuxConstraints = aCoincidence->constraints();
- aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
- CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
- anAuxConstraints.insert(anAuxConstraints.end(),
- aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ for (int i = 0; i < 2; ++i) {
+ // create auxiliary parameters for coincidence with B-spline
+ if (aTgEntities[i]->type() == ENTITY_BSPLINE)
+ myAuxParameters[i].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
+
+ // create auxiliary coincident constraints for tangency with ellipse
+ ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+ CONSTRAINT_PT_ON_CURVE, myAuxParameters[i],
+ aSharedPointEntity, aDummy, aTgEntities[i], aDummy);
+ anAuxConstraints.insert(anAuxConstraints.end(),
+ aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ }
}
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
- mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createArcLineTangency(aTgEntities[0], aTgEntities[1],
aSharedPointEntity, &myCurveCurveAngle);
} else {
- mySolverConstraint = createCurveCurveTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1],
isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
}
rebuild();
}
+bool SketchSolver_ConstraintTangent::remove()
+{
+ if (myAuxPoint) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+ if (myAuxParameters[0])
+ aParams.insert(myAuxParameters[0]->scalar());
+ if (myAuxParameters[1])
+ aParams.insert(myAuxParameters[1]->scalar());
+ aStorage->removeParameters(aParams);
+ myAuxPoint = EntityWrapperPtr();
+ myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
+ }
+ return SketchSolver_Constraint::remove();
+}
+
const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
std::set<FeaturePtr> aCoincidences;
+ std::map<AttributePtr, FeaturePtr> aCoincidentPoints;
std::set<AttributePtr>::const_iterator anIt;
// collect coincidences referred to the first feature
for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
- if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+ if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
aCoincidences.insert(aRef);
+ AttributeRefAttrPtr aRefAttrA = aRef->refattr(SketchPlugin_Constraint::ENTITY_A());
+ if (!aRefAttrA->isObject())
+ aCoincidentPoints[aRefAttrA->attr()] = aRef;
+ AttributeRefAttrPtr aRefAttrB = aRef->refattr(SketchPlugin_Constraint::ENTITY_B());
+ if (!aRefAttrB->isObject())
+ aCoincidentPoints[aRefAttrB->attr()] = aRef;
+ }
}
// leave only coincidences referred to the second feature
FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
if (aCoincidences.find(aRef) != aCoincidences.end())
aCoincidencesBetweenFeatures.insert(aRef);
+ else if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (aRefAttr && !aRefAttr->isObject()) {
+ std::map<AttributePtr, FeaturePtr>::iterator aFound =
+ aCoincidentPoints.find(aRefAttr->attr());
+ if (aFound != aCoincidentPoints.end()) {
+ aCoincidencesBetweenFeatures.insert(aRef);
+ aCoincidencesBetweenFeatures.insert(aFound->second);
+ }
+ }
+ }
+ }
}
return aCoincidencesBetweenFeatures;
std::set<AttributePtr> aCoincidentPoints;
std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
for (; aCIt != aCoincidences.end(); ++ aCIt) {
- AttributeRefAttrPtr aRefAttrA = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
- AttributeRefAttrPtr aRefAttrB = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_B());
- if (!aRefAttrA || aRefAttrA->isObject() ||
- !aRefAttrB || aRefAttrB->isObject())
- continue;
-
- AttributePtr anAttrA = aRefAttrA->attr();
- AttributePtr anAttrB = aRefAttrB->attr();
- if (anAttrA->id() != SketchPlugin_Arc::CENTER_ID() &&
- anAttrA->id() != SketchPlugin_Circle::CENTER_ID() &&
- anAttrB->id() != SketchPlugin_Arc::CENTER_ID() &&
- anAttrB->id() != SketchPlugin_Circle::CENTER_ID()) {
- aCoincidentPoints.insert(anAttrA);
- aCoincidentPoints.insert(anAttrB);
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (!aRefAttr || aRefAttr->isObject())
+ continue;
+
+ AttributePtr anAttr = aRefAttr->attr();
+ FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
+ if (anOwner == theFeature1 || anOwner == theFeature2) {
+ if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) {
+ AttributeIntegerPtr anIndex = (*aCIt)->integer(i == 0 ?
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ if (anIndex) {
+ if (anIndex->value() == 0)
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID());
+ else
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
+ if (anAttr)
+ aCoincidentPoints.insert(anAttr);
+ }
+ }
+ else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+ aCoincidentPoints.insert(anAttr);
+ }
}
}
return aCoincidentPoints;
virtual void notify(const FeaturePtr& theFeature,
PlaneGCSSolver_Update* theUpdater);
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints
+ /// (like for multiple coincidence)
+ virtual bool remove();
+
protected:
/// \brief Converts SketchPlugin constraint to a list of solver constraints
virtual void process();
double myCurveCurveAngle;
AttributePtr mySharedPoint;
EntityWrapperPtr myAuxPoint;
+ ScalarWrapperPtr myAuxParameters[2];
};
#endif
int theSketchDOF,
bool theEventsBlocked,
Type theFeatureOrPoint,
+ const EntityWrapperPtr& theSolverEntity,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- bool isEntityExists = (theStorage->entity(theFeatureOrPoint).get() != 0);
+ bool isEntityExists = (theSolverEntity.get() != 0);
if (theSketchDOF == 0 && isEntityExists) {
// avoid moving elements of fully constrained sketch
theStorage->refresh();
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- SolverConstraintPtr aConstraint =
- move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theFeature, theFrom, theTo);
+ EntityWrapperPtr anEntity = myStorage->entity(theFeature);
+ SolverConstraintPtr aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ theFeature, anEntity, theFrom, theTo);
setTemporary(aConstraint);
return true;
}
bool SketchSolver_Group::movePoint(AttributePtr theAttribute,
+ const int thePointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- SolverConstraintPtr aConstraint =
- move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theAttribute, theFrom, theTo);
+ EntityWrapperPtr anEntity = myStorage->entity(theAttribute);
+ SolverConstraintPtr aConstraint;
+ if (thePointIndex < 0) {
+ aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ theAttribute, anEntity, theFrom, theTo);
+ }
+ else {
+ aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ std::pair<AttributePtr, int>(theAttribute, thePointIndex), anEntity,
+ theFrom, theTo);
+ }
setTemporary(aConstraint);
return true;
}
const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
/** \brief Updates the data corresponding the specified point moved in GUI.
* Special kind of Fixed constraints is created.
- * \param[in] thePoint the attribute to be updated
- * \param[in] theFrom start point of the movement
- * \param[in] theTo final point of the movement
+ * \param[in] thePointOrArray the attribute to be updated
+ * \param[in] thePointIndex index of moved point in array
+ * \param[in] theFrom start point of the movement
+ * \param[in] theTo destination point of the movement
* \return \c true, if the attribute is really moved
*/
- bool movePoint(AttributePtr thePoint,
+ bool movePoint(AttributePtr thePointOrArray,
+ const int thePointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
#include <Events_Loop.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_Events.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
}
}
+static void setPoint(AttributePtr theAttribute,
+ const int thePointIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d> theValue)
+{
+ AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ AttributePoint2DArrayPtr aPointArrayAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (aPointAttr)
+ aPointAttr->setValue(theValue);
+ else if (aPointArrayAttr && thePointIndex >= 0)
+ aPointArrayAttr->setPnt(thePointIndex, theValue);
+}
+
// ========================================================
std::dynamic_pointer_cast<ModelAPI_ObjectMovedMessage>(theMessage);
ObjectPtr aMovedObject = aMoveMsg->movedObject();
- std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
+ AttributePtr aMovedAttribute = aMoveMsg->movedAttribute();
+ int aMovedPoint = aMoveMsg->movedPointIndex();
const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
std::dynamic_pointer_cast<SketchPlugin_Feature>(aMovedFeature);
if (aSketchFeature && !aSketchFeature->isMacro())
needToResolve = moveFeature(aSketchFeature, aFrom, aTo);
- } else if (aMovedPoint)
- needToResolve = moveAttribute(aMovedPoint, aFrom, aTo);
+ } else if (aMovedAttribute)
+ needToResolve = moveAttribute(aMovedAttribute, aMovedPoint, aFrom, aTo);
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
// Purpose: move given attribute in appropriate group
// ============================================================================
bool SketchSolver_Manager::moveAttribute(
- const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+ const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+ const int theMovedPointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
std::dynamic_pointer_cast<SketchPlugin_Constraint>(anOwner);
if (aConstraint)
{
- theMovedAttribute->setValue(theTo);
+ setPoint(theMovedAttribute, theMovedPointIndex, theTo);
Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
return true;
}
if (aSketchFeature)
aGroup = findGroup(aSketchFeature);
if (!aGroup) {
- theMovedAttribute->setValue(theTo);
+ setPoint(theMovedAttribute, theMovedPointIndex, theTo);
return false;
}
aGroup->blockEvents(true);
- return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
+ return aGroup->movePoint(theMovedAttribute, theMovedPointIndex, theFrom, theTo);
}
// ============================================================================
const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
/** \brief Move feature using its moved attribute
- * \param[in] theMovedAttribute dragged point attribute of sketch feature
- * \param[in] theFromPoint original position of the moved point
- * \param[in] theToPoint prefereble position (current position of the mouse)
+ * \param[in] theMovedAttribute dragged point (array of points) attribute of sketch feature
+ * \param[in] theMovedPointIndex index of dragged point in an array (-1 otherwise)
+ * \param[in] theFromPoint original position of the moved point
+ * \param[in] theToPoint prefereble position (current position of the mouse)
* \return \c true if the attribute owner has been changed successfully
*/
- bool moveAttribute(const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+ bool moveAttribute(const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+ const int theMovedPointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFromPoint,
const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
SketcherPrs.h
SketcherPrs_Coincident.h
SketcherPrs_Collinear.h
- SketcherPrs_DimensionStyleListener.h
+ SketcherPrs_DimensionStyle.h
SketcherPrs_Factory.h
SketcherPrs_Parallel.h
SketcherPrs_Tools.h
SET(PROJECT_SOURCES
SketcherPrs_Coincident.cpp
SketcherPrs_Collinear.cpp
- SketcherPrs_DimensionStyleListener.cpp
+ SketcherPrs_DimensionStyle.cpp
SketcherPrs_Factory.cpp
SketcherPrs_Parallel.cpp
SketcherPrs_Tools.cpp
//
#include "SketcherPrs_Angle.h"
-#include "SketcherPrs_DimensionStyleListener.h"
+#include "SketcherPrs_DimensionStyle.h"
#include "SketcherPrs_Tools.h"
#include <SketchPlugin_ConstraintAngle.h>
SetDimensionAspect(myAspect);
- myStyleListener = new SketcherPrs_DimensionStyleListener();
+ myStyleListener = new SketcherPrs_DimensionStyle();
}
SketcherPrs_Angle::~SketcherPrs_Angle()
gp_Pnt& theCenterPoint)
{
bool aReadyToDisplay = false;
+ if (!thePlane)
+ return aReadyToDisplay;
DataPtr aData = theConstraint->data();
std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB->pnt(), aEndB->pnt()));
bool isReversed2 =
aData->boolean(SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID())->value();
+
+ if (aData->integer(SketchPlugin_ConstraintAngle::TYPE_ID())->value() ==
+ (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY)
+ isReversed1 = !isReversed1;
+
anAng = std::shared_ptr<GeomAPI_Angle2d>(
new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
}
aSecondPoint = anAng->firstPoint()->impl<gp_Pnt2d>();
}
+ if (aData->integer(SketchPlugin_ConstraintAngle::TYPE_ID())->value() ==
+ (int)SketcherPrs_Tools::ANGLE_BACKWARD)
+ std::swap(aFirstPoint, aSecondPoint);
std::shared_ptr<GeomAPI_Pnt> aPoint = thePlane->to3D(aFirstPoint.X(), aFirstPoint.Y());
theFirstPoint = aPoint->impl<gp_Pnt>();
myFlyOutPoint = aFlyoutPnt->impl<gp_Pnt>();
}
- std::shared_ptr<ModelAPI_AttributeInteger> aTypeAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeInteger>(aData->attribute(SketchPlugin_ConstraintAngle::TYPE_ID()));
- SketcherPrs_Tools::AngleType anAngleType = (SketcherPrs_Tools::AngleType)(aTypeAttr->value());
-
double aDist = -1;
- switch (anAngleType) {
- case SketcherPrs_Tools::ANGLE_DIRECT: {
-#ifndef COMPILATION_CORRECTION
- SetArrowsVisibility(AIS_TOAV_Both);
-#endif
- SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint);
-#ifndef COMPILATION_CORRECTION
- bool isReversedPlanes = isAnglePlaneReversedToSketchPlane();
- SetType(!isReversedPlanes ? AIS_TOA_Exterior : AIS_TOA_Interior);
-#endif
- }
- break;
- case SketcherPrs_Tools::ANGLE_COMPLEMENTARY: {
- double anEdge1Length = aCenterPoint.Distance(myFirstPoint);
- //aDist = calculateDistanceToFlyoutPoint();
- gp_Pnt aFirstPoint = aCenterPoint.Translated(
- gp_Vec(myCenterPoint, myFirstPoint).Normalized() * (-anEdge1Length));
- SetMeasuredGeometry(aFirstPoint, myCenterPoint, mySecondPoint);
#ifndef COMPILATION_CORRECTION
- SetType(AIS_TOA_Interior);
+ SetArrowsVisibility(AIS_TOAV_Both);
#endif
- }
- break;
- case SketcherPrs_Tools::ANGLE_BACKWARD: {
+ SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint);
#ifndef COMPILATION_CORRECTION
- SetArrowsVisibility(AIS_TOAV_Both);
+ bool isReversedPlanes = isAnglePlaneReversedToSketchPlane();
+ SetType(!isReversedPlanes ? AIS_TOA_Exterior : AIS_TOA_Interior);
#endif
- SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint);
- bool isReversedPlanes = isAnglePlaneReversedToSketchPlane();
-#ifndef COMPILATION_CORRECTION
- SetType(isReversedPlanes ? AIS_TOA_Exterior : AIS_TOA_Interior);
-#endif
- }
- break;
- default:
- break;
- }
if (aDist < 0) /// it was not calculated yet
aDist = calculateDistanceToFlyoutPoint();
SetFlyout(aDist);
#include <AIS_AngleDimension.hxx>
#include <Standard_DefineHandle.hxx>
-#include <SketcherPrs_DimensionStyleListener.h>
+#include <SketcherPrs_DimensionStyle.h>
DEFINE_STANDARD_HANDLE(SketcherPrs_Angle, AIS_AngleDimension)
Handle(Prs3d_DimensionAspect) myAspect;
/// Listener to update dimension visualization style
- SketcherPrs_DimensionStyleListener* myStyleListener;
+ SketcherPrs_DimensionStyle* myStyleListener;
/// container of values obtained from the constraint, which are necessary to fill the presentation
gp_Pnt myFirstPoint; ///< the dimension first point for measured geometry
gp_Pnt myCenterPoint; ///< the dimension center point for measured geometry
gp_Pnt myFlyOutPoint; ///< the dimension fly out point for measured geometry
- SketcherPrs_DimensionStyleListener::DimensionValue myValue; /// the structure filled by constraint
+ SketcherPrs_DimensionStyle::DimensionValue myValue; /// the structure filled by constraint
};
--- /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_DimensionStyle.h"
+#include <Prs3d_DimensionAspect.hxx>
+#include "SketcherPrs_Tools.h"
+
+#include <Events_Loop.h>
+
+#include <AIS_Dimension.hxx>
+#include <TCollection_ExtendedString.hxx>
+
+//#ifndef WNT
+// #define COMPILATION_CORRECTION
+//#endif
+
+// it is not possible to use 0x2211 as summ symbol because it is not supported by
+// debian Linux platform
+static const Standard_ExtCharacter MyEmptySymbol(' ');
+static const Standard_ExtCharacter MySigmaSymbol('=');//0x03A3); // using equal instead of sigma
+
+
+SketcherPrs_DimensionStyle::DimensionValue::DimensionValue(double theDoubleValue,
+ bool theHasParameters, const std::string& theTextValue)
+: myDoubleValue(theDoubleValue),
+ myHasParameters(theHasParameters),
+ myTextValue(theTextValue)
+{
+}
+
+void SketcherPrs_DimensionStyle::DimensionValue::init(
+ const AttributeDoublePtr& theAttributeValue)
+{
+ myDoubleValue = theAttributeValue->value();
+ myHasParameters = theAttributeValue->usedParameters().size() > 0;
+ myTextValue = theAttributeValue->text();
+}
+
+SketcherPrs_DimensionStyle::SketcherPrs_DimensionStyle()
+{
+}
+
+SketcherPrs_DimensionStyle::~SketcherPrs_DimensionStyle()
+{
+}
+
+void SketcherPrs_DimensionStyle::updateDimensions(AIS_Dimension* theDimension,
+ const SketcherPrs_DimensionStyle::DimensionValue& theDimensionValue)
+{
+ if (!theDimension)
+ return;
+ updateDimensions(theDimension, theDimensionValue.myHasParameters,
+ theDimensionValue.myTextValue, theDimensionValue.myDoubleValue);
+}
+
+void SketcherPrs_DimensionStyle::updateDimensions(AIS_Dimension* theDimension,
+ const bool theHasParameters,
+ const std::string& theTextValue,
+ const double theDoubleValue)
+{
+ if (!theDimension)
+ return;
+
+ /// do not show special symbols of dimension:
+ /// previous implementation did not allow to unite them
+ theDimension->SetSpecialSymbol(MyEmptySymbol);
+ theDimension->SetDisplaySpecialSymbol(AIS_DSS_No);
+
+ TCollection_ExtendedString aCustomValue;
+ if (theHasParameters) {
+ //bool isParameterTextStyle = myStyle == SketcherPrs_ParameterStyleMessage::ParameterText;
+ bool isParameterTextStyle =
+ SketcherPrs_Tools::parameterStyle() == SketcherPrs_Tools::ParameterText;
+
+ if (isParameterTextStyle)
+ aCustomValue = theTextValue.c_str();
+ else {
+ // format value string using "sprintf"
+ TCollection_AsciiString aFormatStr =
+ theDimension->Attributes()->DimensionAspect()->ValueStringFormat();
+ char aFmtBuffer[256];
+ sprintf (aFmtBuffer, aFormatStr.ToCString(), theDoubleValue);
+ aCustomValue = TCollection_ExtendedString (aFmtBuffer);
+
+ aCustomValue.Insert (1, MySigmaSymbol);
+ }
+ }
+ else {
+ // format value string using "sprintf"
+ TCollection_AsciiString aFormatStr =
+ theDimension->Attributes()->DimensionAspect()->ValueStringFormat();
+ char aFmtBuffer[256];
+ sprintf (aFmtBuffer, aFormatStr.ToCString(), theDoubleValue);
+ aCustomValue = TCollection_ExtendedString (aFmtBuffer);
+ }
+#ifdef COMPILATION_CORRECTION
+ theDimension->SetCustomValue(theDoubleValue);
+#else
+ theDimension->SetCustomValue(aCustomValue);
+#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
+//
+
+#ifndef SketcherPrs_DimensionStyleListener_H
+#define SketcherPrs_DimensionStyleListener_H
+
+//#include <Events_Listener.h>
+
+#include <ModelAPI_AttributeDouble.h>
+
+#include "SketcherPrs_Tools.h"
+
+#include <Standard.hxx>
+
+#include <string>
+
+/**
+* \class SketcherPrs_DimensionStyleListener
+* \ingroup GUI
+* A class for representation of linear dimension constraint.
+* It supports SketchPlugin_ConstraintLength and SketchPlugin_ConstraintDistance features.
+*/
+class SketcherPrs_DimensionStyle
+{
+public:
+ class DimensionValue {
+ public:
+ DimensionValue(double theDoubleValue, bool theHasParameters, const std::string& theTextValue);
+ /// Fills internal fields by the given attribute
+ /// \param theAttributeValue a model attribute
+ void init(const AttributeDoublePtr& theAttributeValue);
+
+ public:
+ double myDoubleValue; ///< the angle value to be shown as custom value of presentation
+ bool myHasParameters; ///< true if the atrribute value has used parameters
+ std::string myTextValue; ///< the angle value depending on angle type
+ };
+
+public:
+ /// Constructor
+ Standard_EXPORT SketcherPrs_DimensionStyle();
+
+ /// Destructor
+ Standard_EXPORT ~SketcherPrs_DimensionStyle();
+
+ /// Visualizes the dimension text or dimension value depending on the has parameters state
+ /// \param theDimension a modified dimension
+ /// \param theDimensionValue container filled by the model double attribute
+ Standard_EXPORT void updateDimensions(AIS_Dimension* theDimension,
+ const DimensionValue& theDimensionValue);
+
+private:
+ /// Visualizes the dimension text or dimension value depending on the has parameters state
+ /// \param theDimension a modified dimension
+ /// \param theHasParameters if true, the text is shown, else digit
+ /// \param theTextValue a dimension text value
+ /// \param theDoubleValue a dimension digit value
+ void updateDimensions(AIS_Dimension* theDimension,
+ const bool theHasParameters,
+ const std::string& theTextValue,
+ const double theDoubleValue);
+};
+
+#endif
\ No newline at end of file
+++ /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_DimensionStyleListener.h"
-#include <Prs3d_DimensionAspect.hxx>
-#include "SketcherPrs_Tools.h"
-
-#include <Events_Loop.h>
-
-#include <AIS_Dimension.hxx>
-#include <TCollection_ExtendedString.hxx>
-
-//#ifndef WNT
-// #define COMPILATION_CORRECTION
-//#endif
-
-// it is not possible to use 0x2211 as summ symbol because it is not supported by
-// debian Linux platform
-static const Standard_ExtCharacter MyEmptySymbol(' ');
-static const Standard_ExtCharacter MySigmaSymbol('=');//0x03A3); // using equal instead of sigma
-
-SketcherPrs_DimensionStyleListener::DimensionValue::DimensionValue(double theDoubleValue,
- bool theHasParameters, const std::string& theTextValue)
-: myDoubleValue(theDoubleValue),
- myHasParameters(theHasParameters),
- myTextValue(theTextValue)
-{
-}
-
-void SketcherPrs_DimensionStyleListener::DimensionValue::init(
- const AttributeDoublePtr& theAttributeValue)
-{
- myDoubleValue = theAttributeValue->value();
- myHasParameters = theAttributeValue->usedParameters().size() > 0;
- myTextValue = theAttributeValue->text();
-}
-
-SketcherPrs_DimensionStyleListener::SketcherPrs_DimensionStyleListener()
-{
- Events_Loop* aLoop = Events_Loop::loop();
- const Events_ID kDocCreatedEvent =
- SketcherPrs_ParameterStyleMessage::eventId();
- aLoop->registerListener(this, kDocCreatedEvent, NULL, false);
-}
-
-SketcherPrs_DimensionStyleListener::~SketcherPrs_DimensionStyleListener()
-{
- Events_Loop* aLoop = Events_Loop::loop();
- aLoop->removeListener(this);
-}
-
-void SketcherPrs_DimensionStyleListener::processEvent(
- const std::shared_ptr<Events_Message>& theMessage)
-{
- const Events_ID kParameterStyleEvent = SketcherPrs_ParameterStyleMessage::eventId();
- if (theMessage->eventID() == kParameterStyleEvent) {
- std::shared_ptr<SketcherPrs_ParameterStyleMessage> aMessage = std::dynamic_pointer_cast<
- SketcherPrs_ParameterStyleMessage>(theMessage);
- myStyle = aMessage->style();
- }
-}
-
-void SketcherPrs_DimensionStyleListener::updateDimensions(AIS_Dimension* theDimension,
- const SketcherPrs_DimensionStyleListener::DimensionValue& theDimensionValue)
-{
- if (!theDimension)
- return;
- updateDimensions(theDimension, theDimensionValue.myHasParameters,
- theDimensionValue.myTextValue, theDimensionValue.myDoubleValue);
-}
-
-void SketcherPrs_DimensionStyleListener::updateDimensions(AIS_Dimension* theDimension,
- const bool theHasParameters,
- const std::string& theTextValue,
- const double theDoubleValue)
-{
- if (!theDimension)
- return;
-
- /// do not show special symbols of dimension: previous implementation did not allow to unite them
- theDimension->SetSpecialSymbol(MyEmptySymbol);
- theDimension->SetDisplaySpecialSymbol(AIS_DSS_No);
-
- TCollection_ExtendedString aCustomValue;
- if (theHasParameters) {
- bool isParameterTextStyle = myStyle == SketcherPrs_ParameterStyleMessage::ParameterText;
-
- if (isParameterTextStyle)
- aCustomValue = theTextValue.c_str();
- else {
- // format value string using "sprintf"
- TCollection_AsciiString aFormatStr =
- theDimension->Attributes()->DimensionAspect()->ValueStringFormat();
- char aFmtBuffer[256];
- sprintf (aFmtBuffer, aFormatStr.ToCString(), theDoubleValue);
- aCustomValue = TCollection_ExtendedString (aFmtBuffer);
-
- aCustomValue.Insert (1, MySigmaSymbol);
- }
- }
- else {
- // format value string using "sprintf"
- TCollection_AsciiString aFormatStr =
- theDimension->Attributes()->DimensionAspect()->ValueStringFormat();
- char aFmtBuffer[256];
- sprintf (aFmtBuffer, aFormatStr.ToCString(), theDoubleValue);
- aCustomValue = TCollection_ExtendedString (aFmtBuffer);
- }
-#ifdef COMPILATION_CORRECTION
- theDimension->SetCustomValue(theDoubleValue);
-#else
- theDimension->SetCustomValue(aCustomValue);
-#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
-//
-
-#ifndef SketcherPrs_DimensionStyleListener_H
-#define SketcherPrs_DimensionStyleListener_H
-
-#include <Events_Listener.h>
-
-#include <ModelAPI_AttributeDouble.h>
-
-#include "SketcherPrs_Tools.h"
-
-#include <Standard.hxx>
-
-#include <string>
-
-/**
-* \class SketcherPrs_DimensionStyleListener
-* \ingroup GUI
-* A class for representation of linear dimension constraint.
-* It supports SketchPlugin_ConstraintLength and SketchPlugin_ConstraintDistance features.
-*/
-class SketcherPrs_DimensionStyleListener : public Events_Listener
-{
-public:
- class DimensionValue {
- public:
- DimensionValue(double theDoubleValue, bool theHasParameters, const std::string& theTextValue);
- /// Fills internal fields by the given attribute
- /// \param theAttributeValue a model attribute
- void init(const AttributeDoublePtr& theAttributeValue);
-
- public:
- double myDoubleValue; ///< the angle value to be shown as custom value of presentation
- bool myHasParameters; ///< true if the atrribute value has used parameters
- std::string myTextValue; ///< the angle value depending on angle type
- };
-
-public:
- /// Constructor
- Standard_EXPORT SketcherPrs_DimensionStyleListener();
-
- /// Destructor
- Standard_EXPORT ~SketcherPrs_DimensionStyleListener();
-
- /// Process the ModelAPI_DocumentCreatedMessage to fulfill a document
- /// from the message with origin and planes
- virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
-
- /// Visualizes the dimension text or dimension value depending on the has parameters state
- /// \param theDimension a modified dimension
- /// \param theDimensionValue container filled by the model double attribute
- Standard_EXPORT void updateDimensions(AIS_Dimension* theDimension,
- const DimensionValue& theDimensionValue);
-
-private:
- /// Visualizes the dimension text or dimension value depending on the has parameters state
- /// \param theDimension a modified dimension
- /// \param theHasParameters if true, the text is shown, else digit
- /// \param theTextValue a dimension text value
- /// \param theDoubleValue a dimension digit value
- void updateDimensions(AIS_Dimension* theDimension,
- const bool theHasParameters,
- const std::string& theTextValue,
- const double theDoubleValue);
-private:
- /// Style how the parameter of dimension should be visualized
- SketcherPrs_ParameterStyleMessage::ParameterStyle myStyle;
-};
-
-#endif
\ No newline at end of file
#include "SketcherPrs_LengthDimension.h"
#include "SketcherPrs_Tools.h"
-#include "SketcherPrs_DimensionStyleListener.h"
+#include "SketcherPrs_DimensionStyle.h"
#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintLength.h>
myValue(0., false, "")
{
SetDimensionAspect(createDimensionAspect());
- myStyleListener = new SketcherPrs_DimensionStyleListener();
+ myStyleListener = new SketcherPrs_DimensionStyle();
setDirection(theConstraint, plane());
}
#include <gp_Pln.hxx>
#include <string>
-#include <SketcherPrs_DimensionStyleListener.h>
+#include <SketcherPrs_DimensionStyle.h>
DEFINE_STANDARD_HANDLE(SketcherPrs_LengthDimension, AIS_LengthDimension)
//Handle(Prs3d_DimensionAspect) myAspect;
/// Listener to update dimension visualization style
- SketcherPrs_DimensionStyleListener* myStyleListener;
+ SketcherPrs_DimensionStyle* myStyleListener;
/// container of values obtained from the constraint, which are necessary
/// to fill the presentation
double myDistance; ///< the flyout distance
/// the structure filled by constraint
- SketcherPrs_DimensionStyleListener::DimensionValue myValue;
+ SketcherPrs_DimensionStyle::DimensionValue myValue;
};
#endif
\ No newline at end of file
#include "SketcherPrs_Radius.h"
#include "SketcherPrs_Tools.h"
-#include "SketcherPrs_DimensionStyleListener.h"
+#include "SketcherPrs_DimensionStyle.h"
#include <SketchPlugin_ConstraintRadius.h>
#include <SketchPlugin_Constraint.h>
myValue(1, false, "")
{
SetDimensionAspect(createDimensionAspect());
- myStyleListener = new SketcherPrs_DimensionStyleListener();
+ myStyleListener = new SketcherPrs_DimensionStyle();
}
SketcherPrs_Radius::~SketcherPrs_Radius()
#include <AIS_RadiusDimension.hxx>
#include <Standard_DefineHandle.hxx>
-#include <SketcherPrs_DimensionStyleListener.h>
+#include <SketcherPrs_DimensionStyle.h>
DEFINE_STANDARD_HANDLE(SketcherPrs_Radius, AIS_RadiusDimension)
SketchPlugin_Sketch* mySketcher;
/// Listener to update dimension visualization style
- SketcherPrs_DimensionStyleListener* myStyleListener;
+ SketcherPrs_DimensionStyle* myStyleListener;
/// container of values obtained from the constraint, which are necessary to fill the presentation
gp_Circ myCircle; ///< the radius circle
gp_Pnt myAnchorPoint; ///< an ancor for the radius value visualization
- SketcherPrs_DimensionStyleListener::DimensionValue myValue; /// the structure filled by constraint
+ SketcherPrs_DimensionStyle::DimensionValue myValue; /// the structure filled by constraint
};
#endif
\ No newline at end of file
//
#include "SketcherPrs_SensitivePoint.h"
+#include "SketcherPrs_SymbolPrs.h"
#include <Graphic3d_ArrayOfPoints.hxx>
-#include "SketcherPrs_SymbolPrs.h"
+#include <Standard_Version.hxx>
#define DEBUG_SENSITIVE_TO_BE_CORRECTED
Standard_Boolean SketcherPrs_SensitivePoint::Matches(SelectBasics_SelectingVolumeManager& theMgr,
SelectBasics_PickResult& thePickResult)
{
- Standard_Real aDepth = RealLast();
- Standard_Real aDistToCOG = RealLast();
- gp_Pnt aPnt = Point();
- if (!theMgr.Overlaps (aPnt, aDepth))
- {
- thePickResult = SelectBasics_PickResult (aDepth, aDistToCOG);
- return Standard_False;
- }
+#if OCC_VERSION_HEX < 0x070400
+ Standard_Real aDepth = RealLast();
+ Standard_Real aDistToCOG = RealLast();
+ gp_Pnt aPnt = Point();
+ if (!theMgr.Overlaps(aPnt, aDepth))
+ {
+ thePickResult = SelectBasics_PickResult(aDepth, aDistToCOG);
+ return Standard_False;
+ }
- aDistToCOG = aDepth;
- thePickResult = SelectBasics_PickResult (aDepth, aDistToCOG);
- return Standard_True;
+ aDistToCOG = aDepth;
+ thePickResult = SelectBasics_PickResult(aDepth, aDistToCOG);
+ return Standard_True;
+#else
+ gp_Pnt aPnt = Point();
+ if (theMgr.Overlaps (aPnt, thePickResult))
+ return Standard_True;
+ return Standard_False;
+#endif
}
gp_Pnt SketcherPrs_SensitivePoint::Point() const
#ifndef SketcherPrs_SensitivePoint_H
#define SketcherPrs_SensitivePoint_H
+#include <SelectBasics_EntityOwner.hxx>
#include <Select3D_SensitiveEntity.hxx>
#include <Standard_DefineHandle.hxx>
}
// The icon for constraint is not found
static const char aMsg[] = "Error! constraint images are not found";
- cout<<aMsg<<endl;
+ std::cout<<aMsg<<std::endl;
Events_InfoMessage("SketcherPrs_SymbolPrs", aMsg).send();
myIconsMap[iconName()] = Handle(Image_AlienPixMap)();
return Handle(Image_AlienPixMap)();
namespace SketcherPrs_Tools {
+static ParameterStyle MyStyle = ParameterValue;
+
+void setParameterStyle(ParameterStyle theStyle)
+{
+ MyStyle = theStyle;
+}
+
+ParameterStyle parameterStyle()
+{
+ return MyStyle;
+}
+
AttributePtr getAttribute(ModelAPI_Feature* theFeature, const std::string& theAttrName)
{
AttributePtr anAttribute;
return thePlane->to3D(aFlyoutPnt->x(), aFlyoutPnt->y());
}
-void sendExpressionShownEvent(const bool& theState)
-{
- static Events_ID anId = SketcherPrs_ParameterStyleMessage::eventId();
- std::shared_ptr<SketcherPrs_ParameterStyleMessage> aMessage = std::shared_ptr
- <SketcherPrs_ParameterStyleMessage>(new SketcherPrs_ParameterStyleMessage(anId, 0));
- aMessage->setStyle(theState ? SketcherPrs_ParameterStyleMessage::ParameterText
- : SketcherPrs_ParameterStyleMessage::ParameterValue);
- Events_Loop::loop()->send(aMessage);
- Events_Loop::loop()->flush(anId);
-}
-
void sendEmptyPresentationError(ModelAPI_Feature* theFeature, const std::string theError)
{
Events_InfoMessage("SketcherPrs_Tools",
class GeomDataAPI_Point2D;
class AIS_Dimension;
-//#define MyTextHeight 20
+namespace SketcherPrs_Tools {
-/// Message that style of visualization of parameter is changed.
-/// It will be shown as expression or value
-class SketcherPrs_ParameterStyleMessage : public Events_Message
-{
-public:
/// \enum ParameterStyle lists styles of parameter
enum ParameterStyle {
ParameterValue, ///< using symbol with the parameter value
ParameterText ///< using parameter text
};
-public:
- /// Creates an empty message
- SKETCHERPRS_EXPORT SketcherPrs_ParameterStyleMessage(const Events_ID theID,
- const void* theSender = 0)
- : Events_Message(theID, theSender) {}
- /// The virtual destructor
- SKETCHERPRS_EXPORT virtual ~SketcherPrs_ParameterStyleMessage() {}
- /// Static. Returns EventID of the message.
- SKETCHERPRS_EXPORT static Events_ID eventId()
- {
- static const char * MY_EVENT_PARAMETER_STYLE_ID("ParameterStyle");
- return Events_Loop::eventByName(MY_EVENT_PARAMETER_STYLE_ID);
- }
- /// Returns a document stored in the message
- SKETCHERPRS_EXPORT ParameterStyle style() const { return myStyle; }
- /// Sets a document to the message
- SKETCHERPRS_EXPORT void setStyle(ParameterStyle theStyle) { myStyle = theStyle; }
-private:
- ParameterStyle myStyle; /// style of the parameter visualization
-};
+ /// Set dimensions parameters style
+ /// \param theStyle new style
+ SKETCHERPRS_EXPORT void setParameterStyle(ParameterStyle theStyle);
-namespace SketcherPrs_Tools {
+ /// Return dimensions parameters style
+ SKETCHERPRS_EXPORT ParameterStyle parameterStyle();
/// Enumeration with modes for activation of selection custom presentations
enum SelectionModes {
const ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
- /// Sends event about expression visualization type is changed for dimension presentations
- /// Sends event to redisplay all sub-features of composite feature
- /// \param theState a new state
- SKETCHERPRS_EXPORT void sendExpressionShownEvent(const bool& theState);
-
/// Throws an exception(in debug mode) and sends a signal about necessity to hide the object
/// \param theFeature a feature where AIS presentation is empty
/// \param theError a debug error information
void displayedObjects(const Handle(AIS_InteractiveContext)& theAIS, AIS_ListOfInteractive& theList)
{
// Get from null point
- theAIS->DisplayedObjects(theList, true);
+#if OCC_VERSION_HEX < 0x070400
+ theAIS->DisplayedObjects(theList, true);
+#else
+ theAIS->DisplayedObjects(theList);
+#endif
}
QString qIntListInfo(const QIntList& theValues, const QString& theSeparator = QString(", "))
//bool isCustomized = customizeObject(theObject);
int aDispMode = isShading? Shading : Wireframe;
- if (isShading)
- anAISIO->Attributes()->SetFaceBoundaryDraw( Standard_True );
anAISIO->SetDisplayMode(aDispMode);
aContext->Display(anAISIO, aDispMode, 0, false, true, AIS_DS_Displayed);
#ifdef TINSPECTOR
myContextId = aContext.get();
if (!myWorkshop->selectionActivate()->isTrihedronActive())
selectionActivate()->deactivateTrihedron(true);
- aContext->DefaultDrawer()->VIsoAspect()->SetNumber(0);
- aContext->DefaultDrawer()->UIsoAspect()->SetNumber(0);
+ // Do not modify default drawer. The same is done in ModuleBase_ResultPrs
+ //aContext->DefaultDrawer()->VIsoAspect()->SetNumber(0);
+ //aContext->DefaultDrawer()->UIsoAspect()->SetNumber(0);
//Handle(AIS_Trihedron) aTrihedron = myWorkshop->viewer()->trihedron();
//aTrihedron->getHighlightPointAspect()->SetScale(2.0);
//aTrihedron->getHighlightPointAspect()->SetTypeOfMarker(Aspect_TOM_O_STAR);
// Commented out according to discussion in bug #2825
- //ModuleBase_IViewer::DefaultHighlightDrawer = aContext->HighlightStyle();
+ ModuleBase_IViewer::DefaultHighlightDrawer = aContext->HighlightStyle();
//Handle(Prs3d_Drawer) aSelStyle = aContext->SelectionStyle();
//double aDeflection =
// QString(ModelAPI_ResultConstruction::DEFAULT_DEFLECTION().c_str()).toDouble();
#include <GeomAPI_Shape.h>
#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultGroup.h>
#include <ModelAPI_AttributeSelectionList.h>
#include <QAction>
#include <QGridLayout>
#include <QListWidget>
#include <QMainWindow>
+#include <QTimer>
static const int LayoutMargin = 3;
+//********************************************************************
+bool getGroup(ModuleBase_ViewerPrsPtr thePrs, ResultGroupPtr& theResGroup,
+ FeaturePtr& theGroupFeature)
+{
+ ObjectPtr anObject = thePrs->object();
+ if (!anObject.get())
+ return false;
+
+ theResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
+ if (theResGroup.get()) {
+ theGroupFeature = ModelAPI_Feature::feature(theResGroup);
+ }
+ else {
+ theGroupFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
+ if (theGroupFeature.get())
+ theResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(theGroupFeature->firstResult());
+ }
+ return theGroupFeature.get() && theResGroup.get();
+}
+
+//********************************************************************
+void updateHiddenShapes(Handle(ModuleBase_ResultPrs) thePrs, const TopoDS_ListOfShape& theShapes)
+{
+ TopoDS_ListOfShape aAlreadyHidden = thePrs->hiddenSubShapes();
+ TopoDS_ListOfShape::Iterator aShPIt(theShapes);
+ for (; aShPIt.More(); aShPIt.Next()) {
+ if (aAlreadyHidden.Contains(aShPIt.Value()))
+ aAlreadyHidden.Remove(aShPIt.Value());
+ }
+ thePrs->setSubShapeHidden(aAlreadyHidden);
+}
+
//********************************************************************
XGUI_FacesPanel::XGUI_FacesPanel(QWidget* theParent, XGUI_Workshop* theWorkshop)
: QDockWidget(theParent), myIsActive(false), myWorkshop(theWorkshop)
{
setWindowTitle(tr("Hide Faces"));
+ setObjectName("Hide Faces");
+
QAction* aViewAct = toggleViewAction();
setStyleSheet("::title { position: relative; padding-left: 5px; text-align: left center }");
myListView->getControl()->setFocusPolicy(Qt::StrongFocus);
myListView->getControl()->viewport()->installEventFilter(this);
+
+ XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+ connect(aDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
+ SLOT(onObjectDisplay(ObjectPtr, AISObjectPtr)));
}
//********************************************************************
std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
- QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> >::const_iterator aIt;
+ QMap<int, ModuleBase_ViewerPrsPtr >::const_iterator aIt;
for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
getObjectsMapFromPrs(aIt.value(), anObjectToShapes, anObjectToPrs);
}
aObjects.insert(aPrsIt->first);
aPrsIt->second->setSubShapeHidden(anEmpty);
}
- std::set<std::shared_ptr<ModelAPI_Object> >::const_iterator aGrpIt;
+ std::set<ObjectPtr >::const_iterator aGrpIt;
for (aGrpIt = myHiddenGroups.cbegin(); aGrpIt != myHiddenGroups.cend(); aGrpIt++)
(*aGrpIt)->setDisplayed(true);
myHiddenGroups.clear();
}
// remove from myItes container
- for (std::set<int>::const_iterator aToBeRemovedIt = anIndicesToBeRemoved.begin();
- aToBeRemovedIt != anIndicesToBeRemoved.end(); aToBeRemovedIt++)
- {
- myItems.remove(*aToBeRemovedIt);
- }
+ removeItems(anIndicesToBeRemoved);
if (!anIndicesToBeRemoved.empty()) // means that myItems has been changed
updateProcessedObjects(myItems, myItemObjects);
- myListView->removeItems(anIndicesToBeRemoved);
// remove from container of hidden objects
for (std::set<ObjectPtr>::const_iterator aHiddenIt = theHiddenObjects.begin();
}
//********************************************************************
-void XGUI_FacesPanel::getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+void XGUI_FacesPanel::getObjectsMapFromResult(ResultGroupPtr theResGroup,
+ FeaturePtr theGroupFeature,
std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectToShapes,
std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs)
{
- ObjectPtr anObject = thePrs->object();
- if (!anObject.get())
- return;
-
XGUI_Displayer* aDisplayer = myWorkshop->displayer();
- ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
- if (aResGroup.get()) {
- // Process a grouip result
- FeaturePtr aGroupFeature = ModelAPI_Feature::feature(aResGroup);
- AttributeSelectionListPtr aSelectionList = aGroupFeature->selectionList("group_list");
- AISObjectPtr aPrs;
- for (int i = 0; i < aSelectionList->size(); i++) {
- AttributeSelectionPtr aSelection = aSelectionList->value(i);
- ResultPtr aRes = aSelection->context();
- aPrs = aDisplayer->getAISObject(aRes);
- if (aPrs.get()) {
- Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
- aPrs->impl<Handle(AIS_InteractiveObject)>());
- if (!aResultPrs.IsNull()) {
- GeomShapePtr aShape = aSelection->value();
- if (theObjectToShapes.find(aRes) != theObjectToShapes.end())
- theObjectToShapes.at(aRes).Append(aShape->impl<TopoDS_Shape>());
- else {
- TopoDS_ListOfShape aListOfShapes;
- aListOfShapes.Append(aShape->impl<TopoDS_Shape>());
- theObjectToShapes[aRes] = aListOfShapes;
- theObjectToPrs[aRes] = aResultPrs;
- }
+ // Process a grouip result
+ AttributeSelectionListPtr aSelectionList = theGroupFeature->selectionList("group_list");
+ AISObjectPtr aPrs;
+ for (int i = 0; i < aSelectionList->size(); i++) {
+ AttributeSelectionPtr aSelection = aSelectionList->value(i);
+ ResultPtr aRes = aSelection->context();
+ aPrs = aDisplayer->getAISObject(aRes);
+ if (aPrs.get()) {
+ Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
+ aPrs->impl<Handle(AIS_InteractiveObject)>());
+ if (!aResultPrs.IsNull()) {
+ GeomShapePtr aShape = aSelection->value();
+ if (theObjectToShapes.find(aRes) != theObjectToShapes.end())
+ theObjectToShapes.at(aRes).Append(aShape->impl<TopoDS_Shape>());
+ else {
+ TopoDS_ListOfShape aListOfShapes;
+ aListOfShapes.Append(aShape->impl<TopoDS_Shape>());
+ theObjectToShapes[aRes] = aListOfShapes;
+ theObjectToPrs[aRes] = aResultPrs;
}
}
}
}
+}
+
+//********************************************************************
+void objectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+ std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectToShapes,
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs)
+{
+ ObjectPtr anObject = thePrs->object();
+ if (!anObject.get())
+ return;
+
+ // Process bodies
+ Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
+ thePrs->interactive());
+ if (aResultPrs.IsNull())
+ return;
+
+ if (theObjectToShapes.find(anObject) != theObjectToShapes.end())
+ theObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(thePrs));
else {
- // Process bodies
- Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
- thePrs->interactive());
- if (aResultPrs.IsNull())
- return;
-
- if (theObjectToShapes.find(anObject) != theObjectToShapes.end())
- theObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(thePrs));
- else {
- TopoDS_ListOfShape aListOfShapes;
- aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(thePrs));
- theObjectToShapes[anObject] = aListOfShapes;
- theObjectToPrs[anObject] = aResultPrs;
- }
+ TopoDS_ListOfShape aListOfShapes;
+ aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(thePrs));
+ theObjectToShapes[anObject] = aListOfShapes;
+ theObjectToPrs[anObject] = aResultPrs;
}
}
+//********************************************************************
+void XGUI_FacesPanel::getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+ std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectToShapes,
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs)
+{
+ ResultGroupPtr aResGroup;
+ FeaturePtr aGroupFeature;
+ if (getGroup(thePrs, aResGroup, aGroupFeature))
+ getObjectsMapFromResult(aResGroup, aGroupFeature, theObjectToShapes, theObjectToPrs);
+ else
+ objectsMapFromPrs(thePrs, theObjectToShapes, theObjectToPrs);
+}
+
//********************************************************************
void XGUI_FacesPanel::processSelection()
{
if (!anObject.get())
continue;
- ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
- if (aResGroup.get()) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(aResGroup);
- if (aFeature.get()) {
- AttributeSelectionListPtr aSelectionListAttr =
- aFeature->data()->selectionList("group_list");
- std::string aType = aSelectionListAttr->selectionType();
- if (aType != "Faces")
- continue;
- }
+ ResultGroupPtr aResGroup;
+ FeaturePtr aGroupFeature;
+ if (getGroup(aPrs, aResGroup, aGroupFeature)) {
+ AttributeSelectionListPtr aSelectionListAttr =
+ aGroupFeature->data()->selectionList("group_list");
+ std::string aType = aSelectionListAttr->selectionType();
+ if (aType != "Faces")
+ continue;
}
else {
GeomShapePtr aShapePtr = aPrs->shape();
if (myListView->hasItem(aItemName))
continue;
- getObjectsMapFromPrs(aPrs, anObjectToShapes, anObjectToPrs);
- if (aResGroup.get() && aResGroup->isDisplayed()) {
- aResGroup->setDisplayed(false);
- myHiddenGroups.insert(aResGroup);
+ if (aResGroup.get()) {
+ if (aResGroup->isDisplayed()) {
+ aResGroup->setDisplayed(false);
+ myHiddenGroups.insert(aResGroup);
+ }
+ getObjectsMapFromResult(aResGroup, aGroupFeature, anObjectToShapes, anObjectToPrs);
}
+ else
+ objectsMapFromPrs(aPrs, anObjectToShapes, anObjectToPrs);
// The code is dedicated to remove already selected items if they are selected twice
// It can happen in case of groups selection
}
// Remove duplicate items
- if (aToRemove.size() > 0) {
- myListView->removeItems(aToRemove);
- std::set<int>::const_iterator aIntIt;
- for (aIntIt = aToRemove.cbegin(); aIntIt != aToRemove.cend(); aIntIt++)
- myItems.remove(*aIntIt);
- }
+ removeItems(aToRemove);
if (isModified) {
updateProcessedObjects(myItems, myItemObjects);
flushRedisplay();
std::set<ModuleBase_ViewerPrsPtr>::const_iterator aIt;
for (aIt = aRestored.cbegin(); aIt != aRestored.cend(); aIt++) {
getObjectsMapFromPrs((*aIt), anObjectToShapes, anObjectToPrs);
- ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>((*aIt)->object());
- if (aResGroup.get()) {
- std::set<std::shared_ptr<ModelAPI_Object> >::iterator aGrpIt = myHiddenGroups.find(aResGroup);
+ ResultGroupPtr aResGroup;
+ FeaturePtr aGroupFeature;
+ if (getGroup((*aIt), aResGroup, aGroupFeature)) {
+ std::set<ObjectPtr >::iterator aGrpIt = myHiddenGroups.find(aResGroup);
if (aGrpIt != myHiddenGroups.end()) {
aResGroup->setDisplayed(true);
myHiddenGroups.erase(aGrpIt);
//********************************************************************
bool XGUI_FacesPanel::redisplayObjects(
- const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects)
+ const std::set<ObjectPtr >& theObjects)
{
if (theObjects.empty())
return false;
for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = theItems.begin();
anIt != theItems.end(); anIt++) {
ModuleBase_ViewerPrsPtr aPrs = anIt.value();
- ObjectPtr anObject = aPrs.get() ? aPrs->object() : ObjectPtr();
- if (anObject.get()) {
- ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
- if (aResGroup.get()) {
- FeaturePtr aGroupFeature = ModelAPI_Feature::feature(aResGroup);
- AttributeSelectionListPtr aSelectionList = aGroupFeature->selectionList("group_list");
- for (int i = 0; i < aSelectionList->size(); i++) {
- AttributeSelectionPtr aSelection = aSelectionList->value(i);
- ResultPtr aRes = aSelection->context();
- if (theObjects.find(aRes) == theObjects.end())
- theObjects.insert(aRes);
- }
- }
- else {
- if (theObjects.find(anObject) == theObjects.end())
- theObjects.insert(anObject);
+ ResultGroupPtr aResGroup;
+ FeaturePtr aGroupFeature;
+ if (getGroup(aPrs, aResGroup, aGroupFeature)) {
+ AttributeSelectionListPtr aSelectionList = aGroupFeature->selectionList("group_list");
+ for (int i = 0; i < aSelectionList->size(); i++) {
+ AttributeSelectionPtr aSelection = aSelectionList->value(i);
+ ResultPtr aRes = aSelection->context();
+ if (theObjects.find(aRes) == theObjects.end())
+ theObjects.insert(aRes);
}
}
+ else {
+ if (theObjects.find(aPrs->object()) == theObjects.end())
+ theObjects.insert(aPrs->object());
+ }
}
}
{
std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
- QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> >::const_iterator aIt;
+ QMap<int, ModuleBase_ViewerPrsPtr >::const_iterator aIt;
for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
getObjectsMapFromPrs(aIt.value(), anObjectToShapes, anObjectToPrs);
}
anObjectBrowser->updateAllIndexes();
myWorkshop->viewer()->update();
}
+
+
+//********************************************************************
+void XGUI_FacesPanel::onObjectDisplay(ObjectPtr theObject, AISObjectPtr theAIS)
+{
+ bool aContains = false;
+ QMap<int, ModuleBase_ViewerPrsPtr>::iterator aIt;
+ for (aIt = myItems.begin(); aIt != myItems.end(); aIt++) {
+ ModuleBase_ViewerPrsPtr aPrs = aIt.value();
+ if (aPrs->object() == theObject) {
+ aContains = true;
+ break;
+ }
+ }
+ if (aContains) {
+ ResultGroupPtr aResGroup;
+ FeaturePtr aGroupFeature;
+ std::map<ObjectPtr, TopoDS_ListOfShape> aObjectToShapes;
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)> aObjectToPrs;
+ std::set<ObjectPtr> aObjects;
+ std::set<int> aIdsToRem;
+
+ TopoDS_ListOfShape aHideShapes;
+ std::map<ObjectPtr, TopoDS_ListOfShape>::const_iterator aSIt;
+ for (aIt = myItems.begin(); aIt != myItems.end(); aIt++) {
+ ModuleBase_ViewerPrsPtr aPrs = aIt.value();
+ if (getGroup(aPrs, aResGroup, aGroupFeature)) {
+ getObjectsMapFromResult(aResGroup, aGroupFeature, aObjectToShapes, aObjectToPrs);
+ if (aResGroup == theObject) {
+ // If group is displayed it means that it has to be deleted from the Faces list and all
+ // corresponded faces have been restored
+ for (aSIt = aObjectToShapes.begin(); aSIt != aObjectToShapes.end(); aSIt++) {
+ TopoDS_ListOfShape aShapes = aSIt->second;
+ Handle(ModuleBase_ResultPrs) aPrs = aObjectToPrs[aSIt->first];
+ TopoDS_ListOfShape aAlreadyHidden = aPrs->hiddenSubShapes();
+ TopoDS_ListOfShape::Iterator aShPIt(aShapes);
+ for (; aShPIt.More(); aShPIt.Next()) {
+ if (aAlreadyHidden.Contains(aShPIt.Value()))
+ aAlreadyHidden.Remove(aShPIt.Value());
+ }
+ aPrs->setSubShapeHidden(aAlreadyHidden);
+ aObjects.insert(aSIt->first);
+ }
+ aIdsToRem.insert(aIt.key());
+ }
+ else {
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::iterator aPIt =
+ aObjectToPrs.find(theObject);
+ if (aPIt != aObjectToPrs.end()) {
+ ObjectPtr aObj = aPIt->first;
+ if (aObj == theObject) {
+ Handle(ModuleBase_ResultPrs) aPrs = aPIt->second;
+ TopoDS_ListOfShape aShapes = aObjectToShapes[aObj];
+ aHideShapes.Append(aShapes);
+ aObjects.insert(aObj);
+ }
+ }
+ }
+ }
+ else {
+ if (aPrs->object() == theObject) {
+ TopoDS_Shape aShape = aPrs->shape()->impl<TopoDS_Shape>();
+ if (!aShape.IsNull())
+ aHideShapes.Append(aShape);
+ aPrs->setInteractive(theAIS->impl<Handle(AIS_InteractiveObject)>());
+ }
+ }
+ }
+ double aTransp = transparency();
+ if (aHideShapes.Size() > 0) {
+ Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
+ theAIS->impl<Handle(AIS_InteractiveObject)>());
+ if (!aResultPrs.IsNull()) {
+ aResultPrs->setSubShapeHidden(aHideShapes);
+ aResultPrs->setHiddenSubShapeTransparency(aTransp);
+ aObjects.insert(theObject);
+ }
+ }
+ removeItems(aIdsToRem);
+ myWorkshop->selector()->clearSelection();
+ if (redisplayObjects(aObjects))
+ QTimer::singleShot(50, this, SLOT(flushRedisplay()));
+ }
+}
+
+void XGUI_FacesPanel::removeItems(std::set<int> theIds)
+{
+ if (theIds.empty())
+ return;
+ myListView->removeItems(theIds);
+ std::set<int>::const_iterator aRIt;
+ for (aRIt = theIds.begin(); aRIt != theIds.end(); aRIt++)
+ myItems.remove(*aRIt);
+}
#include "XGUI.h"
-#include <ModelAPI_Object.h>
-
#include <ModuleBase_ActionType.h>
#include <ModuleBase_Definitions.h>
#include <ModuleBase_ViewerPrs.h>
#include <ModuleBase_ResultPrs.h>
+#include <ModelAPI_Object.h>
+#include <ModelAPI_ResultGroup.h>
+#include <ModelAPI_Feature.h>
+
+#include <GeomAPI_AISObject.h>
+
#include <SelectMgr_ListOfFilter.hxx>
#include <TopoDS_Shape.hxx>
/// Returns true if the object is in internal container of hidden objects by this panel
/// \param theObject a checked object
/// \return boolean value
- bool isObjectHiddenByPanel(const std::shared_ptr<ModelAPI_Object>& theObject) const
+ bool isObjectHiddenByPanel(const ObjectPtr& theObject) const
{ return myHiddenObjects.find(theObject) != myHiddenObjects.end(); }
/// Removed faces of the objects from the panel
/// \param container of objects
- void restoreObjects(const std::set<std::shared_ptr<ModelAPI_Object> >& theHiddenObjects);
+ void restoreObjects(const std::set<ObjectPtr >& theHiddenObjects);
/// Returns true if the event is processed. The default implementation is empty, returns false.
virtual bool processAction(ModuleBase_ActionType theActionType);
XGUI_Workshop* workshop() const { return myWorkshop; }
+public slots:
+ /// Slot called on an object erase
+ void onObjectDisplay(ObjectPtr theObject, AISObjectPtr theAIS);
protected:
/// Reimplementation to emit a signal about the panel close
/// Redisplay objects.
/// \param theObjects container of objects
/// \return true if some of objects was redisplayed
- static bool redisplayObjects(const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects);
+ static bool redisplayObjects(const std::set<ObjectPtr>& theObjects);
/// Container of objects participating in the panel, it is filled by internal container
/// \param theItems container of selected values
/// \param theObjects [out] container of objects
- static void updateProcessedObjects(QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> > theItems,
- std::set<std::shared_ptr<ModelAPI_Object> >& theObjects);
+ static void updateProcessedObjects(QMap<int, ModuleBase_ViewerPrsPtr> theItems,
+ std::set<ObjectPtr>& theObjects);
/// Returns maps of shapes and presentations. If object is a body result then it returns
/// its ruslts. If it is a group then it returns result of shapes included into the gropup
/// \param thePrs a selected presintation
/// \param theObjectsToShapes map of objects to shapes list
/// \param theObjectToPrs map of objects to presentations
- void getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+ void getObjectsMapFromResult(ResultGroupPtr theResGroup, FeaturePtr theGroupFeature,
std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectsToShapes,
std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs);
+ void getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+ std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectToShapes,
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs);
+
/// Returns true if transparency choice is checked
/// \return boolean value
bool useTransparency() const;
double transparency() const;
+ void removeItems(std::set<int> theIds);
+
protected slots:
/// Deletes element in list of items
void onDeleteItem();
/// Closes faces panel restore all hidden faces by calling reset()
void onClosed();
-private:
/// Flushes redisplay event and perform update of object browser icons
/// (objects might be hidden/shown)
void flushRedisplay() const;
-protected:
+private:
+
QCheckBox* myHiddenOrTransparent; ///< if checked - transparent, else hidden
ModuleBase_ListView* myListView; ///< list control of processed faces
XGUI_Workshop* myWorkshop; ///< workshop
int myLastItemIndex; ///< last index to be used in the map of items for the next added item
QMap<int, ModuleBase_ViewerPrsPtr> myItems; ///< selected face items
- std::set<std::shared_ptr<ModelAPI_Object> > myItemObjects; ///< cached objects of myItems
- std::set<std::shared_ptr<ModelAPI_Object> > myHiddenObjects; ///< hidden objects
- std::set<std::shared_ptr<ModelAPI_Object> > myHiddenGroups; ///< hidden objects
+ std::set<ObjectPtr > myItemObjects; ///< cached objects of myItems
+ std::set<ObjectPtr > myHiddenObjects; ///< hidden objects
+ std::set<ObjectPtr > myHiddenGroups; ///< hidden objects
};
#endif
\ No newline at end of file
//********************************************************************
void XGUI_InspectionPanel::clearContent()
{
+ myStackWgt->setCurrentIndex(myFeaturePanelId);
setName("");
for (int i = 0; i <= VertexId; i++) {
mySubShapesTab->item((SudShape)i, 1)->setText("");
buildFeaturePane(aFeature);
}
else {
- myStackWgt->setCurrentIndex(myShapePanelId);
TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
if (aShape.IsNull()) {
ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
}
}
}
- if (aShape.IsNull())
+ if (aShape.IsNull()) {
+ myStackWgt->setCurrentIndex(myFeaturePanelId);
return;
+ }
+ myStackWgt->setCurrentIndex(myShapePanelId);
GeomShapePtr aShapePtr(new GeomAPI_Shape());
aShapePtr->setImpl(new TopoDS_Shape(aShape));
#include "ModuleBase_OperationFeature.h"
#include "ModuleBase_Tools.h"
-#include "ModelAPI_CompositeFeature.h"
-#include "ModelAPI_Session.h"
+#include <Config_Translator.h>
+
+#include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_Session.h>
#include <XGUI_PropertyPanel.h>
#include <QToolButton>
if (isGrantedOperation(theOperation->id()))
return true;
if (theOperation && theOperation->isModified()) {
- QString aTitle = theOperation->getDescription()->description();
+ ModuleBase_OperationFeature* aOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
+ std::string aContext;
+ if (aOp)
+ aContext = aOp->feature()->getKind();
+ QString aTitle = Config_Translator::translate(aContext,
+ theOperation->getDescription()->description().toStdString()).c_str();
+
if (theMessageKind == XGUI_AbortOperationMessage) {
QString aMessage = tr("%1 operation will be aborted.").arg(aTitle);
myActiveMessageBox = createMessageBox(aMessage);
if (theFeature->isAction() || !theFeature->data())
return;
+ ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
if (myWidgets.empty()) {
- ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
QString aXmlRepr = anOperation->getDescription()->xmlRepresentation();
ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myOperationMgr->workshop());
- aFactory.createPanel(contentWidget(), theFeature);
- /// Apply button should be update if the feature was modified by the panel
+ ModuleBase_PageBase* aPage = contentWidget();
+ aFactory.createPanel(aPage, theFeature);
+ // update model widgets if exist
+ setModelWidgets(aPage->modelWidgets());
+ // Apply button should be update if the feature was modified by the panel
myOperationMgr->onValidateOperation();
}
- updateApplyPlusButton(theFeature);
+ ModuleBase_OperationFeature* aFeatureOp =
+ dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
+ if (aFeatureOp && (!aFeatureOp->isEditOperation()))
+ updateApplyPlusButton(theFeature);
+ else
+ findButton(PROP_PANEL_OK_PLUS)->setVisible(false);
}
void XGUI_PropertyPanel::updateApplyPlusButton(FeaturePtr theFeature)
ModuleBase_ModelWidget* aNewFocusMWidget = ModuleBase_ModelWidget::findModelWidget(this,
aNewFocusWidget);
if (aNewFocusMWidget) {
- if (aFocusMWidget) {
+ if (aFocusMWidget && (aFocusMWidget != aNewFocusMWidget)) {
aFocusMWidget->setHighlighted(false);
}
aNewFocusMWidget->emitFocusInWidget();
myLastSelectionPlace = ModuleBase_ISelection::Viewer;
QList<ModuleBase_ViewerPrsPtr> aValues;
Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
- if (!aContext.IsNull())
+ if (!aContext.IsNull()) {
aValues = selection()->getSelected(ModuleBase_ISelection::Viewer);
-
+ // Update is necessary for OCCT 7.4.0: when it is clears selection it doesn't updates viewer
+#if OCC_VERSION_HEX == 0x070400
+ if (aValues.isEmpty())
+ aContext->UpdateCurrentViewer();
+#endif
+ }
QObjectPtrList anObjects;
convertToObjectBrowserSelection(aValues, anObjects);
myWorkshop->objectBrowser()->setObjectsSelected(anObjects);
aView3d->SetProj(theX, theY, theZ);
aView3d->SetTwist( theTwist );
aView3d->FitAll(0.01, false);
- aView3d->SetZSize(0.);
+ //aView3d->SetZSize(0.);
if (aView3d->Depth() < 0.1)
aView3d->DepthFitAll();
}
// Load translations
QStringList aLangs;
aLangs << "*_en.ts"; // load by default eng translations
+
+ /// If version of OCCT is 7.4.0 or more then it means that
+ /// this is version of SALOME older then 9.4.0
+#if OCC_VERSION_HEX >= 0x070400
+ QString aCurrLang = aResMgr->language();
+#else
QString aCurrLang = aResMgr->stringValue("language", "language", "en");
+#endif
+
if(aCurrLang != "en") {
aLangs << "*_" + aCurrLang + ".ts"; // then replace with translated files
}
if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) {
if (!theOperation->isHideFacesVisible())
- myFacesPanel->hide();
+ myFacesPanel->close();
}
}
if (abortAllOperations()) {
ModuleBase_OperationFeature* anImportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
module()->createOperation(ExchangePlugin_ImportPart::ID()));
+ myPropertyPanel->updateApplyPlusButton(anImportPartOp->feature());
operationMgr()->startOperation(anImportPartOp);
}
}
if (abortAllOperations()) {
ModuleBase_OperationFeature* anExportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
module()->createOperation(ExchangePlugin_ExportPart::ID()));
+ myPropertyPanel->updateApplyPlusButton(anExportPartOp->feature());
operationMgr()->startOperation(anExportPartOp);
}
}
myObjectBrowser->initialize(myModule->rootNode());
myModule->customizeObjectBrowser(myObjectBrowser);
aObjDock->setWidget(myObjectBrowser);
+ aObjDock->setObjectName("Object browser");
connect(myObjectBrowser, SIGNAL(sizeChanged()), SLOT(onDockSizeChanged()));
}
QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
+ if (anObjects.isEmpty())
+ return;
+
if (!abortAllOperations())
return;
<source>Validate operation</source>
<translation>Valider l'opération</translation>
</message>
+ <message>
+ <source>Part files (*.shaperpart);;All files (*.*)</source>
+ <translation>Fichiers pièces (*.shaperpart);;Tous les fichiers (*.*)</translation>
+ </message>
</context>
<context>
<name>XGUI_ActionsMgr</name>
<source>Windows</source>
<translation>Fenêtres</translation>
</message>
+ <message>
+ <source>Iso-lines...</source>
+ <translation></translation>
+ </message>
</context>
<context>
<name>XGUI_DataTree</name>
</message>
<message>
<source>INF_DESK_TOOLBAR_STANDARD</source>
- <translation type="unfinished"></translation>
+ <translation>INF_DESK_TOOLBAR_STANDARD</translation>
</message>
<message>
<source>Redo</source>
<source>Results not found</source>
<translation>Résultats non trouvés</translation>
</message>
+ <message>
+ <source>Export part...</source>
+ <translation>Partie export...</translation>
+ </message>
+ <message>
+ <source>Export a part of the current document into a file</source>
+ <translation>Exporter une partie du document courant dans un fichier</translation>
+ </message>
+ <message>
+ <source>Import part...</source>
+ <translation>Importer une partie...</translation>
+ </message>
+ <message>
+ <source>Import structure of a part</source>
+ <translation>Structure d'importation d'une pièce</translation>
+ </message>
+ <message>
+ <source>Import shape...</source>
+ <translation>Forme de l'importation...</translation>
+ </message>
+ <message>
+ <source>Import shape from a file</source>
+ <translation>Importer une forme à partir d'un fichier</translation>
+ </message>
+ <message>
+ <source>Number of Iso-lines</source>
+ <translation>Nombre de lignes Iso-Lines</translation>
+ </message>
</context>
</TS>
<file>pictures/normal-view.png</file>
<file>pictures/move_to_end.png</file>
<file>pictures/move_to_end_split.png</file>
+ <file>pictures/ArrowCursor.png</file>
+ <file>pictures/CrossCursor.png</file>
+ <file>pictures/HandCursor.png</file>
</qresource>
</RCC>
SET(RESTRICTED_ROOT_DIR $ENV{RESTRICTED_ROOT_DIR} CACHE PATH "Path to the restricted repository")
+set(hdfFilesRestr "")
if (EXISTS ${RESTRICTED_ROOT_DIR})
file(GLOB hdfFilesRestr "${RESTRICTED_ROOT_DIR}/SHAPER/test.hdfs/*.hdf")
+endif()
+
+file(GLOB hdfFilesCur "${CMAKE_CURRENT_SOURCE_DIR}/*.hdf")
+set(hdfFilesRestr ${hdfFilesCur} ${hdfFilesRestr})
- if (WIN32) # different separators and path to libraries variable name
- SET(_JUSTPATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_BIN};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES};${SUIT_LIB_DIR};$ENV{PATH}")
- STRING(REPLACE "\\" "/" _JUSTPATH "${_JUSTPATH}")
- STRING(REPLACE ";" "\\;" _JUSTPATH "${_JUSTPATH}")
- SET(_PYTHONPATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_ADDONS};$ENV{PYTHONPATH}")
- STRING(REPLACE "\\" "/" _PYTHONPATH "${_PYTHONPATH}")
- STRING(REPLACE ";" "\\;" _PYTHONPATH "${_PYTHONPATH}")
- else()
- SET(_LD_LIBRARY_PATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_BIN}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES}:${SUIT_LIB_DIR}:$ENV{LD_LIBRARY_PATH}")
- SET(_PYTHONPATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_ADDONS}:$ENV{PYTHONPATH}")
- endif()
+if (WIN32) # different separators and path to libraries variable name
+ SET(_JUSTPATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_BIN};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES};${SUIT_LIB_DIR};$ENV{PATH}")
+ STRING(REPLACE "\\" "/" _JUSTPATH "${_JUSTPATH}")
+ STRING(REPLACE ";" "\\;" _JUSTPATH "${_JUSTPATH}")
+ SET(_PYTHONPATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES};${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_ADDONS};$ENV{PYTHONPATH}")
+ STRING(REPLACE "\\" "/" _PYTHONPATH "${_PYTHONPATH}")
+ STRING(REPLACE ";" "\\;" _PYTHONPATH "${_PYTHONPATH}")
+else()
+ SET(_LD_LIBRARY_PATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_BIN}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES}:${SUIT_LIB_DIR}:$ENV{LD_LIBRARY_PATH}")
+ SET(_PYTHONPATH "${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_SWIG}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_PLUGIN_FILES}:${CMAKE_INSTALL_PREFIX}/${SHAPER_INSTALL_ADDONS}:$ENV{PYTHONPATH}")
+endif()
- foreach(eachFilePath ${hdfFilesRestr})
- # Strip the ".hdf" suffix
- GET_FILENAME_COMPONENT(aTestName ${eachFilePath} NAME_WE)
- # Check corresponding ".py" file with reference data exists
- IF(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${aTestName}.py")
- MESSAGE(WARNING "File ${aTestName}.py containing reference data does not exist")
- continue()
- ENDIF()
+foreach(eachFilePath ${hdfFilesRestr})
+ # Strip the ".hdf" suffix
+ GET_FILENAME_COMPONENT(aTestName ${eachFilePath} NAME_WE)
+ # Check corresponding ".py" file with reference data exists
+ IF(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${aTestName}.py")
+ MESSAGE(WARNING "File ${aTestName}.py containing reference data does not exist")
+ continue()
+ ENDIF()
- # Add "SubprojectName_" prefix
- GET_FILENAME_COMPONENT(aSubprojectName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
- SET(aTestName "${aSubprojectName}_${aTestName}")
+ # Add "SubprojectName_" prefix
+ GET_FILENAME_COMPONENT(aSubprojectName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+ SET(aTestName "${aSubprojectName}_${aTestName}")
- # Full path to the python test file being executed
- SET(aTestFilePath "${eachFilePath}")
- IF(EXISTS ${aTestFilePath})
- ADD_TEST(NAME ${aTestName} COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/test.py" "$ENV{KERNEL_ROOT_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" "${aTestFilePath}")
- if (WIN32) # different path to libraries variable name
- SET_TESTS_PROPERTIES(${aTestName} PROPERTIES ENVIRONMENT "PATH=${_JUSTPATH};PYTHONPATH=${_PYTHONPATH}"
- LABELS "models_hdf")
- else()
- SET_TESTS_PROPERTIES(${aTestName} PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${_LD_LIBRARY_PATH};PYTHONPATH=${_PYTHONPATH}"
- LABELS "models_hdf")
- endif()
- # Debug output...
- # MESSAGE(STATUS "Test added: ${aTestName} file: ${aTestFilePath}")
- ELSE(EXISTS ${aTestFilePath})
- MESSAGE(WARNING "Can not find the test file: ${aTestFilePath}")
- ENDIF(EXISTS ${aTestFilePath})
- endforeach(eachFilePath ${ARGN})
+ # Full path to the python test file being executed
+ SET(aTestFilePath "${eachFilePath}")
+ IF(EXISTS ${aTestFilePath})
+ ADD_TEST(NAME ${aTestName} COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/test.py" "$ENV{KERNEL_ROOT_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" "${aTestFilePath}")
+ if (WIN32) # different path to libraries variable name
+ SET_TESTS_PROPERTIES(${aTestName} PROPERTIES ENVIRONMENT "PATH=${_JUSTPATH};PYTHONPATH=${_PYTHONPATH}"
+ LABELS "models_hdf")
+ else()
+ SET_TESTS_PROPERTIES(${aTestName} PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${_LD_LIBRARY_PATH};PYTHONPATH=${_PYTHONPATH}"
+ LABELS "models_hdf")
+ endif()
+ # Debug output...
+ # MESSAGE(STATUS "Test added: ${aTestName} file: ${aTestFilePath}")
+ ELSE(EXISTS ${aTestFilePath})
+ MESSAGE(WARNING "Can not find the test file: ${aTestFilePath}")
+ ENDIF(EXISTS ${aTestFilePath})
+endforeach(eachFilePath ${ARGN})
- ADD_CUSTOM_TARGET(run_hdf_tests COMMAND ${CMAKE_CTEST_COMMAND} -C "${CMAKE_BUILD_TYPE}" -L "models_hdf")
-endif()
+ADD_CUSTOM_TARGET(run_hdf_tests COMMAND ${CMAKE_CTEST_COMMAND} -C "${CMAKE_BUILD_TYPE}" -L "models_hdf")
--- /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
+#
+
+if __name__ == "__main__":
+ aPartFeature = locals()["Part_1"]
+ model.testNbResults(aPartFeature, 1)
+ model.testNbSubResults(aPartFeature, [0])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.SOLID, [552])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.FACE, [4086])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.EDGE, [17086])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.VERTEX, [34172])
+ model.testResultsVolumes(aPartFeature, [55.645173358299])
--- /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
+#
+
+if __name__ == "__main__":
+ aPartFeature = locals()["Part_1"]
+ model.testNbResults(aPartFeature, 1)
+ model.testNbSubResults(aPartFeature, [0])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.SOLID, [3])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.FACE, [33])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.EDGE, [162])
+ model.testNbSubShapes(aPartFeature, GeomAPI_Shape.VERTEX, [324])
+ model.testResultsVolumes(aPartFeature, [75056.139056284388])