]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'V9_4_BR'
authorvsr <vsr@opencascade.com>
Fri, 6 Dec 2019 14:07:16 +0000 (17:07 +0300)
committervsr <vsr@opencascade.com>
Fri, 6 Dec 2019 14:07:16 +0000 (17:07 +0300)
427 files changed:
CMakeLists.txt
doc/gui/Introduction.rst
doc/gui/images/plugins_preferences.png
doc/gui/images/popup_menu_object_browser_feature.png
doc/gui/images/shortcuts_preferences.png [new file with mode: 0644]
doc/gui/images/sketch_preferences.png
doc/gui/images/viewer_preferences.png
doc/gui/images/visualization_preferences.png
doc/gui/images/windows_preferences.png [new file with mode: 0644]
env_linux.sh
src/BuildAPI/BuildAPI_Edge.cpp
src/BuildAPI/BuildAPI_Edge.h
src/BuildAPI/BuildAPI_Vertex.cpp
src/BuildAPI/BuildAPI_Vertex.h
src/BuildAPI/BuildAPI_Wire.cpp
src/BuildAPI/BuildAPI_Wire.h
src/BuildPlugin/BuildPlugin_Edge.cpp
src/BuildPlugin/BuildPlugin_Edge.h
src/BuildPlugin/BuildPlugin_Face.cpp
src/BuildPlugin/BuildPlugin_Plugin.cpp
src/BuildPlugin/BuildPlugin_Shell.cpp
src/BuildPlugin/BuildPlugin_Validators.cpp
src/BuildPlugin/BuildPlugin_Validators.h
src/BuildPlugin/BuildPlugin_Vertex.cpp
src/BuildPlugin/BuildPlugin_Vertex.h
src/BuildPlugin/BuildPlugin_Wire.cpp
src/BuildPlugin/BuildPlugin_Wire.h
src/BuildPlugin/BuildPlugin_msg_fr.ts [new file with mode: 0644]
src/BuildPlugin/CMakeLists.txt
src/BuildPlugin/Test/TestEdge.py
src/BuildPlugin/Test/TestEdge_WholeSketch_1.py [new file with mode: 0644]
src/BuildPlugin/Test/TestEdge_WholeSketch_2.py [new file with mode: 0644]
src/BuildPlugin/Test/TestEdge_WholeSketch_3.py [new file with mode: 0644]
src/BuildPlugin/Test/TestEdge_WholeSketch_4.py [new file with mode: 0644]
src/BuildPlugin/Test/TestFace_WholeSketch_1.py [new file with mode: 0644]
src/BuildPlugin/Test/TestFace_WholeSketch_2.py [new file with mode: 0644]
src/BuildPlugin/Test/TestShell_WholeSketch_1.py [new file with mode: 0644]
src/BuildPlugin/Test/TestShell_WholeSketch_2.py [new file with mode: 0644]
src/BuildPlugin/Test/TestVertex.py
src/BuildPlugin/Test/TestVertex_WholeSketch_1.py [new file with mode: 0644]
src/BuildPlugin/Test/TestVertex_WholeSketch_2.py [new file with mode: 0644]
src/BuildPlugin/Test/TestWire.py
src/BuildPlugin/Test/TestWire_WholeSketch_1.py [new file with mode: 0644]
src/BuildPlugin/Test/TestWire_WholeSketch_2.py [new file with mode: 0644]
src/BuildPlugin/Test/TestWire_WholeSketch_3.py [new file with mode: 0644]
src/BuildPlugin/Test/TestWire_WholeSketch_4.py [new file with mode: 0644]
src/BuildPlugin/Test/TestWire_WholeSketch_5.py [new file with mode: 0644]
src/BuildPlugin/Test/TestWire_WholeSketch_6.py [new file with mode: 0644]
src/BuildPlugin/doc/edgeFeature.rst
src/BuildPlugin/doc/faceFeature.rst
src/BuildPlugin/doc/images/Edge.png
src/BuildPlugin/doc/images/Vertex.png
src/BuildPlugin/doc/images/Wire.png
src/BuildPlugin/doc/shellFeature.rst
src/BuildPlugin/doc/vertexFeature.rst
src/BuildPlugin/doc/wireFeature.rst
src/BuildPlugin/edge_widget.xml
src/BuildPlugin/face_widget.xml
src/BuildPlugin/shell_widget.xml
src/BuildPlugin/vertex_widget.xml
src/BuildPlugin/wire_widget.xml
src/CollectionPlugin/CMakeLists.txt
src/CollectionPlugin/CollectionPlugin_Group.cpp
src/CollectionPlugin/CollectionPlugin_Group.h
src/CollectionPlugin/CollectionPlugin_msg_fr.ts [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMoveAndSplit1.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMoveAndSplit2.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMoveAndSplit3.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupWholeFeature1.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupWholeFeature2.py [new file with mode: 0644]
src/CollectionPlugin/plugin-Collection.xml
src/Config/Config_FeatureMessage.cpp
src/Config/Config_FeatureMessage.h
src/Config/Config_FeatureReader.cpp
src/Config/Config_Keywords.h
src/Config/Config_WidgetAPI.h
src/ConnectorPlugin/CMakeLists.txt
src/ConnectorPlugin/ConnectorPlugin_msg_fr.ts [new file with mode: 0644]
src/ConstructionPlugin/CMakeLists.txt
src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts [new file with mode: 0644]
src/ConstructionPlugin/doc/images/Point1.png
src/ConstructionPlugin/doc/images/Point2.png
src/ConstructionPlugin/doc/images/Point3.png
src/ConstructionPlugin/doc/images/Point4.png
src/ConstructionPlugin/doc/images/Point5.png
src/ConstructionPlugin/plugin-Construction.xml
src/Events/Events.i
src/Events/Events_Listener.h
src/ExchangeAPI/ExchangeAPI_Export.cpp
src/ExchangeAPI/ExchangeAPI_Export.h
src/ExchangeAPI/ExchangeAPI_Import.cpp
src/ExchangeAPI/ExchangeAPI_Import.h
src/ExchangePlugin/CMakeLists.txt
src/ExchangePlugin/ExchangePlugin_ExportPart.cpp [new file with mode: 0644]
src/ExchangePlugin/ExchangePlugin_ExportPart.h [new file with mode: 0644]
src/ExchangePlugin/ExchangePlugin_ImportPart.cpp [new file with mode: 0644]
src/ExchangePlugin/ExchangePlugin_ImportPart.h [new file with mode: 0644]
src/ExchangePlugin/ExchangePlugin_Plugin.cpp
src/ExchangePlugin/ExchangePlugin_Validators.cpp
src/ExchangePlugin/ExchangePlugin_Validators.h
src/ExchangePlugin/ExchangePlugin_msg_en.ts
src/ExchangePlugin/ExchangePlugin_msg_fr.ts [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Failure_1.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Failure_2.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Failure_3.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_FullPartSet.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_FullPart_1.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_FullPart_2.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_PartSet.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_1.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_2.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_3.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_4.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_5.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_6.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_7.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestExportPart_Results_8.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterCurrent_1.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterCurrent_2.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterLast_1.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterLast_2.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterLast_3.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterLast_4.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterLast_5.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_AfterLast_6.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_Construction_1.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_Construction_2.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_Construction_3.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_Construction_4.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_Multiple.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_ToEmptyPart.py [new file with mode: 0644]
src/ExchangePlugin/Test/TestImportPart_ToEmptyPartSet.py [new file with mode: 0644]
src/ExchangePlugin/icons/export_part.png [new file with mode: 0644]
src/ExchangePlugin/icons/import_part.png [new file with mode: 0644]
src/ExchangePlugin/plugin-Exchange.xml
src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.cpp
src/FeaturesAPI/FeaturesAPI_ExtrusionBoolean.h
src/FeaturesAPI/FeaturesAPI_RevolutionBoolean.cpp
src/FeaturesAPI/FeaturesAPI_RevolutionBoolean.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.h
src/FeaturesPlugin/FeaturesPlugin_BooleanCut.h
src/FeaturesPlugin/FeaturesPlugin_BooleanFill.h
src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp
src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.h
src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.h
src/FeaturesPlugin/FeaturesPlugin_Chamfer.h
src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.h
src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp
src/FeaturesPlugin/FeaturesPlugin_Extrusion.h
src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp
src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.h
src/FeaturesPlugin/FeaturesPlugin_ExtrusionCut.h
src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.cpp
src/FeaturesPlugin/FeaturesPlugin_ExtrusionFuse.h
src/FeaturesPlugin/FeaturesPlugin_Fillet.h
src/FeaturesPlugin/FeaturesPlugin_Measurement.h
src/FeaturesPlugin/FeaturesPlugin_MultiRotation.h
src/FeaturesPlugin/FeaturesPlugin_MultiTranslation.h
src/FeaturesPlugin/FeaturesPlugin_Partition.h
src/FeaturesPlugin/FeaturesPlugin_Pipe.h
src/FeaturesPlugin/FeaturesPlugin_Placement.h
src/FeaturesPlugin/FeaturesPlugin_Recover.h
src/FeaturesPlugin/FeaturesPlugin_RemoveSubShapes.h
src/FeaturesPlugin/FeaturesPlugin_Revolution.cpp
src/FeaturesPlugin/FeaturesPlugin_Revolution.h
src/FeaturesPlugin/FeaturesPlugin_RevolutionCut.h
src/FeaturesPlugin/FeaturesPlugin_RevolutionFuse.h
src/FeaturesPlugin/FeaturesPlugin_Rotation.h
src/FeaturesPlugin/FeaturesPlugin_Scale.h
src/FeaturesPlugin/FeaturesPlugin_Symmetry.h
src/FeaturesPlugin/FeaturesPlugin_Translation.h
src/FeaturesPlugin/FeaturesPlugin_Union.h
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts [new file with mode: 0644]
src/FeaturesPlugin/Test/TestBooleanFuse_CompSolid_Face.py
src/FeaturesPlugin/Test/TestBooleanFuse_ErrorMsg.py
src/FeaturesPlugin/Test/TestBooleanFuse_Face_Face.py
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v0_3.py
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_2.py
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_3.py
src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestMeasurementAngle3Points.py
src/FeaturesPlugin/Test/TestPipe.py
src/FeaturesPlugin/Test/TestRevolutionCut_ThroughAll.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestRevolutionFuse_ThroughAll.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestUnion.py
src/FeaturesPlugin/Test/TestUnion4CurvedFaces.py
src/FeaturesPlugin/Test/TestUnion4CurvedFaces_2.py
src/FeaturesPlugin/Test/TestUnion4Faces.py
src/FeaturesPlugin/Test/TestUnionOfUnion.py
src/FeaturesPlugin/doc/TUI_extrusionCutThroughAll.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/TUI_extrusionFuseThroughAll.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/TUI_revolutionCutThroughAll.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/TUI_revolutionFuseThroughAll.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/extrusion_cut_through_all.py [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/extrusion_fuse_through_all.py [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/revolution_cut_through_all.py [new file with mode: 0644]
src/FeaturesPlugin/doc/examples/revolution_fuse_through_all.py [new file with mode: 0644]
src/FeaturesPlugin/doc/extrusionCutFeature.rst
src/FeaturesPlugin/doc/extrusionFuseFeature.rst
src/FeaturesPlugin/doc/images/ExtrusionCut1.png
src/FeaturesPlugin/doc/images/ExtrusionCut2.png
src/FeaturesPlugin/doc/images/ExtrusionCut3.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/ExtrusionFuse1.png
src/FeaturesPlugin/doc/images/ExtrusionFuse2.png
src/FeaturesPlugin/doc/images/ExtrusionFuse3.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/RevolutionCut1.png
src/FeaturesPlugin/doc/images/RevolutionCut2.png
src/FeaturesPlugin/doc/images/RevolutionCut3.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/RevolutionFuse1.png
src/FeaturesPlugin/doc/images/RevolutionFuse2.png
src/FeaturesPlugin/doc/images/RevolutionFuse3.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/extrusion_cut_through_all_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/extrusion_through_all.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/revolution_cut_through_all_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/revolution_fuse_through_all_result.png [new file with mode: 0644]
src/FeaturesPlugin/doc/images/revolution_through_all.png [new file with mode: 0644]
src/FeaturesPlugin/doc/revolutionCutFeature.rst
src/FeaturesPlugin/doc/revolutionFuseFeature.rst
src/FeaturesPlugin/extrusioncut_widget.xml
src/FeaturesPlugin/extrusionfuse_widget.xml
src/FeaturesPlugin/icons/extrusion_throughall_32x32.png [new file with mode: 0644]
src/FeaturesPlugin/icons/revol_throughall_32x32.png [new file with mode: 0644]
src/FeaturesPlugin/pipe_widget.xml
src/FeaturesPlugin/plugin-Features.xml
src/FeaturesPlugin/revolutioncut_widget.xml
src/FeaturesPlugin/revolutionfuse_widget.xml
src/GeomAPI/GeomAPI_Angle2d.cpp
src/GeomAPI/GeomAPI_Edge.cpp
src/GeomAPI/GeomAPI_Edge.h
src/GeomAPI/GeomAPI_Vertex.cpp
src/GeomAPI/GeomAPI_Vertex.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_UnifySameDomain.cpp
src/GeomData/GeomData_Dir.cpp
src/GeomDataAPI/CMakeLists.txt
src/GeomDataAPI/GeomDataAPI_swig.h
src/GeomValidators/CMakeLists.txt
src/GeomValidators/GeomValidators_BodyShapes.cpp
src/GeomValidators/GeomValidators_GlobalSelection.cpp [new file with mode: 0644]
src/GeomValidators/GeomValidators_GlobalSelection.h [new file with mode: 0644]
src/GeomValidators/GeomValidators_Plugin.cpp
src/GeomValidators/GeomValidators_ZeroOffset.cpp
src/Model/CMakeLists.txt
src/Model/Model_Application.cpp
src/Model/Model_AttributeIntArray.cpp
src/Model/Model_AttributeIntArray.h
src/Model/Model_AttributeReference.cpp
src/Model/Model_AttributeSelection.cpp
src/Model/Model_AttributeSelection.h
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/Model/Model_Document.cpp
src/Model/Model_Document.h
src/Model/Model_Tools.cpp [new file with mode: 0644]
src/Model/Model_Tools.h [new file with mode: 0644]
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI.i
src/ModelAPI/ModelAPI_AttributeIntArray.h
src/ModelAPI/ModelAPI_Document.h
src/ModelAPI/ModelAPI_Events.h
src/ModelAPI/ModelAPI_Tools.cpp
src/ModelAPI/ModelAPI_Tools.h
src/ModelAPI/ModelAPI_swig.h
src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp
src/ModuleBase/CMakeLists.txt
src/ModuleBase/ModuleBase_ChoiceCtrl.cpp
src/ModuleBase/ModuleBase_IModule.cpp
src/ModuleBase/ModuleBase_IModule.h
src/ModuleBase/ModuleBase_IPropertyPanel.cpp
src/ModuleBase/ModuleBase_IPropertyPanel.h
src/ModuleBase/ModuleBase_IWorkshop.h
src/ModuleBase/ModuleBase_ListView.cpp
src/ModuleBase/ModuleBase_ListView.h
src/ModuleBase/ModuleBase_ModelWidget.cpp
src/ModuleBase/ModuleBase_ModelWidget.h
src/ModuleBase/ModuleBase_Operation.cpp
src/ModuleBase/ModuleBase_Operation.h
src/ModuleBase/ModuleBase_OperationAction.cpp [deleted file]
src/ModuleBase/ModuleBase_OperationAction.h [deleted file]
src/ModuleBase/ModuleBase_OperationFeature.cpp
src/ModuleBase/ModuleBase_ResultPrs.cpp
src/ModuleBase/ModuleBase_ResultPrs.h
src/ModuleBase/ModuleBase_ToolBox.cpp
src/ModuleBase/ModuleBase_Tools.cpp
src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp
src/ModuleBase/ModuleBase_WidgetDoubleValue.h
src/ModuleBase/ModuleBase_WidgetFactory.cpp
src/ModuleBase/ModuleBase_WidgetIntValue.cpp
src/ModuleBase/ModuleBase_WidgetIntValue.h
src/ModuleBase/ModuleBase_WidgetLabel.cpp
src/ModuleBase/ModuleBase_WidgetLineEdit.cpp
src/ModuleBase/ModuleBase_WidgetLineEdit.h
src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp
src/ModuleBase/ModuleBase_WidgetMultiSelector.h
src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp
src/ModuleBase/ModuleBase_WidgetSelectionFilter.h
src/ModuleBase/ModuleBase_WidgetShapeSelector.cpp
src/ModuleBase/ModuleBase_WidgetShapeSelector.h
src/ModuleBase/ModuleBase_WidgetUndoLabel.cpp [new file with mode: 0644]
src/ModuleBase/ModuleBase_WidgetUndoLabel.h [new file with mode: 0644]
src/ModuleBase/ModuleBase_WidgetValidated.cpp
src/ModuleBase/ModuleBase_WidgetValidated.h
src/ModuleBase/ModuleBase_msg_fr.ts [new file with mode: 0644]
src/ParametersPlugin/CMakeLists.txt
src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp
src/ParametersPlugin/ParametersPlugin_msg_fr.ts [new file with mode: 0644]
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_CustomPrs.cpp
src/PartSet/PartSet_IconFactory.cpp
src/PartSet/PartSet_MenuMgr.cpp
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_OverconstraintListener.cpp
src/PartSet/PartSet_OverconstraintListener.h
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherMgr.h
src/PartSet/PartSet_Tools.cpp
src/PartSet/PartSet_Tools.h
src/PartSet/PartSet_WidgetFeaturePointSelector.cpp
src/PartSet/PartSet_WidgetFeaturePointSelector.h
src/PartSet/PartSet_WidgetSketchCreator.h
src/PartSet/PartSet_WidgetSketchLabel.cpp
src/PartSet/PartSet_WidgetSketchLabel.h
src/PartSet/PartSet_msg_fr.ts [new file with mode: 0644]
src/PartSetPlugin/CMakeLists.txt
src/PartSetPlugin/PartSetPlugin_msg_fr.ts [new file with mode: 0644]
src/PrimitivesPlugin/CMakeLists.txt
src/PrimitivesPlugin/PrimitivesPlugin_msg_fr.ts [new file with mode: 0644]
src/PythonAPI/model/exchange/__init__.py
src/PythonAPI/model/exchange/tools.py [new file with mode: 0644]
src/SHAPERGUI/CMakeLists.txt
src/SHAPERGUI/SHAPERGUI.cpp
src/SHAPERGUI/SHAPERGUI.h
src/SHAPERGUI/SHAPERGUI_msg_fr.ts [new file with mode: 0644]
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp
src/SketchPlugin/SketchPlugin_ConstraintAngle.h
src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp
src/SketchPlugin/SketchPlugin_ConstraintDistance.h
src/SketchPlugin/SketchPlugin_ConstraintDistanceAlongDir.cpp
src/SketchPlugin/SketchPlugin_ConstraintLength.cpp
src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp
src/SketchPlugin/SketchPlugin_Fillet.cpp
src/SketchPlugin/SketchPlugin_Line.cpp
src/SketchPlugin/SketchPlugin_Line.h
src/SketchPlugin/SketchPlugin_MacroArc.cpp
src/SketchPlugin/SketchPlugin_MacroCircle.cpp
src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Projection.cpp
src/SketchPlugin/SketchPlugin_Sketch.cpp
src/SketchPlugin/SketchPlugin_Sketch.h
src/SketchPlugin/SketchPlugin_SketchEntity.h
src/SketchPlugin/SketchPlugin_Tools.cpp
src/SketchPlugin/SketchPlugin_Tools.h
src/SketchPlugin/SketchPlugin_msg_fr.ts [new file with mode: 0644]
src/SketchPlugin/Test/Test3087_1.py [new file with mode: 0644]
src/SketchPlugin/Test/Test3087_2.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintDistanceBehavior.py
src/SketchPlugin/Test/TestConstraintDistanceHorizontal.py
src/SketchPlugin/Test/TestConstraintDistanceHorizontalZero.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintDistanceVertical.py
src/SketchPlugin/Test/TestConstraintDistanceVerticalZero.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintDistanceZero.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintTangentEllipticArc.py
src/SketchPlugin/Test/TestMoveEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestPresentation.py
src/SketchPlugin/Test/TestRemainingDoF.py [new file with mode: 0644]
src/SketchPlugin/doc/SketchPlugin.rst
src/SketchPlugin/doc/images/Overconstrained.png [new file with mode: 0644]
src/SketchPlugin/doc/images/SketchPanel.png
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h
src/SketchSolver/SketchSolver_ConstraintDistance.cpp
src/SketchSolver/SketchSolver_Error.h
src/SketchSolver/SketchSolver_Group.cpp
src/SketchSolver/SketchSolver_Group.h
src/SketchSolver/SketchSolver_Manager.cpp
src/SketchSolver/SketchSolver_Manager.h
src/SketchSolver/SketchSolver_Storage.h
src/SketchSolver/SketchSolver_msg_fr.ts [new file with mode: 0644]
src/SketcherPrs/SketcherPrs_Angle.cpp
src/SketcherPrs/SketcherPrs_LengthDimension.cpp
src/SketcherPrs/SketcherPrs_SymbolPrs.cpp
src/SketcherPrs/SketcherPrs_Tools.cpp
src/XGUI/CMakeLists.txt
src/XGUI/XGUI_ContextMenuMgr.cpp
src/XGUI/XGUI_CustomPrs.cpp [deleted file]
src/XGUI/XGUI_CustomPrs.h [deleted file]
src/XGUI/XGUI_Displayer.cpp
src/XGUI/XGUI_Displayer.h
src/XGUI/XGUI_FacesPanel.cpp
src/XGUI/XGUI_FacesPanel.h
src/XGUI/XGUI_InspectionPanel.cpp
src/XGUI/XGUI_InspectionPanel.h
src/XGUI/XGUI_ModuleConnector.cpp
src/XGUI/XGUI_ModuleConnector.h
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_SelectionMgr.cpp
src/XGUI/XGUI_SelectionMgr.h
src/XGUI/XGUI_Tools.cpp
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_Workshop.h
src/XGUI/XGUI_WorkshopListener.cpp
src/XGUI/XGUI_WorkshopListener.h
src/XGUI/XGUI_msg_fr.ts [new file with mode: 0644]
src/XGUI/XGUI_pictures.qrc
src/XGUI/pictures/move_to_end.png [new file with mode: 0644]
src/XGUI/pictures/move_to_end_split.png [new file with mode: 0644]
test.hdfs/roselend.py
test.sh

index ce95b287b2a0e3214fad9e1c7b7abff3d34b31c3..c63a22307b8a5cfe57f62eec4202265d439c847a 100644 (file)
@@ -120,7 +120,9 @@ ENDIF(${HAVE_SALOME})
 # Sketcher: Change radius of circular edges while dragging a point on the edge
 SET(SKETCHER_CHANGE_RADIUS_WHEN_MOVE TRUE)
 
+SET(MAKE_TRANSLATION YES)
 
+    ADD_DEFINITIONS( -DMAKE_TRANSLATION )
 ADD_SUBDIRECTORY (src/Config)
 ADD_SUBDIRECTORY (src/Events)
 ADD_SUBDIRECTORY (src/Selector)
index 2a8d9015c1f987455b3d7d03ef0021360d50f5c9..c35c806f64609bfa65a0e587bdb6d1e64a8e1fd1 100644 (file)
@@ -241,7 +241,7 @@ Each feature, result, construction, group, field, parameter can be renamed using
 .. centered::\r
    Construction pop-up menu\r
 \r
-The order of features can be changed using *Move to the end* pop-up menu command. It works only for Group features. The selected group will be moved to the end of features list.\r
+The order of features can be changed using *Move to the end* and *Move to the end and split* pop-up menu commands. They work only for Group features. The selected group or several groups will be moved to the end of features list. The *Move to the end and split* also splits the resulting group in several groups: one group per one selection.\r
 \r
 Folders can be used to arrange long Tree View for features.\r
 \r
@@ -491,6 +491,7 @@ This tab defines presentation of objects displayed in OCC 3D viewer.
 \r
 **Input fields**:\r
 \r
+- **Selection color** defines a color for selected objects;\r
 - **Result color** selects default shading color for objects from **Results** branch;\r
 - **Group color** selects default color for objects from **Groups** branch;\r
 - **Construction color** selects default color for objects from **Constructions** branch;\r
@@ -558,6 +559,32 @@ Plugins tab defines folders where plugins and resources are located.
    \r
 .. _sketch_preferences:\r
    \r
+Shortcuts tab\r
+^^^^^^^^^^^^^\r
+\r
+Shortcuts tab defines shortcut keys for different operations.\r
+\r
+.. image:: images/shortcuts_preferences.png\r
+   :align: center\r
+\r
+.. centered::\r
+   Preferences - Shortcuts tab\r
+   \r
+- **Add parameter in parameters manager dialog** defines shortcut keys for adding parameter in parameters manager dialog box.\r
+   \r
+Windows tab\r
+^^^^^^^^^^^\r
+\r
+Windows tab contains definitions for the module windows management.\r
+\r
+.. image:: images/windows_preferences.png\r
+   :align: center\r
+\r
+.. centered::\r
+   Preferences - Windows tab\r
+\r
+- **Use HideFaces panel in operation** if the checkbox is checked then HideFaces panel will be launched automatically on launching an operation where using of this panel is considered.\r
+\r
 Sketch tab\r
 ^^^^^^^^^^\r
 \r
@@ -574,6 +601,7 @@ Sketch tab defines properties of coordinate planes shown for selection of sketch
 - **Size** defines size of coordinate planes;\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
 \r
    \r
 .. _viewer_preferences:\r
index f82715e7aaeb2dfa16db156b7a60a778fd3cedfa..cb0d5e7b03a0d933bd2e09f827bda4f23664bc92 100755 (executable)
Binary files a/doc/gui/images/plugins_preferences.png and b/doc/gui/images/plugins_preferences.png differ
index 30e40564de322526f602705c080f79103c65dbd7..ed32e2f4cfcf22a0645cfd4f37baf54fee8ec086 100755 (executable)
Binary files a/doc/gui/images/popup_menu_object_browser_feature.png and b/doc/gui/images/popup_menu_object_browser_feature.png differ
diff --git a/doc/gui/images/shortcuts_preferences.png b/doc/gui/images/shortcuts_preferences.png
new file mode 100644 (file)
index 0000000..a33dfa0
Binary files /dev/null and b/doc/gui/images/shortcuts_preferences.png differ
index ae6ceb0ff44d1b71fed2a69ae2833e2f4cf0d3bb..ce3b32ff2ff899e4128193a992f9a261561e1412 100755 (executable)
Binary files a/doc/gui/images/sketch_preferences.png and b/doc/gui/images/sketch_preferences.png differ
index 3a368852bbf397f270d65ab4c3f631aa4eabfceb..1cacff225f04e6139aab156cb7c3014feb3d7501 100755 (executable)
Binary files a/doc/gui/images/viewer_preferences.png and b/doc/gui/images/viewer_preferences.png differ
index 25cb63c6402a598d3919dd9ee1d4153c30e90eb9..6a1b50983008c62b27def8079e615cf49c2e9738 100755 (executable)
Binary files a/doc/gui/images/visualization_preferences.png and b/doc/gui/images/visualization_preferences.png differ
diff --git a/doc/gui/images/windows_preferences.png b/doc/gui/images/windows_preferences.png
new file mode 100644 (file)
index 0000000..8d4e1f9
Binary files /dev/null and b/doc/gui/images/windows_preferences.png differ
index d6cf38269b8046626dac346450c1e0ec19024966..5dbe200badf9cb7222a9a2038d16023e3f790d04 100644 (file)
@@ -24,6 +24,8 @@ export PATH=${CPPLINT_ROOT_DIR}:${PATH}
 ##
 
 #------ SHAPER ------
-export PATH=${SHAPER_ROOT_DIR}/bin/salome:${PATH}
-export PYTHONPATH=${SHAPER_ROOT_DIR}/bin/salome:${SHAPER_ROOT_DIR}/lib/python3.6/site-packages/salome:${PYTHONPATH}
+export SHAPER_BIN_DIR=${SHAPER_ROOT_DIR}/bin/salome
+export SHAPER_PYTHON_SCRIPTS_DIR=${SHAPER_ROOT_DIR}/lib/python3.6/site-packages/salome
+export PATH=${SHAPER_BIN_DIR}:${PATH}
+export PYTHONPATH=${SHAPER_BIN_DIR}:${SHAPER_PYTHON_SCRIPTS_DIR}:${PYTHONPATH}
 export LD_LIBRARY_PATH=${SHAPER_ROOT_DIR}/lib/salome:${LD_LIBRARY_PATH}
index 3371f01eaf109912c91fd67a226bd60af4a7191d..e0816f8331c741a1caec81a995f4add6bffe6f89 100644 (file)
@@ -31,11 +31,13 @@ BuildAPI_Edge::BuildAPI_Edge(const std::shared_ptr<ModelAPI_Feature>& theFeature
 
 //==================================================================================================
 BuildAPI_Edge::BuildAPI_Edge(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                             const std::list<ModelHighAPI_Selection>& theBaseObjects)
+                             const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                             const bool theComputeIntersections)
 : ModelHighAPI_Interface(theFeature)
 {
   if(initialize()) {
     fillAttribute(BuildPlugin_Edge::CREATION_BY_SEGMENTS(), mycreationMethod);
+    fillAttribute(theComputeIntersections, mycomputeIntersections);
     setBase(theBaseObjects);
   }
 }
@@ -83,17 +85,23 @@ void BuildAPI_Edge::dump(ModelHighAPI_Dumper& theDumper) const
     theDumper << aBase->selection(BuildPlugin_Edge::FIRST_POINT()) << ", "
               << aBase->selection(BuildPlugin_Edge::SECOND_POINT());
   }
-  else
+  else {
     theDumper << aBase->selectionList(BuildPlugin_Edge::BASE_OBJECTS_ID());
+
+    AttributeBooleanPtr isIntersect = aBase->boolean(BuildPlugin_Edge::INTERSECT_ID());
+    if (isIntersect->isInitialized())
+      theDumper << ", " << isIntersect;
+  }
   theDumper << ")" << std::endl;
 }
 
 //==================================================================================================
 EdgePtr addEdge(const std::shared_ptr<ModelAPI_Document>& thePart,
-                const std::list<ModelHighAPI_Selection>& theBaseObjects)
+                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                const bool theComputeIntersections)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(BuildAPI_Edge::ID());
-  return EdgePtr(new BuildAPI_Edge(aFeature, theBaseObjects));
+  return EdgePtr(new BuildAPI_Edge(aFeature, theBaseObjects, theComputeIntersections));
 }
 
 EdgePtr addEdge(const std::shared_ptr<ModelAPI_Document>& thePart,
index 11a7fa90210d6a424a649fa964899287c22a325e..e6a7e46d760cd398f57fed8be3c9f4457194c93d 100644 (file)
@@ -42,7 +42,8 @@ public:
   /// Constructor with values.
   BUILDAPI_EXPORT
   explicit BuildAPI_Edge(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                         const std::list<ModelHighAPI_Selection>& theBaseObjects);
+                         const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                         const bool theComputeIntersections = false);
 
   /// Constructor by points.
   BUILDAPI_EXPORT
@@ -54,7 +55,7 @@ public:
   BUILDAPI_EXPORT
   virtual ~BuildAPI_Edge();
 
-  INTERFACE_4(BuildPlugin_Edge::ID(),
+  INTERFACE_5(BuildPlugin_Edge::ID(),
               baseObjects, BuildPlugin_Edge::BASE_OBJECTS_ID(),
               ModelAPI_AttributeSelectionList, /** Base objects */,
               creationMethod, BuildPlugin_Edge::CREATION_METHOD(),
@@ -62,7 +63,9 @@ public:
               firstPoint, BuildPlugin_Edge::FIRST_POINT(),
               ModelAPI_AttributeSelection, /** First point */,
               secondPoint, BuildPlugin_Edge::SECOND_POINT(),
-              ModelAPI_AttributeSelection, /** Second point */)
+              ModelAPI_AttributeSelection, /** Second point */,
+              computeIntersections, BuildPlugin_Edge::INTERSECT_ID(),
+              ModelAPI_AttributeBoolean, /** Intersect edges */)
 
   /// Modify base attribute of the feature.
   BUILDAPI_EXPORT
@@ -80,7 +83,8 @@ typedef std::shared_ptr<BuildAPI_Edge> EdgePtr;
 /// \brief Create Edge feature.
 BUILDAPI_EXPORT
 EdgePtr addEdge(const std::shared_ptr<ModelAPI_Document>& thePart,
-                const std::list<ModelHighAPI_Selection>& theBaseObjects);
+                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                const bool theComputeIntersection = false);
 /// \ingroup CPPHighAPI
 /// \brief Create Edge feature.
 BUILDAPI_EXPORT
index 327a2d2905d2b856c9dd346db41f294612eb17e0..f94b230f18cf841a6f2161690c27852faae9d2f5 100644 (file)
@@ -35,6 +35,19 @@ BuildAPI_Vertex::BuildAPI_Vertex(const std::shared_ptr<ModelAPI_Feature>& theFea
 : ModelHighAPI_Interface(theFeature)
 {
   if(initialize()) {
+    fillAttribute(false, mydoIntersect);
+    setBase(theBaseObjects);
+  }
+}
+
+//==================================================================================================
+BuildAPI_Vertex::BuildAPI_Vertex(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                 const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                 const bool theDoIntersect)
+: ModelHighAPI_Interface(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theDoIntersect, mydoIntersect);
     setBase(theBaseObjects);
   }
 }
@@ -61,6 +74,15 @@ VertexPtr addVertex(const std::shared_ptr<ModelAPI_Document>& thePart,
   return VertexPtr(new BuildAPI_Vertex(aFeature, theBaseObjects));
 }
 
+//==================================================================================================
+VertexPtr addVertex(const std::shared_ptr<ModelAPI_Document>& thePart,
+                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                    const bool theDoIntersect)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(BuildAPI_Vertex::ID());
+  return VertexPtr(new BuildAPI_Vertex(aFeature, theBaseObjects, theDoIntersect));
+}
+
 //==================================================================================================
 void BuildAPI_Vertex::dump(ModelHighAPI_Dumper& theDumper) const
 {
@@ -68,5 +90,6 @@ void BuildAPI_Vertex::dump(ModelHighAPI_Dumper& theDumper) const
   std::string aPartName = theDumper.name(aBase->document());
 
   theDumper << aBase << " = model.addVertex(" << aPartName << ", "
-            << aBase->selectionList(BuildPlugin_Vertex::BASE_OBJECTS_ID()) << ")" << std::endl;
+            << aBase->selectionList(BuildPlugin_Vertex::BASE_OBJECTS_ID()) << ", "
+            << aBase->boolean(BuildPlugin_Vertex::INTERSECT_ID()) << ")" << std::endl;
 }
index 6a96640a488d964b798e75a09b581abe1f85bb23..77ba77e957db28fb06ba7797a56e69737d51fbff 100644 (file)
@@ -44,13 +44,21 @@ public:
   explicit BuildAPI_Vertex(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                            const std::list<ModelHighAPI_Selection>& theBaseObjects);
 
+  /// Constructor with values.
+  BUILDAPI_EXPORT
+  explicit BuildAPI_Vertex(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                           const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                           const bool theDoIntersect);
+
   /// Destructor.
   BUILDAPI_EXPORT
   virtual ~BuildAPI_Vertex();
 
-  INTERFACE_1(BuildPlugin_Vertex::ID(),
+  INTERFACE_2(BuildPlugin_Vertex::ID(),
               baseObjects, BuildPlugin_Vertex::BASE_OBJECTS_ID(),
-              ModelAPI_AttributeSelectionList, /** Base objects */)
+              ModelAPI_AttributeSelectionList, /** Base objects */,
+              doIntersect, BuildPlugin_Vertex::INTERSECT_ID(),
+              ModelAPI_AttributeBoolean, /** Compute intersections */)
 
   /// Modify base attribute of the feature.
   BUILDAPI_EXPORT
@@ -70,4 +78,11 @@ BUILDAPI_EXPORT
 VertexPtr addVertex(const std::shared_ptr<ModelAPI_Document>& thePart,
                     const std::list<ModelHighAPI_Selection>& theBaseObjects);
 
+/// \ingroup CPPHighAPI
+/// \brief Create Vertex feature.
+BUILDAPI_EXPORT
+VertexPtr addVertex(const std::shared_ptr<ModelAPI_Document>& thePart,
+                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                    const bool theDoIntersect);
+
 #endif // BuildAPI_Vertex_H_
index 69c68be456a41276cedec0da4e09edd495713355..ffd58d48af7f160d6c63e3223ce3110078fec084 100644 (file)
@@ -31,10 +31,12 @@ BuildAPI_Wire::BuildAPI_Wire(const std::shared_ptr<ModelAPI_Feature>& theFeature
 
 //==================================================================================================
 BuildAPI_Wire::BuildAPI_Wire(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                             const std::list<ModelHighAPI_Selection>& theBaseObjects)
+                             const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                             const bool theComputeIntersections)
 : ModelHighAPI_Interface(theFeature)
 {
   if(initialize()) {
+    fillAttribute(theComputeIntersections, mycomputeIntersections);
     setBase(theBaseObjects);
   }
 }
@@ -60,7 +62,13 @@ void BuildAPI_Wire::dump(ModelHighAPI_Dumper& theDumper) const
   std::string aPartName = theDumper.name(aBase->document());
 
   theDumper << aBase << " = model.addWire(" << aPartName << ", "
-            << aBase->selectionList(BuildPlugin_Wire::BASE_OBJECTS_ID()) << ")" << std::endl;
+            << aBase->selectionList(BuildPlugin_Wire::BASE_OBJECTS_ID());
+
+  AttributeBooleanPtr isIntersect = aBase->boolean(BuildPlugin_Wire::INTERSECT_ID());
+  if (isIntersect->isInitialized())
+    theDumper << ", " << isIntersect;
+
+  theDumper << ")" << std::endl;
 }
 
 //==================================================================================================
@@ -71,8 +79,9 @@ void BuildAPI_Wire::addContour()
 
 //==================================================================================================
 WirePtr addWire(const std::shared_ptr<ModelAPI_Document>& thePart,
-                const std::list<ModelHighAPI_Selection>& theBaseObjects)
+                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                const bool theComputeIntersections)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(BuildAPI_Wire::ID());
-  return WirePtr(new BuildAPI_Wire(aFeature, theBaseObjects));
+  return WirePtr(new BuildAPI_Wire(aFeature, theBaseObjects, theComputeIntersections));
 }
index 4934943d7b3c8abab6fd0b8a6c370598e02938ab..86e78837b4015dc7ce8d50b45b579cd729c704d2 100644 (file)
@@ -42,15 +42,18 @@ public:
   /// Constructor with values.
   BUILDAPI_EXPORT
   explicit BuildAPI_Wire(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                         const std::list<ModelHighAPI_Selection>& theBaseObjects);
+                         const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                         const bool theComputeIntersections = false);
 
   /// Destructor.
   BUILDAPI_EXPORT
   virtual ~BuildAPI_Wire();
 
-  INTERFACE_1(BuildPlugin_Wire::ID(),
+  INTERFACE_2(BuildPlugin_Wire::ID(),
               baseObjects, BuildPlugin_Wire::BASE_OBJECTS_ID(),
-              ModelAPI_AttributeSelectionList, /** Base objects */)
+              ModelAPI_AttributeSelectionList, /** Base objects */,
+              computeIntersections, BuildPlugin_Wire::INTERSECT_ID(),
+              ModelAPI_AttributeBoolean, /** Intersect edges */)
 
   /// Modify base attribute of the feature.
   BUILDAPI_EXPORT
@@ -72,6 +75,7 @@ typedef std::shared_ptr<BuildAPI_Wire> WirePtr;
 /// \brief Create Wire feature.
 BUILDAPI_EXPORT
 WirePtr addWire(const std::shared_ptr<ModelAPI_Document>& thePart,
-                const std::list<ModelHighAPI_Selection>& theBaseObjects);
+                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                const bool theComputeIntersections = false);
 
 #endif // BuildAPI_Wire_H_
index 0f85ae3e443842129b491d6e11ee39ea6ccaa76e..2a07d390c2088ce7b1c922f82b50954c29fd0275 100644 (file)
 
 #include "BuildPlugin_Edge.h"
 
+#include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 
+#include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_Copy.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_Partition.h>
 #include <GeomAlgoAPI_Tools.h>
 
 #include <GeomAPI_Edge.h>
@@ -64,6 +68,9 @@ void BuildPlugin_Edge::initAttributes()
 
   data()->addAttribute(FIRST_POINT(), ModelAPI_AttributeSelection::typeId());
   data()->addAttribute(SECOND_POINT(), ModelAPI_AttributeSelection::typeId());
+
+  data()->addAttribute(INTERSECT_ID(), ModelAPI_AttributeBoolean::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INTERSECT_ID());
 }
 
 //=================================================================================================
@@ -96,7 +103,6 @@ void BuildPlugin_Edge::edgesBySegments()
   // Collect base shapes.
   ListOfShape aListOfShapes;
   std::string aError;
-  int aResultIndex = 0;
   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
     GeomShapePtr aShape;
@@ -108,29 +114,48 @@ void BuildPlugin_Edge::edgesBySegments()
       setError("Error: Empty shape selected.");
       return;
     }
+    aListOfShapes.push_back(aShape);
+  }
 
-    if(aShape->shapeType() != GeomAPI_Shape::EDGE) {
-      setError("Error: Selected shape has wrong type. Only edges acceptable.");
-      return;
-    }
+  AttributeBooleanPtr isIntersect = boolean(INTERSECT_ID());
 
-    // Copy shape.
-    GeomMakeShapePtr aCopyAlgo(new GeomAlgoAPI_Copy(aShape));
+  GeomShapePtr aResult;
+  std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo;
+  if (isIntersect->isInitialized() && isIntersect->value()) {
+    aPartitionAlgo.reset(new GeomAlgoAPI_Partition(aListOfShapes, ListOfShape()));
 
     std::string anError;
-    if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCopyAlgo, getKind(), anError)) {
+    if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), anError)) {
       setError(anError);
       return;
     }
 
-    // Store result.
-    ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
+    aResult = aPartitionAlgo->shape();
+  }
+  else
+    aResult = GeomAlgoAPI_CompoundBuilder::compound(aListOfShapes);
+
+  int aResultIndex = 0;
+
+  // Explode on edges
+  std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aProcessed;
+  for (GeomAPI_ShapeExplorer anExp(aResult, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
+    GeomShapePtr anEdge = anExp.current();
+    if (aProcessed.find(anEdge) != aProcessed.end())
+      continue; // vertex is already processed
+    aProcessed.insert(anEdge);
 
-    ListOfShape aBaseShapes;
-    aBaseShapes.push_back(aShape);
-    aResultBody->storeModified(aBaseShapes, aCopyAlgo->shape(), aCopyAlgo);
-    aResultBody->loadModifiedShapes(aCopyAlgo, aShape, GeomAPI_Shape::VERTEX);
+    std::shared_ptr<GeomAlgoAPI_Copy> aCopyAlgo(new GeomAlgoAPI_Copy(anEdge));
 
+    std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList);
+    if (aPartitionAlgo)
+      aMakeShapeList->appendAlgo(aPartitionAlgo);
+    aMakeShapeList->appendAlgo(aCopyAlgo);
+
+    // Store result.
+    ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
+    aResultBody->storeModified(aListOfShapes, aCopyAlgo->shape(), aMakeShapeList);
+    aResultBody->loadModifiedShapes(aMakeShapeList, anEdge, GeomAPI_Shape::VERTEX);
     setResult(aResultBody, aResultIndex);
     ++aResultIndex;
   }
index 27f1665ba0eb3f0da9ff5510a13cfc5f3725b20f..af142f55b02ad9f95261259ea14a20dc699a8273 100644 (file)
@@ -89,6 +89,13 @@ public:
     return MY_SECOND_POINT_ID;
   }
 
+  /// Attribute name of "Compute intersections" checkbox.
+  inline static const std::string& INTERSECT_ID()
+  {
+    static const std::string MY_INTERSECT_ID("intersect");
+    return MY_INTERSECT_ID;
+  }
+
   /// Request for initialization of data model of the feature: adding all attributes.
   BUILDPLUGIN_EXPORT virtual void initAttributes();
 
index 022865abdd3682773a3b4a0a1cee2e70858ea434..ac88ffe6aaa6837d8d67440fd060a658fdc5456b 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultConstruction.h>
 
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_PlanarEdges.h>
@@ -71,11 +72,21 @@ void BuildPlugin_Face::execute()
     if(!aShape.get()) {
       aShape = aContext;
     }
-    // keep selected faces "as is"
     if (aShape->shapeType() == GeomAPI_Shape::FACE) {
+      // keep selected faces "as is"
       anOriginalFaces.push_back(aShape);
       continue;
     }
+    else if (!aSelection->value() && aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
+      // collect faces from the sketch
+      ResultConstructionPtr aSketch =
+          std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelection->context());
+      if (aSketch && aSketch->facesNum() > 0) {
+        for (int i = 0; i < aSketch->facesNum(); ++i)
+          anOriginalFaces.push_back(aSketch->face(i));
+        continue;
+      }
+    }
 
     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
       GeomShapePtr anEdge = anExp.current();
index 5d37e3299e8602c5efddd19b4c8561d6b14de795..4c20e54ddcc2f84b1dcbdb071414530c62f66130 100644 (file)
@@ -57,6 +57,8 @@ BuildPlugin_Plugin::BuildPlugin_Plugin()
                               new BuildPlugin_ValidatorSubShapesSelection());
   aFactory->registerValidator("BuildPlugin_ValidatorFillingSelection",
                               new BuildPlugin_ValidatorFillingSelection());
+  aFactory->registerValidator("BuildPlugin_ValidatorBaseForVertex",
+                              new BuildPlugin_ValidatorBaseForVertex());
 
   // Register this plugin.
   ModelAPI_Session::get()->registerPlugin(this);
index 7f1010307502ee73fa57b18556aa824de3880354..293a63818a99cd339898a292ce2f9a790dab97d8 100644 (file)
@@ -48,6 +48,18 @@ void BuildPlugin_Shell::execute()
   ListOfShape aShapes, aContexts;
   getOriginalShapesAndContexts(BASE_OBJECTS_ID(), aShapes, aContexts);
 
+  // Collect sketch faces.
+  for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
+    GeomShapePtr aShape = aSelection->value();
+    ResultConstructionPtr aContext =
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelection->context());
+    if (!aShape && aContext) {
+      for (int i = 0; i < aContext->facesNum(); ++i)
+        aShapes.push_back(aContext->face(i));
+    }
+  }
+
   // Sew faces.
   GeomMakeShapePtr aSewingAlgo(new GeomAlgoAPI_Sewing(aShapes));
 
index 65be3411933356f25d4724b941c2659b693436a4..aef6b7fc8828430feb890998dc6e01a765c6b10d 100644 (file)
@@ -39,6 +39,8 @@
 #include <GeomValidators_FeatureKind.h>
 #include <GeomValidators_ShapeType.h>
 
+#include <SketchPlugin_Sketch.h>
+
 #include <Events_InfoMessage.h>
 
 //=================================================================================================
@@ -102,17 +104,6 @@ bool BuildPlugin_ValidatorBaseForBuild::isValid(const AttributePtr& theAttribute
         theError = "Infinite objects not acceptable.";
         return false;
       }
-
-      std::shared_ptr<GeomAPI_PlanarEdges> anEdges =
-        std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aContextShape);
-      if(anEdges.get()) {
-        if(aShape->isEqual(aContextShape)) {
-          // It is whole sketch.
-          return false;
-        }
-
-        continue;
-      }
     }
   }
 
@@ -125,12 +116,6 @@ bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptr<ModelAPI_Fe
                                                Events_InfoMessage& theError) const
 {
   // Get attribute.
-  if(theArguments.size() != 1) {
-    std::string aMsg = "Error: BuildPlugin_ValidatorBaseForWire should be used only "
-                       "with 1 parameter (ID of base objects list).";
-    Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
-    return false;
-  }
   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
   if(!aSelectionList.get()) {
     theError = "Empty attribute \"%1\".";
@@ -138,25 +123,53 @@ bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptr<ModelAPI_Fe
     return false;
   }
 
+  GeomAPI_Shape::ShapeType aShapeType = GeomAPI_Shape::shapeTypeByStr(theArguments.back());
 
   // Collect base shapes.
   ListOfShape aListOfShapes;
   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
     GeomShapePtr aShape = aSelection->value();
-    if(!aShape.get()) {
-      if (aSelection->context().get())
-        aShape = aSelection->context()->shape();
-    }
-    if (aShape.get())
+    ResultPtr aContext = aSelection->context();
+    if (!aShape.get() && aContext.get())
+      aShape = aContext->shape();
+
+    bool isProper = aShape.get() &&
+        (aShape->shapeType() == GeomAPI_Shape::EDGE || aShape->shapeType() == aShapeType);
+
+    if (isProper)
       aListOfShapes.push_back(aShape);
+    else {
+      // is it a sketch?
+      FeaturePtr aFeature = aSelection->contextFeature();
+      if (!aFeature.get()) {
+        GeomShapePtr aValue = aSelection->value();
+        // whole sketch is allowed only
+        if (aContext.get() && !aValue.get()) {
+          aFeature = ModelAPI_Feature::feature(aContext);
+        }
+      }
+
+      if (!aFeature.get()) {
+        theError = "Error: Incorrect selection.";
+        return false;
+      }
+
+      if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
+        theError = "Error: %1 shape is not allowed for selection.";
+        theError.arg(aFeature->getKind());
+        return false;
+      }
+    }
   }
 
-  // Create wire.
-  GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
-  if(!aWire.get()) {
-    theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
-    return false;
+  if (aShapeType == GeomAPI_Shape::WIRE) {
+    // Create wire.
+    GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
+    if (!aWire.get() && !aListOfShapes.empty()) {
+      theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
+      return false;
+    }
   }
 
   return true;
@@ -196,7 +209,11 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Fe
       }
       aShape = aSelection->context()->shape();
     }
-    if (aShape->shapeType() == GeomAPI_Shape::FACE) {
+    ResultConstructionPtr aSketchRes =
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelection->context());
+
+    if (aShape->shapeType() == GeomAPI_Shape::FACE ||
+        (!aSelection->value() && aSketchRes && aSketchRes->facesNum() > 0)) {
       // skip faces exploding
       hasFaces = true;
       continue;
@@ -464,7 +481,7 @@ bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttri
     return false;
   }
 
-  FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+  //FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
 
   // Check selected shapes.
   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
@@ -491,3 +508,64 @@ bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttri
 
   return true;
 }
+
+
+//=================================================================================================
+bool BuildPlugin_ValidatorBaseForVertex::isValid(const AttributePtr& theAttribute,
+                                                 const std::list<std::string>& /*theArguments*/,
+                                                 Events_InfoMessage& theError) const
+{
+  if (!theAttribute.get()) {
+    theError = "Error: empty selection.";
+    return false;
+  }
+
+  AttributeSelectionListPtr aSelectionList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!aSelectionList.get()) {
+    theError = "Could not get selection list.";
+    return false;
+  }
+
+  for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr aSelectionAttr = aSelectionList->value(anIndex);
+    if (!aSelectionAttr.get()) {
+      theError = "Empty attribute in list.";
+      return false;
+    }
+
+    // Vertex?
+    bool isVertex = false;
+    GeomShapePtr aShape = aSelectionAttr->value();
+    ResultPtr aContext = aSelectionAttr->context();
+    if (!aShape.get() && aContext.get())
+      aShape = aContext->shape();
+    if (aShape.get())
+      isVertex = (aShape->shapeType() == GeomAPI_Shape::VERTEX);
+
+    if (!isVertex) {
+      // Sketch?
+      FeaturePtr aFeature = aSelectionAttr->contextFeature();
+      if (!aFeature.get()) {
+        GeomShapePtr aValue = aSelectionAttr->value();
+        // whole sketch is allowed only
+        if (aContext.get() && !aValue.get()) {
+          aFeature = ModelAPI_Feature::feature(aContext);
+        }
+      }
+
+      if (!aFeature.get()) {
+        theError = "Error: Incorrect selection.";
+        return false;
+      }
+
+      if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
+        theError = "Error: %1 shape is not allowed for selection.";
+        theError.arg(aFeature->getKind());
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
index 4c54b6b7b8ef5b2c7d1ab3d65b91032f8298465f..116d44afcfefc596cde350b124f9998c093a11d5 100644 (file)
@@ -118,4 +118,19 @@ public:
                         Events_InfoMessage& theError) const;
 };
 
+/// \class BuildPlugin_ValidatorBaseForVertex
+/// \ingroup Validators
+/// \brief A validator for selection of Vertex feature.
+class BuildPlugin_ValidatorBaseForVertex: public ModelAPI_AttributeValidator
+{
+public:
+  //! Returns true if attribute is ok.
+  //! \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
index 82f3521ed81ac72dd66859b97c9a7e5a19e83bef..caed091a2666136d012d500bbc9f9c6f2f383415 100644 (file)
 #include "BuildPlugin_Vertex.h"
 
 #include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_ResultBody.h>
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Session.h>
 
+#include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_Copy.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
 #include <GeomAlgoAPI_Tools.h>
+#include <GeomAlgoAPI_Partition.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <GeomAPI_ShapeExplorer.h>
 
 //=================================================================================================
 BuildPlugin_Vertex::BuildPlugin_Vertex()
@@ -34,62 +44,120 @@ BuildPlugin_Vertex::BuildPlugin_Vertex()
 void BuildPlugin_Vertex::initAttributes()
 {
   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
+
+  data()->addAttribute(INTERSECT_ID(), ModelAPI_AttributeBoolean::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INTERSECT_ID());
 }
 
-//=================================================================================================
-void BuildPlugin_Vertex::execute()
+void BuildPlugin_Vertex::buildVertices(const ListOfShape& theShapes, bool isIntersect)
 {
-  // Get base objects list.
-  AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID());
-  if(!aSelectionList.get()) {
-    setError("Error: Could not get selection list.");
-    return;
-  }
-  if(aSelectionList->size() == 0) {
-    setError("Error: Empty selection list.");
-    return;
-  }
+  GeomShapePtr aResult;
+  std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo;
+  if (isIntersect) {
+    aPartitionAlgo.reset(new GeomAlgoAPI_Partition(theShapes, ListOfShape()));
 
-  // Collect base shapes.
-  ListOfShape aListOfShapes;
-  int aResultIndex = 0;
-  for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
-    AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
-    GeomShapePtr aShape = aSelection->value();
-    if(!aShape.get()) {
-      ResultPtr aContext = aSelection->context();
-      if(!aContext.get()) {
-        setError("Error: Attribute has empty context.");
-        return;
-      }
-
-      aShape = aContext->shape();
-    }
-    if(!aShape.get()) {
-      setError("Error: Empty shape selected.");
+    std::string anError;
+    if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), anError)) {
+      setError(anError);
       return;
     }
 
-    if(aShape->shapeType() != GeomAPI_Shape::VERTEX) {
-      setError("Error: Selected shape has wrong type. Only vertices acceptable.");
-      return;
-    }
+    aResult = aPartitionAlgo->shape();
+  }
+  else
+    aResult = GeomAlgoAPI_CompoundBuilder::compound(theShapes);
 
-    // Copy shape.
-    std::shared_ptr<GeomAlgoAPI_Copy> aCopyAlgo(new GeomAlgoAPI_Copy(aShape));
+  int aResultIndex = 0;
 
-    std::string anError;
-    if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCopyAlgo, getKind(), anError)) {
-      setError(anError);
-      return;
-    }
+  // Explode on vertices
+  std::set<GeomVertexPtr, GeomAPI_Vertex::GeometricComparator> aProcessed;
+  for (GeomAPI_ShapeExplorer anExp(aResult, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) {
+    GeomVertexPtr aVertex(new GeomAPI_Vertex(anExp.current()));
+    if (aProcessed.find(aVertex) != aProcessed.end())
+      continue; // vertex is already processed
+    aProcessed.insert(aVertex);
+
+    std::shared_ptr<GeomAlgoAPI_Copy> aCopy(new GeomAlgoAPI_Copy(aVertex));
+    aVertex.reset(new GeomAPI_Vertex(aCopy->shape()));
+
+    std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList);
+    if (aPartitionAlgo)
+      aMakeShapeList->appendAlgo(aPartitionAlgo);
+    aMakeShapeList->appendAlgo(aCopy);
 
     // Store result.
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
-    aResultBody->storeModified(aShape, aCopyAlgo->shape());
+    aResultBody->storeModified(theShapes, aVertex, aMakeShapeList);
     setResult(aResultBody, aResultIndex);
     ++aResultIndex;
   }
 
   removeResults(aResultIndex);
 }
+
+static void collectEdgesAndVertices(AttributeSelectionPtr theSelection, ListOfShape& thePrimitives)
+{
+  FeaturePtr aFeature = theSelection->contextFeature();
+  ResultPtr aContext = theSelection->context();
+  GeomShapePtr aShape = theSelection->value();
+  if (aShape)
+    thePrimitives.push_back(aShape);
+  else {
+    if (aContext && !aFeature)
+      aFeature = ModelAPI_Feature::feature(aContext);
+    if (!aFeature)
+      return;
+
+    // process results of the feature
+    const std::list<ResultPtr>& aResults = aFeature->results();
+    std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+    for (; anIt != aResults.end(); ++anIt)
+      thePrimitives.push_back((*anIt)->shape());
+
+    CompositeFeaturePtr aComposite =
+        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
+    if (!aComposite)
+      return;
+
+    // add construction points (centers of circles, etc.)
+    for (int i = 0, nbSubs = aComposite->numberOfSubs(); i < nbSubs; ++i) {
+      FeaturePtr aSubFeature = aComposite->subFeature(i);
+      const std::list<ResultPtr>& aSubResults = aSubFeature->results();
+      // find all points
+      for (anIt = aSubResults.begin(); anIt != aSubResults.cend(); ++anIt) {
+        GeomShapePtr aSubResShape = (*anIt)->shape();
+        if (aSubResShape->isVertex())
+          thePrimitives.push_back(aSubResShape);
+      }
+    }
+  }
+}
+
+void BuildPlugin_Vertex::execute()
+{
+  // Get base objects list.
+  AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID());
+  if (!aSelectionList.get()) {
+    setError("Error: Could not get selection list.");
+    return;
+  }
+  if (aSelectionList->size() == 0) {
+    setError("Error: Empty selection list.");
+    return;
+  }
+
+  // Get "Compute intersections" flag value
+  bool isIntersect = false;
+  if (boolean(INTERSECT_ID()).get() && boolean(INTERSECT_ID())->isInitialized()) {
+    isIntersect = boolean(INTERSECT_ID())->value();
+  }
+
+  // Iterate arguments and collect shapes
+  ListOfShape aShapes;
+  for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
+    collectEdgesAndVertices(aSelection, aShapes);
+  }
+
+  buildVertices(aShapes, isIntersect);
+}
index 62852d5e3a087b13fb93b4739741203c6bf3f901..980dd82017a2a91cd7c411bbf4e66209d46cf1eb 100644 (file)
@@ -23,6 +23,7 @@
 #include "BuildPlugin.h"
 
 #include <ModelAPI_Feature.h>
+#include <GeomAPI_Shape.h>
 
 /// \class BuildPlugin_Vertex
 /// \ingroup Plugins
@@ -47,6 +48,13 @@ public:
     return MY_BASE_OBJECTS_ID;
   }
 
+  /// Attribute name of "Compute intersections" checkbox.
+  inline static const std::string& INTERSECT_ID()
+  {
+    static const std::string MY_INTERSECT_ID("intersect");
+    return MY_INTERSECT_ID;
+  }
+
   /// \return the kind of a feature.
   BUILDPLUGIN_EXPORT virtual const std::string& getKind()
   {
@@ -59,6 +67,9 @@ public:
 
   /// Creates a new part document if needed.
   BUILDPLUGIN_EXPORT virtual void execute();
+
+protected:
+  void buildVertices(const ListOfShape& theShapes, bool isIntersect);
 };
 
 #endif
index 4fe602e84c29c5c4f0dfb3a8c3369b6cdf07c726..c7caa85812a46170e654e5298e309f35a53b494e 100644 (file)
 
 #include "BuildPlugin_Wire.h"
 
+#include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
 
 #include <Events_InfoMessage.h>
 
 #include <GeomAPI_PlanarEdges.h>
 #include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_Vertex.h>
 
-#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_PaveFiller.h>
+#include <GeomAlgoAPI_SketchBuilder.h>
+#include <GeomAlgoAPI_Tools.h>
 #include <GeomAlgoAPI_WireBuilder.h>
 
+#include <SketchPlugin_Sketch.h>
+
 #include <algorithm>
 
+static bool buildSketchWires(FeaturePtr theSketchFeature, GeomShapePtr theSketchShape,
+                             bool isIntersect,
+                             ListOfShape& theWires, GeomMakeShapePtr& theAlgo,
+                             std::string& theError);
+
+static bool buildWire(const ListOfShape& theEdges, GeomShapePtr& theWire, std::string& theError);
+
 //=================================================================================================
 BuildPlugin_Wire::BuildPlugin_Wire()
 {
@@ -42,6 +58,9 @@ BuildPlugin_Wire::BuildPlugin_Wire()
 void BuildPlugin_Wire::initAttributes()
 {
   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
+
+  data()->addAttribute(INTERSECT_ID(), ModelAPI_AttributeBoolean::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INTERSECT_ID());
 }
 
 //=================================================================================================
@@ -58,13 +77,25 @@ void BuildPlugin_Wire::execute()
     return;
   }
 
+  AttributeBooleanPtr anIntersectAttr = boolean(INTERSECT_ID());
+  bool isIntersect = anIntersectAttr->isInitialized() && anIntersectAttr->value();
+
   // Collect base shapes.
   ListOfShape anEdges;
+  std::list< std::pair<FeaturePtr, GeomShapePtr> > aSketches;
   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
     GeomShapePtr aShape = aSelection->value();
     if(!aShape.get()) {
       aShape = aSelection->context()->shape();
+
+      std::shared_ptr<GeomAPI_PlanarEdges> aSketchShape =
+          std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShape);
+      if (aSketchShape) {
+        FeaturePtr aSketchFeature = ModelAPI_Feature::feature(aSelection->context());
+        aSketches.push_back(std::pair<FeaturePtr, GeomShapePtr>(aSketchFeature, aSketchShape));
+        continue;
+      }
     }
     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
       GeomShapePtr anEdge = anExp.current();
@@ -72,27 +103,57 @@ void BuildPlugin_Wire::execute()
     }
   }
 
-  // Create wire.
-  GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(anEdges);
-  if(!aWire.get()) {
-    setError("Error: Result wire is empty. Probably it has disconnected edges or non-manifold.");
-    return;
-  }
+  int aResultIndex = 0;
+  std::string anError;
 
-  // Store result.
-  ResultBodyPtr aResultBody = document()->createBody(data());
-  aResultBody->store(aWire);
-  for(GeomAPI_ShapeExplorer anExp(aWire, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
-    GeomShapePtr anEdgeInResult = anExp.current();
-    for(ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) {
-      std::shared_ptr<GeomAPI_Edge> anEdgeInList(new GeomAPI_Edge(*anIt));
-      if(anEdgeInList->isEqual(anEdgeInResult)) {
-        aResultBody->modified(anEdgeInList, anEdgeInResult);
-        break;
+  if (!anEdges.empty()) {
+    // Create wire from the list of edges.
+    GeomShapePtr aWire;
+    if (!buildWire(anEdges, aWire, anError)) {
+      setError(anError);
+      return;
+    }
+
+    // Store result.
+    ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
+    aResultBody->store(aWire);
+    for (GeomAPI_ShapeExplorer anExp(aWire, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
+      GeomShapePtr anEdgeInResult = anExp.current();
+      for (ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) {
+        std::shared_ptr<GeomAPI_Edge> anEdgeInList(new GeomAPI_Edge(*anIt));
+        if (anEdgeInList->isEqual(anEdgeInResult)) {
+          aResultBody->modified(anEdgeInList, anEdgeInResult);
+          break;
+        }
       }
     }
+    setResult(aResultBody, aResultIndex);
+    ++aResultIndex;
   }
-  setResult(aResultBody);
+
+  // create wires from sketches
+  for (std::list<std::pair<FeaturePtr, GeomShapePtr> >::iterator anIt = aSketches.begin();
+       anIt != aSketches.end(); ++anIt) {
+    ListOfShape aWires;
+    GeomMakeShapePtr aMakeShapeList;
+    if (!buildSketchWires(anIt->first, anIt->second, isIntersect,
+                          aWires, aMakeShapeList, anError)) {
+      setError(anError);
+      return;
+    }
+
+    for (ListOfShape::iterator aWIt = aWires.begin(); aWIt != aWires.end(); ++aWIt) {
+      ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
+      ListOfShape aSketches;
+      aSketches.push_back(anIt->second);
+      aResultBody->storeModified(aSketches, *aWIt, aMakeShapeList);
+      aResultBody->loadModifiedShapes(aMakeShapeList, anIt->second, GeomAPI_Shape::EDGE);
+      setResult(aResultBody, aResultIndex);
+      ++aResultIndex;
+    }
+  }
+
+  removeResults(aResultIndex);
 }
 
 //=================================================================================================
@@ -216,3 +277,142 @@ bool BuildPlugin_Wire::addContour()
 
   return true;
 }
+
+
+
+// =====================     Auxiliary functions     ==============================================
+
+bool buildWire(const ListOfShape& theEdges, GeomShapePtr& theWire, std::string& theError)
+{
+  theWire = GeomAlgoAPI_WireBuilder::wire(theEdges);
+  if (!theWire.get()) {
+    theError = "Error: Result wire is empty. Probably it has disconnected edges or non-manifold.";
+    return false;
+  }
+  return true;
+}
+
+bool buildSketchWires(FeaturePtr theSketchFeature, GeomShapePtr theSketchShape, bool isIntersect,
+                      ListOfShape& theWires, GeomMakeShapePtr& theAlgo, std::string& theError)
+{
+  ListOfShape aSketchEdges =
+      std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theSketchShape)->getEdges();
+
+  std::shared_ptr<GeomAlgoAPI_MakeShapeList> anAlgoList(new GeomAlgoAPI_MakeShapeList);
+  if (isIntersect) {
+    std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aProcessedEdges;
+    // perform sketch builder first
+    AttributePointPtr anOrigin = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+        theSketchFeature->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+    AttributeDirPtr aNormal = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+        theSketchFeature->attribute(SketchPlugin_Sketch::NORM_ID()));
+    AttributeDirPtr aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+        theSketchFeature->attribute(SketchPlugin_Sketch::DIRX_ID()));
+    std::shared_ptr<GeomAlgoAPI_SketchBuilder> aSketchBuilder(new GeomAlgoAPI_SketchBuilder(
+        anOrigin->pnt(), aDirX->dir(), aNormal->dir(), theSketchShape));
+
+    anAlgoList->appendAlgo(aSketchBuilder);
+
+    // collect wires from faces
+    const ListOfShape& aFaces = aSketchBuilder->faces();
+    for (ListOfShape::const_iterator anIt = aFaces.begin(); anIt != aFaces.end(); ++anIt) {
+      for (GeomAPI_ShapeExplorer aWExp(*anIt, GeomAPI_Shape::WIRE); aWExp.more(); aWExp.next()) {
+        GeomAPI_ShapeExplorer aEExp(aWExp.current(), GeomAPI_Shape::EDGE);
+        if (aProcessedEdges.find(aEExp.current()) != aProcessedEdges.end())
+          continue; // wire is already processed
+        // mark edges as processed
+        for (; aEExp.more(); aEExp.next())
+          aProcessedEdges.insert(aEExp.current());
+        // store the wire
+        theWires.push_back(aWExp.current());
+      }
+    }
+
+    // collect unused edges
+    ListOfShape aCopy;
+    for (ListOfShape::iterator anIt = aSketchEdges.begin(); anIt != aSketchEdges.end(); ++anIt) {
+      ListOfShape anImages;
+      aSketchBuilder->modified(*anIt, anImages);
+      for (ListOfShape::iterator anEdge = anImages.begin(); anEdge != anImages.end(); ++anEdge)
+        if (aProcessedEdges.find(*anEdge) == aProcessedEdges.end())
+          aCopy.push_back(*anEdge);
+    }
+
+    if (aCopy.size() > 1) {
+      // split these edges
+      std::shared_ptr<GeomAlgoAPI_PaveFiller> aGeneralFuse(new GeomAlgoAPI_PaveFiller(aCopy));
+      if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(
+              aGeneralFuse, BuildPlugin_Wire::ID(), theError))
+        return false;
+      anAlgoList->appendAlgo(aGeneralFuse);
+
+      // collect edges after the split
+      aSketchEdges.clear();
+      for (GeomAPI_ShapeExplorer anExp(aGeneralFuse->shape(), GeomAPI_Shape::EDGE);
+           anExp.more(); anExp.next())
+        aSketchEdges.push_back(anExp.current());
+    }
+    else
+      aSketchEdges = aCopy;
+  }
+
+  // connect least edges to wires
+  typedef std::list<ListOfShape> ListOfWires;
+  ListOfWires aNewWires;
+  typedef std::map<GeomVertexPtr, ListOfWires::iterator,
+                   GeomAPI_Vertex::GeometricComparator> MapVertexWire;
+  MapVertexWire aMapVW;
+  for (ListOfShape::iterator aEIt = aSketchEdges.begin(); aEIt != aSketchEdges.end(); ++aEIt) {
+    GeomEdgePtr anEdge = (*aEIt)->edge();
+    GeomVertexPtr aStartV, aEndV;
+    anEdge->vertices(aStartV, aEndV);
+    MapVertexWire::iterator aFoundStart = aMapVW.find(aStartV);
+    MapVertexWire::iterator aFoundEnd = aMapVW.find(aEndV);
+    if (aFoundStart == aMapVW.end()) {
+      if (aFoundEnd == aMapVW.end()) {
+        // new wire
+        aNewWires.push_back(ListOfShape());
+        ListOfWires::iterator aNewW = --aNewWires.end();
+        aNewW->push_back(anEdge);
+        aMapVW[aStartV] = aNewW;
+        aMapVW[aEndV] = aNewW;
+        continue;
+      }
+    }
+    else {
+      if (aFoundEnd == aMapVW.end()) {
+        // swap found vertices for correct further processing
+        aFoundEnd = aFoundStart;
+        aStartV = aEndV;
+      }
+      else {
+        // both vertices are found => close the loop
+        aFoundStart->second->push_back(anEdge);
+        if (aFoundStart->second != aFoundEnd->second) {
+          aFoundStart->second->insert(aFoundStart->second->end(),
+              aFoundEnd->second->begin(), aFoundEnd->second->end());
+          aNewWires.erase(aFoundEnd->second);
+        }
+        aMapVW.erase(aFoundStart);
+        aMapVW.erase(aFoundEnd);
+        continue;
+      }
+    }
+    // add edge to existing wire, substitute the connection point
+    // by the other boundary point of the edge
+    aFoundEnd->second->push_back(anEdge);
+    aMapVW[aStartV] = aFoundEnd->second;
+    aMapVW.erase(aFoundEnd);
+  }
+
+  // generate new wires from the sets of edges
+  for (ListOfWires::iterator anIt = aNewWires.begin(); anIt != aNewWires.end(); ++anIt) {
+    GeomShapePtr aWire;
+    if (!buildWire(*anIt, aWire, theError))
+      return false;
+    theWires.push_back(aWire);
+  }
+
+  theAlgo = anAlgoList;
+  return true;
+}
index c0b873174344e4f7db5054ec5a276bfdc26c9d9d..5677bebb3275b228583941a23d5e9181a0c14502 100644 (file)
@@ -54,6 +54,13 @@ public:
     return MY_ADD_CONTOUR_ACTION_ID;
   }
 
+  /// Attribute name of "Compute intersections" checkbox.
+  inline static const std::string& INTERSECT_ID()
+  {
+    static const std::string MY_INTERSECT_ID("intersect");
+    return MY_INTERSECT_ID;
+  }
+
   /// \return the kind of a feature.
   BUILDPLUGIN_EXPORT virtual const std::string& getKind()
   {
diff --git a/src/BuildPlugin/BuildPlugin_msg_fr.ts b/src/BuildPlugin/BuildPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..61ea6f2
--- /dev/null
@@ -0,0 +1,1131 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Build</source>
+      <translation>Construire</translation>
+    </message>
+    <message>
+      <source>CompSolid</source>
+      <translation>Solide Composite</translation>
+    </message>
+    <message>
+      <source>Compound</source>
+      <translation>Assemblage</translation>
+    </message>
+    <message>
+      <source>Edge</source>
+      <translation>Bord</translation>
+    </message>
+    <message>
+      <source>Face</source>
+      <translation>Face</translation>
+    </message>
+    <message>
+      <source>Filling</source>
+      <translation>Remplissage</translation>
+    </message>
+    <message>
+      <source>Interpolation</source>
+      <translation>Interpolation</translation>
+    </message>
+    <message>
+      <source>Polyline</source>
+      <translation>Polyligne</translation>
+    </message>
+    <message>
+      <source>Shell</source>
+      <translation>Coque</translation>
+    </message>
+    <message>
+      <source>Solid</source>
+      <translation>Solide</translation>
+    </message>
+    <message>
+      <source>Sub-Shapes</source>
+      <translation>Sous-formes</translation>
+    </message>
+    <message>
+      <source>Vertex</source>
+      <translation>Sommet</translation>
+    </message>
+    <message>
+      <source>Wire</source>
+      <translation>Contour</translation>
+    </message>
+  </context>
+
+  <!-- Validators -->
+
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Attribute have empty context.</source>
+      <translation>Objet sélectionné non valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty shape selected.</source>
+      <translation>Forme vide sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Les objets infinis ne sont pas acceptés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:first_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:second_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un deuxième point</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Face:BuildPlugin_ValidatorBaseForFace</name>
+    <message>
+      <source>Empty attribute \"%1\".</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+    <message>
+      <source>Objects not selected.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+    <message>
+      <source>Error while checking if edges intersects.</source>
+      <translation>Erreur lors de la vérification de l&apos;intersection des arêtes.</translation>
+    </message>
+    <message>
+      <source>Selected objects have intersections.</source>
+      <translation>Les objets sélectionnés ont des intersections.</translation>
+    </message>
+    <message>
+      <source>Selected object(s) should belong to only one plane.</source>
+      <translation>Les objets sélectionnés doivent appartenir à un seul plan.</translation>
+    </message>
+    <message>
+      <source>Selected objects do not generate closed contour.</source>
+      <translation>Les objets sélectionnés ne génèrent pas un contour fermé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Attribute have empty context.</source>
+      <translation>Objet sélectionné non valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty shape selected.</source>
+      <translation>Forme vide sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Les objets infinis ne sont pas acceptés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Objet sélectionné non valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SubShapes:subshapes:BuildPlugin_ValidatorSubShapesSelection</name>
+    <message>
+      <source>Could not get selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:subshapes:BuildPlugin_ValidatorSubShapesSelection</name>
+    <message>
+      <source>Base shape is empty.</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:subshapes:BuildPlugin_ValidatorSubShapesSelection</name>
+    <message>
+      <source>Empty attribute in list.</source>
+      <translation>Objet sélectionné non valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:subshapes:BuildPlugin_ValidatorSubShapesSelection</name>
+    <message>
+      <source>Selected shape has unacceptable type.</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:subshapes:BuildPlugin_ValidatorSubShapesSelection</name>
+    <message>
+      <source>Selected shape is not inside base face.</source>
+      <translation>La forme sélectionnée n&apos;est pas à l&apos;intérieur de la base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_shape" is not initialized.</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "subshapes" is not initialized.</source>
+      <translation>Sous-formes non sélectionnées.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>La forme de base devrait être l’un des types suivants: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Objet sélectionné non valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Attribute have empty context.</source>
+      <translation>Objet sélectionné non valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty shape selected.</source>
+      <translation>Forme vide sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Les objets infinis ne sont pas acceptés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Wire:BuildPlugin_ValidatorBaseForWire</name>
+    <message>
+      <source>Empty attribute \"%1\".</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:BuildPlugin_ValidatorBaseForWire</name>
+    <message>
+      <source>Result wire empty. Probably it has disconnected edges or non-manifold.</source>
+      <translation>Résultat contour vide. Probablement il possède des bords déconnectés ou non-manifold.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection list.</source>
+      <translation>Impossible d&apos;obtenir la liste de sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Could not get selection.</source>
+      <translation>Impossible d&apos;obtenir la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Attribute have empty context.</source>
+      <translation>Les attributs ont un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty shape selected.</source>
+      <translation>Forme vide sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Les objets infinis ne sont pas acceptés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l'un des suivants : %1</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Filling:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Attribute "%1" should contain at least %2 items.</source>
+      <translation>La liste des segments et des contours doit contenir au moins 2 éléments.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Polyline:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Attribute "%1" should contain at least %2 items.</source>
+      <translation>La liste de points doit contenir au moins 2 éléments</translation>
+    </message>
+  </context>
+  <context>
+    <name>Model_Data</name>
+    <message>
+      <source>Error: Result polyline has self-intersections.</source>
+      <translation>La polyligne a des auto-intersections.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Polyline</name>
+    <message>
+      <source>Error: Result polyline has self-intersections.</source>
+      <translation>La polyligne a des auto-intersections.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Interpolation:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Attribute "%1" should contain at least %2 items.</source>
+      <translation>La liste de points doit contenir au moins 2 éléments</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:tangent_end</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le vecteur tangent à la fin de la courbe</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>CompSolid</name>
+    <message>
+      <source>CompSolid</source>
+      <translation>Solide Composite</translation>
+    </message>
+    <message>
+      <source>Create a compsolid from solids or other compsolids</source>
+      <translation>Créer un solide composite à partir de solides ou d&apos;autres solides composites</translation>
+    </message>
+  </context>
+  <context>
+    <name>CompSolid:BuildPlugin_ValidatorBaseForSolids</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Liste de sélection vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>CompSolid:base_objects</name>
+    <message>
+      <source>Select solids or compsolids.</source>
+      <translation>Sélectionnez des solides ou des solides composites.</translation>
+    </message>
+    <message>
+      <source>Solids and CompSolids:</source>
+      <translation>Solides et Solides Composites:</translation>
+    </message>
+  </context>
+  <context>
+    <name>CompSolid:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Liste de sélection vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>CompSolid:BuildPlugin_ValidatorBaseForSolids</name>
+    <message>
+      <source>Unable to build a solid</source>
+      <translation>Impossible de créer un solide.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Compound</name>
+    <message>
+      <source>Compound</source>
+      <translation>Assemblage</translation>
+    </message>
+    <message>
+      <source>Create a compound of objects</source>
+      <translation>Créer un assemblage</translation>
+    </message>
+  </context>
+  <context>
+    <name>Compound:base_objects</name>
+    <message>
+      <source>Objects:</source>
+      <translation>Objets:</translation>
+    </message>
+    <message>
+      <source>Select any kind of objects.</source>
+      <translation>Sélectionnez n&apos;importe quel type d&apos;objets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Compound:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionner des objets de base.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Edge</name>
+    <message>
+      <source>Create edges from sketch edges or other edge objects</source>
+      <translation>Créer des arêtes à partir d&apos;arêtes d&apos;esquisse ou d&apos;autres objets d&apos;arête</translation>
+    </message>
+    <message>
+      <source>Edge</source>
+      <translation>Bord</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:base_objects</name>
+    <message>
+      <source>Edges:</source>
+      <translation>Arêtes:</translation>
+    </message>
+    <message>
+      <source>Select edges on sketch or edges objects.</source>
+      <translation>Sélectionner des arêtes sur des objets d&apos;esquisse ou d&apos;arêtes.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:creation_method</name>
+    <message>
+      <source>By segments</source>
+      <translation>Par segments</translation>
+    </message>
+    <message>
+      <source>By two points</source>
+      <translation>Par deux points</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:first_point</name>
+    <message>
+      <source>First point</source>
+      <translation>Premier point</translation>
+    </message>
+    <message>
+      <source>Select a first point</source>
+      <translation>Sélectionnez un premier point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:first_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:second_point</name>
+    <message>
+      <source>Second point</source>
+      <translation>Deuxième point</translation>
+    </message>
+    <message>
+      <source>Select a second point</source>
+      <translation>Sélectionnez un deuxième point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Edge:second_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Face</name>
+    <message>
+      <source>Create a face from edges, wires and faces</source>
+      <translation>Créer une face à partir d&apos;arêtes, de contours et de faces</translation>
+    </message>
+    <message>
+      <source>Face</source>
+      <translation>Face</translation>
+    </message>
+  </context>
+  <context>
+    <name>Face:base_objects</name>
+    <message>
+      <source>Objects:</source>
+      <translation>Objets:</translation>
+    </message>
+    <message>
+      <source>Select edges, wires or faces.</source>
+      <translation>Sélectionnez des arêtes, des contours ou des faces.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Filling</name>
+    <message>
+      <source>Create face from list of edges</source>
+      <translation>Créer une face à partir d&apos;une liste d&apos;arêtes</translation>
+    </message>
+    <message>
+      <source>Filling</source>
+      <translation>Remplissage</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:advanced_options</name>
+    <message>
+      <source>Advanced options</source>
+      <translation>Options avancées</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:approximation</name>
+    <message>
+      <source>Approximation</source>
+      <translation>Approximation</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:base_objects</name>
+    <message>
+      <source>Segments and wires:</source>
+      <translation>Segments et contours:</translation>
+    </message>
+    <message>
+      <source>Select edges or wires.</source>
+      <translation>Sélectionnez des arêtes ou des contours.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:max_degree</name>
+    <message>
+      <source>Max deg</source>
+      <translation>Max deg</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:min_degree</name>
+    <message>
+      <source>Min deg</source>
+      <translation>Min deg</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:nb_iter</name>
+    <message>
+      <source>Nb iter</source>
+      <translation>Nb iter</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:orientation</name>
+    <message>
+      <source>Auto-correct edges orientation</source>
+      <translation>Correction automatique de l&apos;orientation des bords</translation>
+    </message>
+    <message>
+      <source>Use curve information</source>
+      <translation>Utiliser les informations de la courbe</translation>
+    </message>
+    <message>
+      <source>Use edges orientation</source>
+      <translation>Utiliser l&apos;orientation des bords</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:tol_2d</name>
+    <message>
+      <source>Tol 2D</source>
+      <translation>Tol 2D</translation>
+    </message>
+  </context>
+  <context>
+    <name>Filling:tol_3d</name>
+    <message>
+      <source>Tol 3D</source>
+      <translation>Tol 3D</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Interpolation</name>
+    <message>
+      <source>Create an interpolation curve from points</source>
+      <translation>Créer une courbe d&apos;interpolation à partir de points</translation>
+    </message>
+    <message>
+      <source>Interpolation</source>
+      <translation>Interpolation</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:base_objects</name>
+    <message>
+      <source>Points and vertices:</source>
+      <translation>Points et sommets:</translation>
+    </message>
+    <message>
+      <source>Select points or vertices objects.</source>
+      <translation>Sélectionner des points ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:closed</name>
+    <message>
+      <source>Closed</source>
+      <translation>Fermé</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:reorder</name>
+    <message>
+      <source>Changes the order of points to construct the shortest curve.</source>
+      <translation>Change l&apos;ordre des points pour construire la courbe la plus courte.</translation>
+    </message>
+    <message>
+      <source>Reorder</source>
+      <translation>Réorganiser</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:tangent_end</name>
+    <message>
+      <source>&lt;end&gt;</source>
+      <translation>&lt;fin&gt;</translation>
+    </message>
+    <message>
+      <source>End</source>
+      <translation>Fin</translation>
+    </message>
+    <message>
+      <source>Select vector tangent to the end of curve</source>
+      <translation>Sélectionnez le vecteur tangent à la fin de la courbe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:tangent_start</name>
+    <message>
+      <source>&lt;start&gt;</source>
+      <translation>&lt;début&gt;</translation>
+    </message>
+    <message>
+      <source>Select vector tangent to the start of curve</source>
+      <translation>Sélectionnez le vecteur tangent au début de la courbe</translation>
+    </message>
+    <message>
+      <source>Start</source>
+      <translation>Début</translation>
+    </message>
+  </context>
+  <context>
+    <name>Interpolation:use_tangents</name>
+    <message>
+      <source>Tangents</source>
+      <translation>Tangentes</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Polyline</name>
+    <message>
+      <source>Create a polyline from points</source>
+      <translation>Créer une polyligne à partir de points</translation>
+    </message>
+    <message>
+      <source>Polyline</source>
+      <translation>Polyligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>Polyline:base_objects</name>
+    <message>
+      <source>Points and vertices:</source>
+      <translation>Points et sommets:</translation>
+    </message>
+    <message>
+      <source>Select points or vertices objects.</source>
+      <translation>Sélectionner des points ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Polyline:closed</name>
+    <message>
+      <source>Closed</source>
+      <translation>Fermé</translation>
+    </message>
+    <message>
+      <source>Closes the polyline.</source>
+      <translation>Ferme la polyligne.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Shell</name>
+    <message>
+      <source>Create a shell from faces or shells objects</source>
+      <translation>Créer une coque à partir d&apos;objets faces ou coques</translation>
+    </message>
+    <message>
+      <source>Shell</source>
+      <translation>Coque</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects</name>
+    <message>
+      <source>Faces and shells:</source>
+      <translation>Faces et coques:</translation>
+    </message>
+    <message>
+      <source>Select faces or shells objects.</source>
+      <translation>Sélectionner des objets faces ou coques.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Shell:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Liste de sélection vide.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Solid</name>
+    <message>
+      <source>Create a solid from faces or shells</source>
+      <translation>Créer un solide à partir de faces ou de coques</translation>
+    </message>
+    <message>
+      <source>Solid</source>
+      <translation>Solide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Solid:BuildPlugin_ValidatorBaseForSolids</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Liste de sélection vide.</translation>
+    </message>
+    <message>
+      <source>Unable to build a solid</source>
+      <translation>Impossible de construire un solide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Solid:base_objects</name>
+    <message>
+      <source>Faces and shells:</source>
+      <translation>Faces et coques:</translation>
+    </message>
+    <message>
+      <source>Select faces or shells.</source>
+      <translation>Sélectionnez des faces ou des coques.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Solid:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
+    <message>
+      <source>Empty selection list.</source>
+      <translation>Liste de sélection vide.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SubShapes</name>
+    <message>
+      <source>Allows to add or to remove sub-shapes of the selected shape</source>
+      <translation>Permet d&apos;ajouter ou de supprimer des sous-formes de la forme sélectionnée</translation>
+    </message>
+    <message>
+      <source>Sub-Shapes</source>
+      <translation>Sous-formes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:base_shape</name>
+    <message>
+      <source>Select a shape to modify.</source>
+      <translation>Sélectionnez une forme à modifier.</translation>
+    </message>
+    <message>
+      <source>Shape:</source>
+      <translation>Forme:</translation>
+    </message>
+  </context>
+  <context>
+    <name>SubShapes:subshapes</name>
+    <message>
+      <source>Select shapes on sketch to add.</source>
+      <translation>Sélectionnez des formes sur l&apos;esquisse à ajouter.</translation>
+    </message>
+    <message>
+      <source>Sub-Shapes:</source>
+      <translation>Sous-formes:</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Vertex</name>
+    <message>
+      <source>Create vertices from sketch point or other vertex objects</source>
+      <translation>Créer des sommets à partir d&apos;un point d&apos;esquisse ou d&apos;autres objets de sommet</translation>
+    </message>
+    <message>
+      <source>Vertex</source>
+      <translation>Sommet</translation>
+    </message>
+  </context>
+  <context>
+    <name>Vertex:base_objects</name>
+    <message>
+      <source>Select vertices on sketch or vertex objects.</source>
+      <translation>Sélectionnez des sommets de l&apos;esquisse ou des objets sommet.</translation>
+    </message>
+    <message>
+      <source>Vertices:</source>
+      <translation>Sommets:</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Wire</name>
+    <message>
+      <source>Create a wire from sketch edges, edges and wires objects</source>
+      <translation>Créer un contour à partir d&apos;arêtes de l’esquisse, d&apos;arêtes et de contours</translation>
+    </message>
+    <message>
+      <source>Wire</source>
+      <translation>Contour</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:add_contour</name>
+    <message>
+      <source>Add contour</source>
+      <translation>Ajouter un contour</translation>
+    </message>
+    <message>
+      <source>Adds to the list of segments other segments of the sketcher connected to the already selected ones to create a closed contour.</source>
+      <translation>Ajoute à la liste des segments d&apos;autres segments de l&apos;esquisse connectés à ceux déjà sélectionnés pour créer un contour fermé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Wire:base_objects</name>
+    <message>
+      <source>Segments and wires:</source>
+      <translation>Segments et contours:</translation>
+    </message>
+    <message>
+      <source>Select edges on sketch, edges or wires objects.</source>
+      <translation>Sélectionner des arêtes sur des objets d&apos;esquisse, d&apos;arêtes ou de contours.</translation>
+    </message>
+  </context>
+
+</TS>
index 25bc5a01310fe54987e856066887768cbaffd885..2954b05c7f0cb94b7601731bcbd92103982f4172 100644 (file)
@@ -25,7 +25,9 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events
                     ${PROJECT_SOURCE_DIR}/src/ModelAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
+                    ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomValidators
+                    ${PROJECT_SOURCE_DIR}/src/SketchPlugin
 )
 
 SET(PROJECT_HEADERS
@@ -83,6 +85,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     BuildPlugin_msg_en.ts
+    BuildPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
@@ -107,16 +110,32 @@ INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Build
 
 ADD_UNIT_TESTS(TestVertex.py
                TestVertex_ErrorMsg.py
+               TestVertex_WholeSketch_1.py
+               TestVertex_WholeSketch_2.py
                TestEdge.py
                TestEdge_ByPoints.py
                TestEdge_ErrorMsg.py
+               TestEdge_WholeSketch_1.py
+               TestEdge_WholeSketch_2.py
+               TestEdge_WholeSketch_3.py
+               TestEdge_WholeSketch_4.py
                TestWire.py
                TestWire_ErrorMsg.py
+               TestWire_WholeSketch_1.py
+               TestWire_WholeSketch_2.py
+               TestWire_WholeSketch_3.py
+               TestWire_WholeSketch_4.py
+               TestWire_WholeSketch_5.py
+               TestWire_WholeSketch_6.py
                TestPolyline.py
                TestInterpolation.py
                TestFace.py
                TestFace_ErrorMsg.py
+               TestFace_WholeSketch_1.py
+               TestFace_WholeSketch_2.py
                TestShell.py
+               TestShell_WholeSketch_1.py
+               TestShell_WholeSketch_2.py
                TestSolid.py
                TestSolid_ErrorMsg.py
                TestCompSolid.py
index 83d163b5ee8294165367bcc39dace57b9495eecf..2e194941ff4a3dccf497325820f1ea2118536b9f 100644 (file)
@@ -114,12 +114,6 @@ assert (len(anEdgeFeature2.results()) == 12)
 aSession.startOperation()
 anEdgeFeature3 = aPart.addFeature("Edge")
 aBaseObjectsList = anEdgeFeature3.selectionList("base_objects")
-aBaseObjectsList.append(aSketchResult, None)
-aSession.finishOperation()
-assert (len(anEdgeFeature3.results()) == 0)
-
-aSession.startOperation()
-aBaseObjectsList.clear()
 aShapeExplorer = GeomAPI_ShapeExplorer(aBoxShape, GeomAPI_Shape.VERTEX)
 aShape = aShapeExplorer.current()
 aBaseObjectsList.append(aBoxResult, aShape)
diff --git a/src/BuildPlugin/Test/TestEdge_WholeSketch_1.py b/src/BuildPlugin/Test/TestEdge_WholeSketch_1.py
new file mode 100644 (file)
index 0000000..aa7a9aa
--- /dev/null
@@ -0,0 +1,44 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")], False)
+model.end()
+
+model.testNbResults(Edge_1, 4)
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.EDGE, [1, 1, 1, 1])
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.VERTEX, [2, 2, 2, 2])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestEdge_WholeSketch_2.py b/src/BuildPlugin/Test/TestEdge_WholeSketch_2.py
new file mode 100644 (file)
index 0000000..8558502
--- /dev/null
@@ -0,0 +1,44 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")], True)
+model.end()
+
+model.testNbResults(Edge_1, 8)
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.EDGE, [1, 1, 1, 1, 1, 1, 1, 1])
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.VERTEX, [2, 2, 2, 2, 2, 2, 2, 2])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestEdge_WholeSketch_3.py b/src/BuildPlugin/Test/TestEdge_WholeSketch_3.py
new file mode 100644 (file)
index 0000000..c725d12
--- /dev/null
@@ -0,0 +1,44 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("COMPOUND", "Sketch_1"), model.selection("EDGE", "Sketch_2/SketchArc_1_2")], False)
+model.end()
+
+model.testNbResults(Edge_1, 4)
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.EDGE, [1, 1, 1, 1])
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.VERTEX, [2, 2, 2, 2])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestEdge_WholeSketch_4.py b/src/BuildPlugin/Test/TestEdge_WholeSketch_4.py
new file mode 100644 (file)
index 0000000..8ddd0ab
--- /dev/null
@@ -0,0 +1,44 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("COMPOUND", "Sketch_1"), model.selection("EDGE", "Sketch_2/SketchArc_1_2")], True)
+model.end()
+
+model.testNbResults(Edge_1, 8)
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.EDGE, [1, 1, 1, 1, 1, 1, 1, 1])
+model.testNbSubShapes(Edge_1, GeomAPI_Shape.VERTEX, [2, 2, 2, 2, 2, 2, 2, 2])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestFace_WholeSketch_1.py b/src/BuildPlugin/Test/TestFace_WholeSketch_1.py
new file mode 100644 (file)
index 0000000..713ccb2
--- /dev/null
@@ -0,0 +1,49 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_2.addCircle(-5, 10, 20)
+SketchLine_4 = Sketch_2.addLine(-25, 10, 15, 10)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_4.startPoint(), SketchCircle_1.results()[1])
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchCircle_1.results()[1])
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")])
+model.end()
+
+model.testNbResults(Face_1, 1)
+model.testNbSubShapes(Face_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Face_1, GeomAPI_Shape.EDGE, [3])
+model.testNbSubShapes(Face_1, GeomAPI_Shape.VERTEX, [6])
+model.testResultsVolumes(Face_1, [441.0539215686274])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestFace_WholeSketch_2.py b/src/BuildPlugin/Test/TestFace_WholeSketch_2.py
new file mode 100644 (file)
index 0000000..c3a25de
--- /dev/null
@@ -0,0 +1,49 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_2.addCircle(-5, 10, 20)
+SketchLine_4 = Sketch_2.addLine(-25, 10, 15, 10)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_4.startPoint(), SketchCircle_1.results()[1])
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchCircle_1.results()[1])
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")])
+model.end()
+
+model.testNbResults(Face_1, 3)
+model.testNbSubShapes(Face_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Face_1, GeomAPI_Shape.EDGE, [3, 2, 2])
+model.testNbSubShapes(Face_1, GeomAPI_Shape.VERTEX, [6, 4, 4])
+model.testResultsVolumes(Face_1, [441.0539215686274, 628.318530717958, 628.318530717958])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestShell_WholeSketch_1.py b/src/BuildPlugin/Test/TestShell_WholeSketch_1.py
new file mode 100644 (file)
index 0000000..0b11501
--- /dev/null
@@ -0,0 +1,49 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_2.addCircle(-5, 10, 20)
+SketchLine_4 = Sketch_2.addLine(-25, 10, 15, 10)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_4.startPoint(), SketchCircle_1.results()[1])
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchCircle_1.results()[1])
+model.do()
+Shell_1 = model.addShell(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")])
+model.end()
+
+model.testNbResults(Shell_1, 1)
+model.testNbSubShapes(Shell_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Shell_1, GeomAPI_Shape.EDGE, [3])
+model.testNbSubShapes(Shell_1, GeomAPI_Shape.VERTEX, [6])
+model.testResultsVolumes(Shell_1, [441.0539215686274])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestShell_WholeSketch_2.py b/src/BuildPlugin/Test/TestShell_WholeSketch_2.py
new file mode 100644 (file)
index 0000000..55a7ad2
--- /dev/null
@@ -0,0 +1,49 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_2.addCircle(-5, 10, 20)
+SketchLine_4 = Sketch_2.addLine(-25, 10, 15, 10)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_4.startPoint(), SketchCircle_1.results()[1])
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchCircle_1.results()[1])
+model.do()
+Shell_1 = model.addShell(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")])
+model.end()
+
+model.testNbResults(Shell_1, 2)
+model.testNbSubShapes(Shell_1, GeomAPI_Shape.FACE, [1, 2])
+model.testNbSubShapes(Shell_1, GeomAPI_Shape.EDGE, [3, 4])
+model.testNbSubShapes(Shell_1, GeomAPI_Shape.VERTEX, [6, 8])
+model.testResultsVolumes(Shell_1, [441.0539215686274, 1256.637061435917])
+
+assert(model.checkPythonDump())
index c9fcd95441450738029112b7f5c66ffbb70084c3..8f086716cd0e9262ea860eb6f0363f8bd8eed06a 100644 (file)
@@ -75,29 +75,33 @@ aSession.finishOperation()
 # Test results
 assert (len(aVertexFeature.results()) == aNumOfPoints)
 
-# Check Vertex feature failed on incorrect input
+# Check Vertex feature correct on a whole sketch
 aSession.startOperation()
 aVertexFeature2 = aPart.addFeature("Vertex")
 aBaseObjectsList = aVertexFeature2.selectionList("base_objects")
 aBaseObjectsList.append(aSketchResult, None)
 aSession.finishOperation()
-assert (len(aVertexFeature2.results()) == 0)
+assert (len(aVertexFeature2.results()) == aNumOfPoints)
 
+# Check Vertex feature failed on incorrect input
 aSession.startOperation()
 aLine = aSketchFeature.addFeature("SketchLine")
 geomDataAPI_Point2D(aLine.attribute("StartPoint")).setValue(0, 0)
 geomDataAPI_Point2D(aLine.attribute("EndPoint")).setValue(100, 100)
 aSession.finishOperation()
 aSession.startOperation()
-aBaseObjectsList.clear()
+aPart.setCurrentFeature(aVertexFeature2, False)
+aSession.finishOperation()
+aSession.startOperation()
+aVertexFeature3 = aPart.addFeature("Vertex")
+aBaseObjectsList = aVertexFeature3.selectionList("base_objects")
 aBaseObjectsList.append(aSketchResult, aLine.lastResult().shape())
 aSession.finishOperation()
-assert (len(aVertexFeature2.results()) == 0)
+assert (len(aVertexFeature3.results()) == 0)
 
 # remove failed feature
 aSession.startOperation()
-aPart.removeFeature(aVertexFeature2)
-aPart.setCurrentFeature(aVertexFeature, True)
+aPart.removeFeature(aVertexFeature3)
 aSession.finishOperation()
 
 from salome.shaper import model
diff --git a/src/BuildPlugin/Test/TestVertex_WholeSketch_1.py b/src/BuildPlugin/Test/TestVertex_WholeSketch_1.py
new file mode 100644 (file)
index 0000000..1bc8fde
--- /dev/null
@@ -0,0 +1,43 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")], False)
+model.end()
+
+model.testNbResults(Vertex_1, 7)
+model.testNbSubShapes(Vertex_1, GeomAPI_Shape.VERTEX, [1, 1, 1, 1, 1, 1, 1])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestVertex_WholeSketch_2.py b/src/BuildPlugin/Test/TestVertex_WholeSketch_2.py
new file mode 100644 (file)
index 0000000..b79a7d9
--- /dev/null
@@ -0,0 +1,43 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")], True)
+model.end()
+
+model.testNbResults(Vertex_1, 9)
+model.testNbSubShapes(Vertex_1, GeomAPI_Shape.VERTEX, [1, 1, 1, 1, 1, 1, 1, 1, 1])
+
+assert(model.checkPythonDump())
index 0bbbbce8fefbae0c8b8572f4b646ef490eddb5c0..fc4734adc5eb577d63ae5c9ec251f71849764313 100644 (file)
@@ -145,7 +145,7 @@ aSession.finishOperation()
 assert (len(aWireFeature2.results()) == 1)
 
 # =============================================================================
-# Test 4. Check Wire feature failed on incorrect input
+# Test 4. Check Wire feature on the whole sketch
 # =============================================================================
 
 aSession.startOperation()
@@ -153,10 +153,15 @@ aWireFeature3 = aPart.addFeature("Wire")
 aBaseObjectsList = aWireFeature3.selectionList("base_objects")
 aBaseObjectsList.append(aSketchResult, None)
 aSession.finishOperation()
-assert (len(aWireFeature3.results()) == 0)
+assert (len(aWireFeature3.results()) == 1)
+
+# =============================================================================
+# Test 5. Check Wire feature failed on incorrect input
+# =============================================================================
 
 aSession.startOperation()
-aBaseObjectsList.clear()
+aWireFeature3 = aPart.addFeature("Wire")
+aBaseObjectsList = aWireFeature3.selectionList("base_objects")
 aShapeExplorer = GeomAPI_ShapeExplorer(aBoxShape, GeomAPI_Shape.VERTEX)
 aShape = aShapeExplorer.current()
 aBaseObjectsList.append(aBoxResult, aShape)
diff --git a/src/BuildPlugin/Test/TestWire_WholeSketch_1.py b/src/BuildPlugin/Test/TestWire_WholeSketch_1.py
new file mode 100644 (file)
index 0000000..e64e662
--- /dev/null
@@ -0,0 +1,44 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Wire_1 = model.addWire(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")], False)
+model.end()
+
+model.testNbResults(Wire_1, 2)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [3, 1])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [6, 2])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestWire_WholeSketch_2.py b/src/BuildPlugin/Test/TestWire_WholeSketch_2.py
new file mode 100644 (file)
index 0000000..e5db2e1
--- /dev/null
@@ -0,0 +1,44 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(0, -20, 45, -15)
+SketchLine_2 = Sketch_1.addLine(45, -15, 10, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(10, 15, 25, -40)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_2.addArc(-5, 10, -5, -10, 15, 10, False)
+model.do()
+Wire_1 = model.addWire(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1"), model.selection("COMPOUND", "Sketch_2")], True)
+model.end()
+
+model.testNbResults(Wire_1, 3)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [3, 2, 1])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [6, 4, 2])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestWire_WholeSketch_3.py b/src/BuildPlugin/Test/TestWire_WholeSketch_3.py
new file mode 100644 (file)
index 0000000..bbc4dac
--- /dev/null
@@ -0,0 +1,48 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(-20.12530657814797, -34.87380706737215, -10.13449613893172, -4.005160196312613)
+SketchLine_2 = Sketch_1.addLine(-15.5320876476665, -20.68212021382587, -37.87121169090271, -18.01751586506584)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchLine_1.result())
+SketchLine_3 = Sketch_1.addLine(-37.87121169090271, -18.01751586506584, -28.23126689685475, -46.70782775211335)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-10.13449613893172, -4.005160196312613, -17.3289483797767, 22.37844327189705)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-17.3289483797767, 22.37844327189705, -36.60883796787262, 2.754269941156556)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-36.60883796787262, 2.754269941156556, -10.13449613893172, -4.005160196312613)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_6.endPoint())
+model.do()
+Wire_1 = model.addWire(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")])
+model.end()
+
+model.testNbResults(Wire_1, 2)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [4, 2])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [8, 4])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestWire_WholeSketch_4.py b/src/BuildPlugin/Test/TestWire_WholeSketch_4.py
new file mode 100644 (file)
index 0000000..fee5553
--- /dev/null
@@ -0,0 +1,48 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(-20.12530657814797, -34.87380706737215, -10.13449613893172, -4.005160196312613)
+SketchLine_2 = Sketch_1.addLine(-15.5320876476665, -20.68212021382587, -37.87121169090271, -18.01751586506584)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchLine_1.result())
+SketchLine_3 = Sketch_1.addLine(-37.87121169090271, -18.01751586506584, -28.23126689685475, -46.70782775211335)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-10.13449613893172, -4.005160196312613, -17.3289483797767, 22.37844327189705)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-17.3289483797767, 22.37844327189705, -36.60883796787262, 2.754269941156556)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-36.60883796787262, 2.754269941156556, -10.13449613893172, -4.005160196312613)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_6.endPoint())
+model.do()
+Wire_1 = model.addWire(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], True)
+model.end()
+
+model.testNbResults(Wire_1, 3)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [3, 2, 2])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [6, 4, 4])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestWire_WholeSketch_5.py b/src/BuildPlugin/Test/TestWire_WholeSketch_5.py
new file mode 100644 (file)
index 0000000..0a07779
--- /dev/null
@@ -0,0 +1,48 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(-20.13297844091623, -34.87132400696332, -10.14115693918956, -4.003004374441855)
+SketchLine_2 = Sketch_1.addLine(-15.36017779982175, -20.12643132586926, -37.81263639928755, -17.52358908612689)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchLine_1.result())
+SketchLine_3 = Sketch_1.addLine(-37.81263639928755, -17.52358908612689, -28.23126689685475, -46.70782775211335)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-10.14115693918956, -4.003004374441855, -17.3289483797767, 22.37844327189705)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-17.3289483797767, 22.37844327189705, -39.00238825664131, 1.575954908729718)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-39.00238825664131, 1.575954908729718, -25.86766799285223, -18.90833134866903)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_2.result())
+model.do()
+Wire_1 = model.addWire(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")])
+model.end()
+
+model.testNbResults(Wire_1, 2)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [4, 2])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [8, 4])
+
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestWire_WholeSketch_6.py b/src/BuildPlugin/Test/TestWire_WholeSketch_6.py
new file mode 100644 (file)
index 0000000..94f7c7a
--- /dev/null
@@ -0,0 +1,48 @@
+# 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 salome.shaper import model
+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"))
+SketchLine_1 = Sketch_1.addLine(-20.13297844091623, -34.87132400696332, -10.14115693918956, -4.003004374441855)
+SketchLine_2 = Sketch_1.addLine(-15.36017779982175, -20.12643132586926, -37.81263639928755, -17.52358908612689)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchLine_1.result())
+SketchLine_3 = Sketch_1.addLine(-37.81263639928755, -17.52358908612689, -28.23126689685475, -46.70782775211335)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-10.14115693918956, -4.003004374441855, -17.3289483797767, 22.37844327189705)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-17.3289483797767, 22.37844327189705, -39.00238825664131, 1.575954908729718)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-39.00238825664131, 1.575954908729718, -25.86766799285223, -18.90833134866903)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_2.result())
+model.do()
+Wire_1 = model.addWire(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], True)
+model.end()
+
+model.testNbResults(Wire_1, 3)
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.EDGE, [5, 1, 2])
+model.testNbSubShapes(Wire_1, GeomAPI_Shape.VERTEX, [10, 2, 4])
+
+assert(model.checkPythonDump())
index a94a22020fe68a429c1a2f4df03ca590e0abd896..2dbc68c5e24571cc085680502d07cb79e4db6bf2 100644 (file)
@@ -14,7 +14,7 @@ The options to create edges:
 
 .. image:: images/edge_by_segments_32x32.png
    :align: left
-**By edges** creates edges using already existing edges in other shapes.
+**By edges** creates edges using already existing edges in other shapes or full sketches.
 
 .. image:: images/edge_by_points_32x32.png
    :align: left
@@ -30,7 +30,8 @@ By edges
 .. centered::
   Create by edges
 
-Select one or several edges in the viewer.
+Select one or several edges in the viewer. Also, the full sketch can be selected. In this case, all edges of the sketch will be processed.
+Checkbox **Compute intersections** forces to split sketch edges in the points of intersection.
 
 **Apply** button creates edges.
 
@@ -38,10 +39,11 @@ Select one or several edges in the viewer.
 
 **TUI Command**:
 
-.. py:function:: model.addEdge(Part_doc, Shapes)
+.. py:function:: model.addEdge(Part_doc, Shapes, Intersect)
 
     :param part: The current part object.
     :param list: A list of shapes.
+    :param bool: Split edges by intersection points. False by default.
     :return: Result object.
 
 Result
index 57f70a2c15041b4621d31907112ea81ac0d0be4c..3552530903fbaabb03e44826089f2f9de1b3ef7a 100644 (file)
@@ -21,6 +21,8 @@ The following property panel will be opened:
   
 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.
+
 **Apply** button creates faces.
 
 **Cancel** button cancels the operation. 
index 4eaf230b39b01c4c6c147321e7f946c1619d2446..9ca142f3a9dfb2a66b420f462443469aae9fdee8 100644 (file)
Binary files a/src/BuildPlugin/doc/images/Edge.png and b/src/BuildPlugin/doc/images/Edge.png differ
index a1650d3ec9ff2d947f9d07eff1d3f6dc87dae9da..0de9852642697979ae258ced6775a8d4dccf4e9d 100644 (file)
Binary files a/src/BuildPlugin/doc/images/Vertex.png and b/src/BuildPlugin/doc/images/Vertex.png differ
index 13ada63fbd5ec2962753526e686494277c0c3655..3248c8c0360d537ed47d344e7b5cd387c6edd79b 100644 (file)
Binary files a/src/BuildPlugin/doc/images/Wire.png and b/src/BuildPlugin/doc/images/Wire.png differ
index cc576b676422768ba1954a8c7bf7acc79336b974..1f212453c3d5e7c658da779321e128ecbeddd6cf 100644 (file)
@@ -18,7 +18,7 @@ The following property panel will be opened:
 .. centered::
   Create a shell
   
-Select one or several faces in the viewer.
+Select one or several faces in the viewer. Additionally, it is allowed to select a whole sketch result from the object browser. In this case, the result shell will contain faces corresponding to all smallest closed contours of the sketch.
 
 **Apply** button creates a shell.
 
index 5b7b1f62bd43c6b521e1938f995e78f5c782cf27..e27d3025f0589f06768ee5d3d5691a923be04a8c 100644 (file)
@@ -18,7 +18,7 @@ The following property panel will be opened:
 .. centered::
   Create vertices
 
-Select one or several vertices in the viewer.
+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.
 
 **Apply** button creates vertices.
 
@@ -26,10 +26,11 @@ Select one or several vertices in the viewer.
 
 **TUI Command**:
 
-.. py:function:: model.addVertex(Part_doc, Shapes)
+.. py:function:: model.addVertex(Part_doc, Shapes, Intersect)
 
     :param part: The current part object.
     :param list: A list of shapes.
+    :param bool: Intersect edges (applicable for sketch only). False by default.
     :return: Result object.
 
 Result
index 32d03e58fe62f36773f649833cc24c97f68ca754..1b9ba515a7af4737cfe1a70c67be7fe587d3678c 100644 (file)
@@ -20,16 +20,20 @@ The following property panel will be opened:
   
 Select one or several edges in the viewer. For automatic selection of a closed contour starting from the selected edge it is necessary to press **Add contour** button.
 
+Moreover, the full sketch can be selected. In this case, a set of wires is composed using edges of the sketch.
+Checkbox **Compute intersections** forces to split sketch edges in the points of intersection.
+
 **Apply** button creates a wire.
 
 **Cancel** button cancels the operation. 
 
 **TUI Command**:
 
-.. py:function:: model.addWire(Part_doc, Shapes)
+.. py:function:: model.addWire(Part_doc, Shapes, Intersect)
 
     :param part: The current part object.
     :param list: A list of shapes.
+    :param bool: Split edges by intersection points. False by default.
     :return: Result object.
 
 Result
index f7ff1144731a23fb064600ec8dc04b8d9e7a32b3..0433b9bb9d2e3b9aa3fbfeef6ea8d01e6ffa517e 100644 (file)
@@ -2,12 +2,14 @@
   <toolbox id="creation_method">
     <box id="by_segments" title="By segments" icon="icons/Build/edge_by_segments_32x32.png">
       <multi_selector id="base_objects"
-                      label="Edges:"
+                      label="Edges or sketches:"
                       tooltip="Select edges on sketch or edges objects."
                       shape_types="edges"
                       concealment="true">
-        <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge"/>
+        <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,compound"/>
       </multi_selector>
+      <boolvalue id="intersect" label="Compute intersections" tooltip="Divide sketch edges in intersection points." default="false"/>
+      <validator id="BuildPlugin_ValidatorBaseForWire" parameters="base_objects,edge"/>
     </box>
     <box id="by_points" title="By two points" icon="icons/Build/edge_by_points_32x32.png">
       <shape_selector id="first_point"
index e61ce59d10aec18995e763c482cba998b6eb7049..78235132d23628d8e8d365f18122d84607cffd7e 100644 (file)
@@ -4,7 +4,7 @@
                   tooltip="Select edges, wires or faces."
                   shape_types="edges wires faces"
                   concealment="true">
-    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire,face"/>
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire,face,compound"/>
   </multi_selector>
   <validator id="BuildPlugin_ValidatorBaseForFace" parameters="base_objects"/>
 </source>
index 50575ff1e55873270f40079f3eb92f6496f76404..cb44a7c302a477335495fccae7d3444adad05fa5 100644 (file)
@@ -4,6 +4,6 @@
                   tooltip="Select faces or shells objects."
                   shape_types="faces shells"
                   concealment="true">
-    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="face,shell"/>
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="face,shell,compound"/>
   </multi_selector>
 </source>
index 77af0a18f5aeec634dc2270fd1abfd3fdace7e04..14ef22749b1520dfee0f0a2a2f3aea9b5e0d822f 100644 (file)
@@ -1,8 +1,10 @@
 <source>
   <multi_selector id="base_objects"
-                  label="Vertices:"
-                  tooltip="Select vertices on sketch or vertex objects."
-                  shape_types="vertices"
+                  label="Vertices and sketches:"
+                  tooltip="Select vertices or sketch objects or features."
+                  shape_types="vertices objects"
                   concealment="true">
+    <validator id="BuildPlugin_ValidatorBaseForVertex"/>
   </multi_selector>
+  <boolvalue id="intersect" label="Compute intersections" tooltip="Compute intersections of all sketch edges." default="false"/>
 </source>
index 96067ebe6d9917d26bfda0e59bbfe7d2ddea87bc..d0fca7a69c0bbf5717e402e4399b7a8b92b2f60f 100644 (file)
@@ -4,11 +4,12 @@
                   tooltip="Select edges on sketch, edges or wires objects."
                   shape_types="edges wires"
                   concealment="true">
-    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire"/>
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire,compound"/>
   </multi_selector>
+  <boolvalue id="intersect" label="Compute intersections" tooltip="Divide sketch edges in intersection points." default="false"/>
   <action id="add_contour"
           label="Add contour"
           tooltip="Adds to the list of segments other segments of the sketcher
                    connected to the already selected ones to create a closed contour."/>
-  <validator id="BuildPlugin_ValidatorBaseForWire" parameters="base_objects"/>
+  <validator id="BuildPlugin_ValidatorBaseForWire" parameters="base_objects,wire"/>
 </source>
index 619c42de6284887177ffd626120824aadfd20f31..a8770cb7c7059cf0a694b4f22f6fc9b1433f060e 100644 (file)
@@ -68,6 +68,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     CollectionPlugin_msg_en.ts
+    CollectionPlugin_msg_fr.ts
 )
 
 # sources / moc wrappings
@@ -157,4 +158,9 @@ ADD_UNIT_TESTS(
                TestGroupWholeResult1.py
                TestGroupWholeResult2.py
                Test3031.py
+               TestGroupWholeFeature1.py
+               TestGroupWholeFeature2.py
+               TestGroupMoveAndSplit1.py
+               TestGroupMoveAndSplit2.py
+               TestGroupMoveAndSplit3.py
 )
index 82926ab21921946ac76ac567b84f900ec9eb16bb..57a2804e3e15aab47a86a9a2e90cab0138c31f4a 100644 (file)
 #include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_ResultGroup.h>
+#include <ModelAPI_Tools.h>
+#include <sstream>
 
 CollectionPlugin_Group::CollectionPlugin_Group()
 {
@@ -44,3 +47,97 @@ void CollectionPlugin_Group::execute()
     setResult(aGroup);
   }
 }
+
+// returns name with suffix, not existing in the existing set
+static std::string findName(
+  const std::string theOrigin, int& theSuffix, std::set<std::string>& theExisting)
+{
+  std::string aRes;
+  do {
+    std::ostringstream aName;
+    aName<<theOrigin<<"_"<<theSuffix;
+    aRes = aName.str();
+    theSuffix++;
+  } while(theExisting.count(aRes));
+  theExisting.insert(aRes);
+  return aRes;
+
+}
+
+bool CollectionPlugin_Group::customAction(const std::string& theActionId)
+{
+  if (theActionId == "split") {
+    DocumentPtr aDoc = document();
+    // collect all existing names of features to give unique names
+    std::set<std::string> aFeatNames, aResNames;
+    std::list<FeaturePtr> allFeat = aDoc->allFeatures();
+    std::list<FeaturePtr>::iterator allFeatIter = allFeat.begin();
+    for(; allFeatIter != allFeat.end(); allFeatIter++) {
+      FeaturePtr aFeat = *allFeatIter;
+      if (aFeat->data().get() && aFeat->data()->isValid()) {
+        aFeatNames.insert(aFeat->name());
+        if (aFeat->getKind() == ID() && aFeat->data().get() && aFeat->data()->isValid()) {
+           std::list<ResultPtr>::const_iterator aRess = aFeat->results().cbegin();
+           for(; aRess != aFeat->results().cend(); aRess++) {
+             ResultPtr aRes = *aRess;
+             if (aRes->data().get() && aRes->data()->isValid()) {
+               aResNames.insert(aRes->data()->name());
+             }
+           }
+        }
+      }
+    }
+
+    AttributeSelectionListPtr aList = selectionList(LIST_ID());
+    std::set<int> aRemoved;
+    bool aStay = false; // to indicate that the good attribute found stays in the list
+    int anIndex = 1; // index of the name assigned to group-feature and result
+    // added in the order: 3 2 1 orig=0, so, keep the results to give names later
+    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
+        aRemoved.insert(aNext);
+        continue;
+      }
+      if (!aStay) {
+        aStay = true;
+        continue;
+      }
+      aRemoved.insert(aNext);
+      FeaturePtr aNew = aDoc->addFeature(ID(), false);
+      AttributeSelectionListPtr aNewList = aNew->selectionList(LIST_ID());
+      aNewList->setSelectionType(aList->selectionType());
+      aNewList->append(anOldAttr->contextObject(), anOldAttr->value());
+      aNew->execute();
+      aResults.push_front(aNew); // to keep the order
+    }
+    aResults.push_back(data()->owner());
+    // remove all selections except the first
+    aList->remove(aRemoved);
+    // set names
+    if (aResults.size() > 1) { // rename if there are new groups appeared only
+      std::list<ObjectPtr>::iterator aResIter = aResults.begin();
+      for(int aSuffix = 1; aResIter != aResults.end(); aResIter++) {
+        FeaturePtr aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(*aResIter);
+        aFeat->data()->setName(findName(name(), aSuffix, aFeatNames));
+        if (!aFeat->results().empty() && !results().empty()) {
+          int aResSuf = aSuffix - 1;
+          std::string aResName = findName(firstResult()->data()->name(), aResSuf, aResNames);
+          aFeat->firstResult()->data()->setName(aResName);
+          ModelAPI_Tools::copyVisualizationAttrs(firstResult(), aFeat->firstResult());
+        }
+      }
+      // remove also filters if split performed
+      FiltersFeaturePtr aFilters = aList->filters();
+      if (aFilters.get()) {
+        std::list<std::string> aFiltersList = aFilters->filters();
+        std::list<std::string>::iterator aFilterName = aFiltersList.begin();
+        for(; aFilterName != aFiltersList.end(); aFilterName++) {
+          aFilters->removeFilter(*aFilterName);
+        }
+      }
+    }
+  }
+  return true;
+}
index 0d61046e3b5dfe003c37fbe7b5b8e93c36a510d1..3c1dd0d165a3a020314170a8ee3119868c96f03b 100644 (file)
@@ -66,6 +66,8 @@ class CollectionPlugin_Group : public ModelAPI_Feature
   /// Use plugin manager for features creation
   CollectionPlugin_Group();
 
+  /// Used for the split action of the group (Move to the end and split)
+  COLLECTIONPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId);
 };
 
 #endif
diff --git a/src/CollectionPlugin/CollectionPlugin_msg_fr.ts b/src/CollectionPlugin/CollectionPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..2cdd311
--- /dev/null
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Field</source>
+      <translation>Champ</translation>
+    </message>
+    <message>
+      <source>Group</source>
+      <translation>Groupe</translation>
+    </message>
+    <message>
+      <source>Group Addition</source>
+      <translation>Addition de groupes</translation>
+    </message>
+    <message>
+      <source>Group Intersection</source>
+      <translation>Intersection de groupes</translation>
+    </message>
+    <message>
+      <source>Group Substraction</source>
+      <translation>Soustraction de groupes</translation>
+    </message>
+  </context>
+
+  <!-- Field -->
+  <context>
+    <name>Field</name>
+    <message>
+      <source>Create fields for selected shapes</source>
+      <translation>Créer des champs pour les formes sélectionnées</translation>
+    </message>
+    <message>
+      <source>Field</source>
+      <translation>Champ</translation>
+    </message>
+  </context>
+  <context>
+    <name>Field:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "components_names" is not initialized.</source>
+      <translation>Les composants ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>Field:CollectionPlugin_FieldValidator</name>
+    <message>
+      <source>Selection list is not initialized</source>
+      <translation>La liste de sélection n&apos;est pas initialisée</translation>
+    </message>
+  </context>
+
+  <!-- Group -->
+  <context>
+    <name>Group</name>
+    <message>
+      <source>Create named collection of geometry entities</source>
+      <translation>Créer une collection nommée d&apos;entités géométriques</translation>
+    </message>
+    <message>
+      <source>Group</source>
+      <translation>Groupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Group:group_list</name>
+    <message>
+      <source>Select a set of objects</source>
+      <translation>Sélectionnez un ensemble d&apos;objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Group:group_list:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Context is empty.</source>
+      <translation>L&apos;objet sélectionné a un contexte vide.</translation>
+    </message>
+    <message>
+      <source>Error: Result construction selected.</source>
+      <translation>Constructions non autorisées pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Group:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "group_list" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Group:name</name>
+    <message>
+      <source>Name</source>
+      <translation>Nom</translation>
+    </message>
+    <message>
+      <source>Please input the group name</source>
+      <translation>S&apos;il vous plaît entrer le nom du groupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Group:group_list</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ensemble d&apos;objets.</translation>
+    </message>
+  </context>
+
+  <!-- GroupAddition -->
+  <context>
+    <name>GroupAddition</name>
+    <message>
+      <source>Group Addition</source>
+      <translation>Addition de groupes</translation>
+    </message>
+    <message>
+      <source>Join several groups to single group</source>
+      <translation>Joindre plusieurs groupes pour former un seul groupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupAddition:group_list</name>
+    <message>
+      <source>Base groups:</source>
+      <translation>Groupes de base:</translation>
+    </message>
+    <message>
+      <source>Select a set of groups</source>
+      <translation>Sélectionnez un ensemble de groupes</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupAddition:name</name>
+    <message>
+      <source>Name</source>
+      <translation>Nom</translation>
+    </message>
+    <message>
+      <source>Please input the group name</source>
+      <translation>S&apos;il vous plaît entrer le nom du groupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupAddition:group_list</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ensemble de groupes.</translation>
+    </message>
+  </context>
+
+  <!-- GroupIntersection -->
+  <context>
+    <name>GroupIntersection</name>
+    <message>
+      <source>Get elements existing in all groups</source>
+      <translation>Obtenir les éléments existants dans tous les groupes</translation>
+    </message>
+    <message>
+      <source>Group Intersection</source>
+      <translation>Intersection de groupes</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupIntersection:EmptyResult</name>
+    <message>
+      <source>Error: Empty result.</source>
+      <translation>Erreur : résultat vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupIntersection:group_list</name>
+    <message>
+      <source>Base groups:</source>
+      <translation>Groupes de base:</translation>
+    </message>
+    <message>
+      <source>Select a set of groups</source>
+      <translation>Sélectionnez un ensemble de groupes</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupIntersection:name</name>
+    <message>
+      <source>Name</source>
+      <translation>Nom</translation>
+    </message>
+    <message>
+      <source>Please input the group name</source>
+      <translation>S&apos;il vous plaît entrer le nom du groupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupIntersection:group_list</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ensemble de groupes.</translation>
+    </message>
+  </context>
+
+  <!-- GroupSubstraction -->
+  <context>
+    <name>GroupSubstraction</name>
+    <message>
+      <source>Exclude elements existing tool groups</source>
+      <translation>Exclure des éléments des groupes d&apos;outils existants</translation>
+    </message>
+    <message>
+      <source>Group Substraction</source>
+      <translation>Soustraction de groupes</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupSubstraction:group_list</name>
+    <message>
+      <source>Main groups:</source>
+      <translation>Groupes principaux:</translation>
+    </message>
+    <message>
+      <source>Select a set of groups</source>
+      <translation>Sélectionnez un ensemble de groupes</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupSubstraction:name</name>
+    <message>
+      <source>Name</source>
+      <translation>Nom</translation>
+    </message>
+    <message>
+      <source>Please input the group name</source>
+      <translation>S&apos;il vous plaît entrer le nom du groupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupSubstraction:tools_list</name>
+    <message>
+      <source>Select a set of groups</source>
+      <translation>Sélectionnez un ensemble de groupes</translation>
+    </message>
+    <message>
+      <source>Tool groups:</source>
+      <translation>Groupes d&apos;outils:</translation>
+    </message>
+  </context>
+  <context>
+    <name>GroupSubstraction:group_list</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ensemble de groupes.</translation>
+    </message>
+  </context>
+
+</TS>
diff --git a/src/CollectionPlugin/Test/TestGroupMoveAndSplit1.py b/src/CollectionPlugin/Test/TestGroupMoveAndSplit1.py
new file mode 100644 (file)
index 0000000..d468c4d
--- /dev/null
@@ -0,0 +1,63 @@
+# 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
+#
+
+# Check the specification case of move to the end and split (#3059)
+
+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()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 12, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(33.32502963835739, 19.24021483244179, 5)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 5)
+SketchLine_1 = Sketch_1.addLine(0, 0, 33.32502963835739, 19.24021483244179)
+SketchLine_1.setAuxiliary(True)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchPoint_1.result())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_1.endPoint())
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_2.result(), SketchLine_1.result(), 30)
+Extrusion_1.setNestedSketch(Sketch_1)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Extrusion_1_1/To_Face")])
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OZ"), 12)
+model.do()
+Part_1_doc.moveFeature(Group_1.feature(), AngularCopy_1.feature(), True)
+model.end()
+
+# must be created 12 groups of faces, 12 results
+assert(Part_1_doc.size("Groups") == 12)
+
+for i in range(12):
+  resShape = modelAPI_Result(Part_1_doc.object("Groups", i)).shape()
+  assert(not resShape.isNull())
+  # the group result is a compund, check that this is a compound of one face
+  aShapeExplorer = GeomAPI_ShapeExplorer(resShape, GeomAPI_Shape.FACE)
+  assert(aShapeExplorer.more())
+  assert(aShapeExplorer.current().isFace())
+  aShapeExplorer.next()
+  assert(not aShapeExplorer.more())
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMoveAndSplit2.py b/src/CollectionPlugin/Test/TestGroupMoveAndSplit2.py
new file mode 100644 (file)
index 0000000..c39ae45
--- /dev/null
@@ -0,0 +1,95 @@
+# 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
+#
+
+# Check the movement to the end and split: move to intermediate position, no duplicates appeared
+
+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"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 10)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "Edges", [model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]")])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 5, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]"), False)
+SketchCircle_2 = SketchProjection_2.createdFeature()
+SketchCircle_3 = Sketch_2.addCircle(0, 10, 3)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchCircle_2.results()[1], SketchCircle_3.center())
+SketchCircle_4 = Sketch_2.addCircle(0, -10, 3)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchCircle_2.results()[1], SketchCircle_4.center())
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OY"), True)
+SketchLine_1 = SketchProjection_3.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchCircle_3.center(), SketchLine_1.result())
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchCircle_4.center(), SketchLine_1.result())
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_3.results()[1], 3)
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchCircle_3.results()[1], SketchCircle_4.results()[1])
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+
+ExtrusionCut_2 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 3, [model.selection("SOLID", "ExtrusionCut_1_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionCut_1_1/Modified_Face&Extrusion_1_1/To_Face"))
+SketchLine_2 = Sketch_3.addLine(10, 2, -10, 2)
+SketchLine_3 = Sketch_3.addLine(-10, 2, -10, -2)
+SketchLine_4 = Sketch_3.addLine(-10, -2, 10, -2)
+SketchLine_5 = Sketch_3.addLine(10, -2, 10, 2)
+SketchConstraintCoincidence_6 = Sketch_3.setCoincident(SketchLine_5.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_7 = Sketch_3.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_8 = Sketch_3.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_9 = Sketch_3.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintHorizontal_1 = Sketch_3.setHorizontal(SketchLine_2.result())
+SketchConstraintVertical_1 = Sketch_3.setVertical(SketchLine_3.result())
+SketchConstraintHorizontal_2 = Sketch_3.setHorizontal(SketchLine_4.result())
+SketchConstraintVertical_2 = Sketch_3.setVertical(SketchLine_5.result())
+SketchProjection_4 = Sketch_3.addProjection(model.selection("EDGE", "([ExtrusionCut_1_1/Modified_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face])2(ExtrusionCut_1_1/Generated_Edge&ExtrusionCut_1_1/From_Face_1)2([ExtrusionCut_1_1/Modified_Face&Extrusion_1_1/To_Face][ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchCircle_4_2])2"), False)
+SketchArc_1 = SketchProjection_4.createdFeature()
+SketchConstraintTangent_1 = Sketch_3.setTangent(SketchLine_5.result(), SketchArc_1.results()[1])
+SketchProjection_5 = Sketch_3.addProjection(model.selection("EDGE", "([ExtrusionCut_1_1/Modified_Face&Extrusion_1_1/To_Face][ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchCircle_4_2])(ExtrusionCut_1_1/Generated_Edge&ExtrusionCut_1_1/From_Face_3)2(ExtrusionCut_1_1/Generated_Edge&ExtrusionCut_1_1/From_Face_2)2([ExtrusionCut_1_1/Generated_Face&Sketch_2/SketchCircle_4_2][ExtrusionCut_1_1/Modified_Face&ExtrusionCut_1_1/From_Face_3])2"), False)
+SketchArc_2 = SketchProjection_5.createdFeature()
+SketchConstraintTangent_2 = Sketch_3.setTangent(SketchArc_2.results()[1], SketchLine_3.result())
+SketchConstraintDistanceVertical_1 = Sketch_3.setVerticalDistance(SketchAPI_Arc(SketchArc_1).center(), SketchLine_2.startPoint(), 2)
+SketchConstraintDistanceVertical_2 = Sketch_3.setVerticalDistance(SketchAPI_Arc(SketchArc_1).center(), SketchLine_4.endPoint(), 2)
+ExtrusionCut_2.setNestedSketch(Sketch_3)
+model.do()
+# move only after the first extrusion-cut
+Part_1_doc.setCurrentFeature(ExtrusionCut_1.feature(), True)
+model.do()
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature(), True)
+model.end()
+assert(Part_1_doc.size("Groups") == 3) # 3 edges in groups results
+
+# check that simple move to the end provides 4 edges (no duplicates)
+model.undo()
+model.undo()
+
+model.begin()
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_2.feature(), True)
+model.end()
+assert(Part_1_doc.size("Groups") == 4) # 4 edges in groups results
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMoveAndSplit3.py b/src/CollectionPlugin/Test/TestGroupMoveAndSplit3.py
new file mode 100644 (file)
index 0000000..0472376
--- /dev/null
@@ -0,0 +1,76 @@
+# 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
+#
+
+# Check the movement to the end and split: whole results, check names of splitted results and groups
+
+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(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-8.333743842364534, 20.52339901477833, -20.15024630541872, 20.52339901477833)
+SketchLine_2 = Sketch_1.addLine(-20.15024630541872, 20.52339901477833, -20.15024630541872, 3.980295566502462)
+SketchLine_3 = Sketch_1.addLine(-20.15024630541872, 3.980295566502462, -8.333743842364534, 3.980295566502462)
+SketchLine_4 = Sketch_1.addLine(-8.333743842364534, 3.980295566502462, -8.333743842364534, 20.52339901477833)
+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(5.721674876847291, 12.81157635467982, 6.421166795138789)
+Extrusion_1.setNestedSketch(Sketch_1)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_1"), model.selection("SOLID", "Extrusion_1_2")])
+Group_1.setName("GroupResult")
+Group_1.result().setName("GroupResult")
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_5 = Sketch_2.addLine(3.924377723198604, 15.23693857548147, -14.36967929032953, 15.23693857548147)
+SketchLine_6 = Sketch_2.addLine(-14.36967929032953, 15.23693857548147, -14.36967929032953, 11.61585476914922)
+SketchLine_7 = Sketch_2.addLine(-14.36967929032953, 11.61585476914922, 3.924377723198604, 11.61585476914922)
+SketchLine_8 = Sketch_2.addLine(3.924377723198604, 11.61585476914922, 3.924377723198604, 15.23693857548147)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_8.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_6.result())
+SketchConstraintHorizontal_4 = Sketch_2.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_4 = Sketch_2.setVertical(SketchLine_8.result())
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Sketch_2/Face-SketchLine_5r-SketchLine_6f-SketchLine_7f-SketchLine_8f_wire")], model.selection(), 2, 5)
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1"), model.selection("SOLID", "Extrusion_2_1")], keepSubResults = True)
+model.do()
+Part_1_doc.moveFeature(Group_1.feature(), Fuse_1.feature(), True)
+model.end()
+
+assert(Part_1_doc.size("Groups") == 2) # 2 results because initially 2 results were selected
+
+# check names of results
+from ModelAPI import *
+res1 = modelAPI_Result(Part_1_doc.object("Groups", 0))
+assert(res1.data().name() == "GroupResult_1")
+res2 = modelAPI_Result(Part_1_doc.object("Groups", 1))
+assert(res2.data().name() == "GroupResult_2")
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupWholeFeature1.py b/src/CollectionPlugin/Test/TestGroupWholeFeature1.py
new file mode 100644 (file)
index 0000000..ef512a9
--- /dev/null
@@ -0,0 +1,65 @@
+# 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
+#
+
+# Tests python API for the whole feature (all results) in group selection
+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(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Group_1 = model.addGroup(Part_1_doc, "Vertices", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_1.setName("CylVertices")
+Group_1.result().setName("CylVertices")
+Group_2 = model.addGroup(Part_1_doc, "Edges", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_2.setName("CylEdges")
+Group_2.result().setName("CylEdges")
+Group_3 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_3.setName("CylFaces")
+Group_3.result().setName("CylFaces")
+Group_4 = model.addGroup(Part_1_doc, "Solids", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_4.setName("CylSolid")
+Group_4.result().setName("CylSolid")
+model.end()
+
+from GeomAPI import GeomAPI_ShapeIterator
+
+# group variable, type of selection, number of expected sub-shapes, sub-shapes type
+test_list = [(Group_1, "Vertices", 2, 7), (Group_2, "Edges", 3, 6), (Group_3, "Faces", 3, 4), (Group_4, "Solids", 1, 2)]
+for test in test_list:
+  assert(test[0].groupList().selectionType() == test[1])
+  assert(len(test[0].results()) == 1)
+  assert(test[0].result().shapeType() == "COMPOUND")
+
+  aResultShape = test[0].feature().firstResult().shape()
+  anIter = GeomAPI_ShapeIterator(aResultShape)
+  aNum = 0
+  while anIter.more():
+    aShape = anIter.current()
+    assert(aShape.shapeType() == test[3])
+    aNum = aNum + 1
+    anIter.next()
+
+  assert(aNum == test[2])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupWholeFeature2.py b/src/CollectionPlugin/Test/TestGroupWholeFeature2.py
new file mode 100644 (file)
index 0000000..8229de9
--- /dev/null
@@ -0,0 +1,58 @@
+# 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
+#
+
+# Tests python API for the whole feature (all results) in group selection
+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(-12, 15, -12, -15)
+SketchLine_2 = Sketch_1.addLine(-12, -15, 12, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(12, 15, 12, -15)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(12, -15, -12, 15)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_4f"), model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "Vertices", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+model.end()
+
+# check the group result: it must be compound of 12 vertices
+assert(Group_1.groupList().selectionType() == "Vertices")
+assert(len(Group_1.results()) == 1)
+assert(Group_1.result().shapeType() == "COMPOUND")
+
+from GeomAPI import GeomAPI_ShapeIterator
+aResultShape = Group_1.feature().firstResult().shape()
+anIter = GeomAPI_ShapeIterator(aResultShape)
+aNum = 0
+while anIter.more():
+  anEdge = anIter.current()
+  assert(anEdge.isVertex())
+  aNum = aNum + 1
+  anIter.next()
+
+assert(aNum == 12)
+
+assert(model.checkPythonDump())
index a02f0bf2fb81c8b901d93f71b50aa83efe1d1043..ea913123b87290bd257e49b2f009961753ef997d 100644 (file)
@@ -18,7 +18,8 @@
         tooltip="Create named collection of geometry entities"
         icon="icons/Collection/shape_group.png"
         apply_continue="true"
-        helpfile="groupFeature.html">
+        helpfile="groupFeature.html"
+        hidefaces_panel="true">
         <source path="group_widget.xml"/>
       </feature>
 
index 47baeae2ee4da30faf6e77d3bb567fcf84bdd26e..e21246920295d4be1c18071bb24a803ed95f0daf 100644 (file)
@@ -40,6 +40,8 @@ Config_FeatureMessage::Config_FeatureMessage(const Events_ID theId, const void*
   myModal = false;
   myIsTitleInToolbar = true;
   myIsApplyContinue = false;
+  myHideFacesPanel = false;
+  myAbortConfirmation = true;
 }
 
 Config_FeatureMessage::~Config_FeatureMessage()
@@ -238,3 +240,24 @@ void Config_FeatureMessage::setTitleInToolbar(bool theValue)
 {
   myIsTitleInToolbar = theValue;
 }
+
+bool Config_FeatureMessage::isHideFacesPanel() const
+{
+  return myHideFacesPanel;
+}
+
+
+void Config_FeatureMessage::setHideFacesPanel(bool theValue)
+{
+  myHideFacesPanel = theValue;
+}
+
+bool Config_FeatureMessage::isAbortConfirmation() const
+{
+  return myAbortConfirmation;
+}
+
+void Config_FeatureMessage::setAbortConfirmation(bool theValue)
+{
+  myAbortConfirmation = theValue;
+}
index a027bec60b1df6e551dfa516bfba51af2f57ac00..8228256a8b065c06d50c19c2a565030bca14cb7a 100644 (file)
@@ -55,6 +55,8 @@ class Config_FeatureMessage : public Events_Message
   bool myModal;     ///<True if the feature has to be represented by modal dialog box
   bool myIsAutoPreview; ///< Preview computation is performed automatically
   bool myIsTitleInToolbar; ///< False if title should not be displayed in the toolbar
+  bool myHideFacesPanel; ///< Show or Hide HideFaces panel. By default is False
+  bool myAbortConfirmation; ///< Ask confirmation of abort of the feature from user
 
   /// True if the feature can have Apply/Continue button in its property panel
   bool myIsApplyContinue;
@@ -120,6 +122,9 @@ class Config_FeatureMessage : public Events_Message
   CONFIG_EXPORT bool isAutoPreview() const;
   /// If true - title should normally be displayed in the toolbar
   CONFIG_EXPORT bool isTitleInToolbar() const;
+  /// If true - then HideFaces panel has to be shown
+  CONFIG_EXPORT bool isHideFacesPanel() const;
+  CONFIG_EXPORT bool isAbortConfirmation() const;
 
   ///Set feature's Id
   CONFIG_EXPORT void setId(const std::string& id);
@@ -157,6 +162,10 @@ class Config_FeatureMessage : public Events_Message
   CONFIG_EXPORT void setModal(bool isModal);
   ///Set flag to display title in toolbar
   CONFIG_EXPORT void setTitleInToolbar(bool theValue);
+  ///Set flag to display title in toolbar
+  CONFIG_EXPORT void setHideFacesPanel(bool theValue);
+  ///Set flag to display title in toolbar
+  CONFIG_EXPORT void setAbortConfirmation(bool theValue);
   ///Set Apply/Continue state;
   ///If true - the feature can have Apply/Continue button in its property panel
   CONFIG_EXPORT void setApplyContinue(bool isModal);
index 7d93e060e7dc85163cad07be11d650a6b2444239..7254b5577d4b6ef91f7369d3e4d493c001ba3ea8 100644 (file)
@@ -179,10 +179,16 @@ void Config_FeatureReader::fillFeature(xmlNodePtr theFeatureNode,
   if (!aHelpFile.empty())
     outFeatureMessage->setHelpFileName(myLibraryName + "/" + aHelpFile);
 
-  if (isInternal) {
-    //Internal feature has no visual representation.
-    return;
-  }
+  bool isHideFaces = getBooleanAttribute(theFeatureNode, HIDEFACES_PANEL, false);
+  outFeatureMessage->setHideFacesPanel(isHideFaces);
+
+  bool isConfirmAbort = getBooleanAttribute(theFeatureNode, ABORT_CONFIRMATION, true);
+  outFeatureMessage->setAbortConfirmation(isConfirmAbort);
+
+  //if (isInternal) {
+  //  //Internal feature has no visual representation.
+  //  return;
+  //}
 
   std::string aText = Config_Translator::translate(anId, getProperty(theFeatureNode, FEATURE_TEXT));
   outFeatureMessage->setText(aText);
index 0a8f4aba4f06bbc7a154385ca958a818146a6951..c0e2fa4b0f920d69c7906d2da8f4cca091005a83 100644 (file)
@@ -35,6 +35,7 @@ const static char* PROPERTY_PANEL_ID = "property_panel_id";
 
 // Widgets
 const static char* WDG_INFO = "label";
+const static char* WDG_UNDOLABEL = "undo_label";
 const static char* WDG_DOUBLEVALUE = "doublevalue";
 const static char* WDG_DOUBLEVALUELABEL = "labelvalue";
 const static char* WDG_INTEGERVALUE = "integervalue";
@@ -77,6 +78,8 @@ const static char* GROUP_TOOLBAR = "toolbar";
 const static char* FEATURE_ICON = "icon";
 const static char* FEATURE_TEXT = "title";
 const static char* HELP_FILE = "helpfile";
+const static char* ABORT_CONFIRMATION = "abort_confirmation";
+const static char* HIDEFACES_PANEL = "hidefaces_panel";
 const static char* FEATURE_KEYSEQUENCE = "keysequence";
 const static char* FEATURE_NESTED = "nested";
 const static char* FEATURE_WHEN_NESTED = "when_nested";
@@ -95,6 +98,7 @@ const static char* ATTR_TOOLTIP = FEATURE_TOOLTIP;
 const static char* ATTR_ICON = FEATURE_ICON;
 const static char* ATTR_LABEL = "label";
 const static char* ATTR_STYLE_SHEET = "styleSheet";
+const static char* ATTR_HTML_STYLE = "isHTML";
 const static char* ATTR_DEFAULT = "default";
 const static char* ATTR_INTERNAL = "internal";
 const static char* ATTR_OBLIGATORY = "obligatory";
@@ -104,6 +108,7 @@ const static char* ATTR_GREED = "greed";
 const static char* ATTR_MODIFIED_IN_EDIT = "modified_in_edit";
 const static char* ATTR_MAIN_ARG = "main_argument";
 const static char* ATTR_GEOMETRICAL_SELECTION = "geometrical_selection";
+const static char* ATTR_VISUAL_CHANGED = "change_visual_attributes";
 
 
 // WDG_INFO properties
index 8f3a826af57d208f111fce64551b01e245b9e8db..055097cb7a2e9f1ea382950e340a0e451e489cee 100644 (file)
@@ -77,7 +77,6 @@ class Config_WidgetAPI
    */
   CONFIG_EXPORT bool getBooleanAttribute(const char* theAttributeName, bool theDefault) const;
 
- protected:
   /// These fields are accessible for ModuleBase_WidgetFactory only
   CONFIG_EXPORT Config_WidgetAPI(std::string theRawXml);
   //! Pass to the next (sibling) node of widget's xml definition. If impossible, returns false
index 7d588bfa1c6ed508b3620a67755b9c73197b9ea5..17a885057e9dfb3f69597e62025ea52b74b426b0 100644 (file)
@@ -29,7 +29,7 @@ SET(XML_RESOURCES
 )
 
 SET(TEXT_RESOURCES
-#    ConnectorPlugin_msg_fr.ts
+    ConnectorPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
diff --git a/src/ConnectorPlugin/ConnectorPlugin_msg_fr.ts b/src/ConnectorPlugin/ConnectorPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..b8e1535
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+  <context>
+    <name>ExportToGEOM</name>
+    <message>
+      <source>Export all results and groups into GEOM module</source>
+      <translation>Exporter tous les résultats et groupes dans le module GEOM</translation>
+    </message>
+    <message>
+      <source>Export to GEOM</source>
+      <translation>Exporter vers GEOM</translation>
+    </message>
+  </context>
+</TS>
index b3fd7497ab883a55a07ae8ceba9d952718d2efc9..391b0ee0437f6d2325e7aa0927908b3de9a7af2a 100644 (file)
@@ -46,6 +46,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
   ConstructionPlugin_msg_en.ts
+  ConstructionPlugin_msg_fr.ts
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts b/src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..c4b158d
--- /dev/null
@@ -0,0 +1,1215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Construction</source>
+      <translation>Construction</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;axe par face fait référence à un type de forme non acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>L&apos;axe par face ne peut être créé que sur une face</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>L&apos;axe par face ne peut être créé que sur une face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>L&apos;axe par face ne peut être créé que sur une face cylindrique</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>L&apos;axe par une face ne peut pas être créé sur la face sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "FirstPoint" is not initialized.</source>
+      <translation>Sélectionnez le premier point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "SecondPoint" is not initialized.</source>
+      <translation>Sélectionnez le deuxième point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "CylindricalFace" is not initialized.</source>
+      <translation>Sélectionnez la face cylindrique</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Seule la sélection d&apos;attribut peut être utilisée pour le premier point, pas %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le premier point fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>Uses composite construction feature without sub-features.</source>
+      <translation>Le premier point utilise une fonctionnalité de construction composite sans sous-fonctionnalités</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le premier point ne contient pas d&apos;élément avec un type de forme acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le premier point ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le premier point fait référence à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Le premier point de type %1 n&apos;est pas pris en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le premier point fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le premier point fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Le premier point fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Seule la sélection d&apos;attribut peut être utilisée pour le deuxième point, pas %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le deuxième point fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>Uses composite construction feature without sub-features.</source>
+      <translation>Le deuxième point utilise une fonctionnalité de construction composite sans sous-fonctionnalités</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le deuxième point ne contient pas d&apos;élément de type de forme acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le deuxième point ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPointGeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le deuxième point fait référence à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Le deuxième point de type %1 n&apos;est pas pris en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le deuxième point fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le deuxième point fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Le deuxième point fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint:GeomValidators_DifferentShapes</name>
+    <message>
+      <source>The feature uses equal shapes.</source>
+      <translation>Les points d&apos;axe doivent être différents</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:DZ</name>
+    <message>
+      <source>DZ </source>
+      <translation>DZ </translation>
+    </message>
+    <message>
+      <source>Z dimension</source>
+      <translation>Dimension Z</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint</name>
+    <message>
+      <source>First point</source>
+      <translation>Premier point</translation>
+    </message>
+    <message>
+      <source>Select a first point</source>
+      <translation>Sélectionnez un premier point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:SecondPoint</name>
+    <message>
+      <source>Second point</source>
+      <translation>Deuxième point</translation>
+    </message>
+    <message>
+      <source>Select a second point</source>
+      <translation>Sélectionnez un deuxième point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:line</name>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Select line.</source>
+      <translation>Sélectionnez une ligne.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:line:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:offset1</name>
+    <message>
+      <source>Distance </source>
+      <translation>Distance </translation>
+    </message>
+    <message>
+      <source>Distance value</source>
+      <translation>Distance</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:offset2</name>
+    <message>
+      <source>Distance </source>
+      <translation>Distance </translation>
+    </message>
+    <message>
+      <source>Distance value</source>
+      <translation>Distance</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane</name>
+    <message>
+      <source>Plane</source>
+      <translation>Plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane1</name>
+    <message>
+      <source>1st plane</source>
+      <translation>1er plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane1:ConstructionPlugin_ValidatorAxisTwoNotParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane2</name>
+    <message>
+      <source>2nd plane</source>
+      <translation>2nd plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane2:ConstructionPlugin_ValidatorAxisTwoNotParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:point</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:reverse_offset1</name>
+    <message>
+      <source>Reverse</source>
+      <translation>Sens inverse</translation>
+    </message>
+    <message>
+      <source>Reverse offset value</source>
+      <translation>Valeur de décalage inverse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:reverse_offset2</name>
+    <message>
+      <source>Reverse</source>
+      <translation>Sens inverse</translation>
+    </message>
+    <message>
+      <source>Reverse offset value</source>
+      <translation>Valeur de décalage inverse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:use_offset1</name>
+    <message>
+      <source>Offset from 1st plane</source>
+      <translation>Décalage du 1er plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:use_offset2</name>
+    <message>
+      <source>Offset from 2nd plane</source>
+      <translation>Décalage du 2e plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Create axis</source>
+      <translation>Créer un axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace</name>
+    <message>
+      <source>Main object</source>
+      <translation>Objet principal</translation>
+    </message>
+    <message>
+      <source>Select a cylindrical object</source>
+      <translation>Sélectionnez un objet cylindrique</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:DX</name>
+    <message>
+      <source>DX </source>
+      <translation>DX </translation>
+    </message>
+    <message>
+      <source>X dimension</source>
+      <translation>Dimension X</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:DY</name>
+    <message>
+      <source>DY </source>
+      <translation>DY </translation>
+    </message>
+    <message>
+      <source>Y dimension</source>
+      <translation>Dimension Y</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CreationMethod</name>
+    <message>
+      <source>As axis of cylindrical face</source>
+      <translation>Comme axe de face cylindrique</translation>
+    </message>
+    <message>
+      <source>By line</source>
+      <translation>Par une ligne</translation>
+    </message>
+    <message>
+      <source>By plane and point</source>
+      <translation>Par un plan et un point</translation>
+    </message>
+    <message>
+      <source>By three dimensions</source>
+      <translation>Par trois dimensions</translation>
+    </message>
+    <message>
+      <source>By two planes</source>
+      <translation>Par deux plans</translation>
+    </message>
+    <message>
+      <source>By two points</source>
+      <translation>Par deux points</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:CylindricalFace</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un objet cylindrique.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:FirstPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un premier point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:line</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez une ligne.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un plan.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Axis:plane1</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un plan.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Plane</source>
+      <translation>Plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:planeFace:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Le plan fait référence à un type de forme non acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:planeFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>Le plan ne peut être créé que sur une face</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:planeFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>Le plan ne peut être créé que sur une face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:planeFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>Le plan ne peut être créé que sur une face cylindrique</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:planeFace:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>Le plan ne peut pas être créé sur la face sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "planeFace" is not initialized.</source>
+      <translation>Sélectionnez la face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "distance" is not initialized.</source>
+      <translation>Définir la distance</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane</name>
+    <message>
+      <source>Create plane</source>
+      <translation>Créer un plan</translation>
+    </message>
+    <message>
+      <source>Plane</source>
+      <translation>Plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for rotation around axis.</source>
+      <translation>Angle de rotation autour de l&apos;axe.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:axis</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select line for axis.</source>
+      <translation>Sélectionnez la ligne pour l&apos;axe.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:axis:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:by_other_plane_option</name>
+    <message>
+      <source>By coincident to point</source>
+      <translation>Par coïncidence au point</translation>
+    </message>
+    <message>
+      <source>By distance from other</source>
+      <translation>Par distance aux autres</translation>
+    </message>
+    <message>
+      <source>By rotation</source>
+      <translation>Par rotation</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:coincident_point</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:creation_method</name>
+    <message>
+      <source>By line and point</source>
+      <translation>Par une ligne et un point</translation>
+    </message>
+    <message>
+      <source>By other plane</source>
+      <translation>Par un autre plan</translation>
+    </message>
+    <message>
+      <source>By three points</source>
+      <translation>Par trois points</translation>
+    </message>
+    <message>
+      <source>By two parallel planes</source>
+      <translation>Par deux plans parallèles</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:distance</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Distance from selected face to plane.</source>
+      <translation>Distance de la face sélectionnée au plan.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:line</name>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Select line.</source>
+      <translation>Sélectionnez une ligne.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:line:ConstructionPlugin_ValidatorPlaneLinePoint</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:perpendicular</name>
+    <message>
+      <source>Makes the plane perpendicular to the selected line.</source>
+      <translation>Rend le plan perpendiculaire à la ligne sélectionnée.</translation>
+    </message>
+    <message>
+      <source>Perpendicular </source>
+      <translation>Perpendiculaire </translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:plane</name>
+    <message>
+      <source>Plane</source>
+      <translation>Plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:plane1</name>
+    <message>
+      <source>1st plane</source>
+      <translation>1er plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:plane1:ConstructionPlugin_ValidatorPlaneTwoParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:plane2</name>
+    <message>
+      <source>2nd plane</source>
+      <translation>2nd plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:plane2:ConstructionPlugin_ValidatorPlaneTwoParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point1</name>
+    <message>
+      <source>1st point</source>
+      <translation>1er point</translation>
+    </message>
+    <message>
+      <source>First point.</source>
+      <translation>Premier point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point1:ConstructionPlugin_ValidatorPlaneThreePoints</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point2</name>
+    <message>
+      <source>2nd point</source>
+      <translation>2ème point</translation>
+    </message>
+    <message>
+      <source>Second point.</source>
+      <translation>Deuxième point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point2:ConstructionPlugin_ValidatorPlaneThreePoints</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point3</name>
+    <message>
+      <source>3rd point</source>
+      <translation>3ème point</translation>
+    </message>
+    <message>
+      <source>Third point.</source>
+      <translation>Troisième point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point3:ConstructionPlugin_ValidatorPlaneThreePoints</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:point:ConstructionPlugin_ValidatorPlaneLinePoint</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Plane:reverse</name>
+    <message>
+      <source>Checked means on the other side of the selected plane.</source>
+      <translation>Coché signifie de l&apos;autre côté du plan sélectionné.</translation>
+    </message>
+    <message>
+      <source>Reverse</source>
+      <translation>Sens inverse</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point</name>
+    <message>
+      <source>Create point</source>
+      <translation>Créer un point</translation>
+    </message>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:distance</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Distance value.</source>
+      <translation>Distance.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:edge</name>
+    <message>
+      <source>Edge</source>
+      <translation>Bord</translation>
+    </message>
+    <message>
+      <source>Edge for creating point on it.</source>
+      <translation>Arête où créer le point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:edge_for_point_projection</name>
+    <message>
+      <source>Edge for projection.</source>
+      <translation>Arête pour la projection.</translation>
+    </message>
+    <message>
+      <source>edge</source>
+      <translation>bord</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:face_for_point_projection</name>
+    <message>
+      <source>Face for projection.</source>
+      <translation>Face pour projection.</translation>
+    </message>
+    <message>
+      <source>face</source>
+      <translation>face</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line</name>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Line for intersection.</source>
+      <translation>Ligne d&apos;intersection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line_1</name>
+    <message>
+      <source>First line</source>
+      <translation>Première ligne</translation>
+    </message>
+    <message>
+      <source>First line.</source>
+      <translation>Première ligne.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line_1:ConstructionPlugin_ValidatorPointLines</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line_2</name>
+    <message>
+      <source>Second line</source>
+      <translation>Deuxième ligne</translation>
+    </message>
+    <message>
+      <source>Second line.</source>
+      <translation>Deuxième ligne.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line_2:ConstructionPlugin_ValidatorPointLines</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane</name>
+    <message>
+      <source>Plane</source>
+      <translation>Plan</translation>
+    </message>
+    <message>
+      <source>Plane for intersection.</source>
+      <translation>Plan d&apos;intersection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_1</name>
+    <message>
+      <source>1st plane</source>
+      <translation>1er plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_2</name>
+    <message>
+      <source>2nd plane</source>
+      <translation>2nd plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_3</name>
+    <message>
+      <source>3rd plane</source>
+      <translation>3ème plan</translation>
+    </message>
+    <message>
+      <source>Select a planar face.</source>
+      <translation>Sélectionnez une face plane.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:object_for_center_of_circle</name>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Object for center of circle.</source>
+      <translation>Objet pour le centre du cercle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:object_for_center_of_gravity</name>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Object for center of gravity.</source>
+      <translation>Objet pour le centre de gravité.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:offset</name>
+    <message>
+      <source>Distance </source>
+      <translation>Distance </translation>
+    </message>
+    <message>
+      <source>Distance from the plane</source>
+      <translation>Distance du plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:point_to_project</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+    <message>
+      <source>Point for projection.</source>
+      <translation>Point de projection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:ratio</name>
+    <message>
+      <source>Ratio</source>
+      <translation>Rapport</translation>
+    </message>
+    <message>
+      <source>Ratio value.</source>
+      <translation>Valeur du rapport.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:reverse</name>
+    <message>
+      <source>Distance from edge end point.</source>
+      <translation>Distance du point final du bord.</translation>
+    </message>
+    <message>
+      <source>Reverse</source>
+      <translation>Sens inverse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:reverse_offset</name>
+    <message>
+      <source>Reverse</source>
+      <translation>Sens inverse</translation>
+    </message>
+    <message>
+      <source>Reverse offset value</source>
+      <translation>Valeur de décalage inverse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:use_offset</name>
+    <message>
+      <source>Offset from the plane</source>
+      <translation>Décalage du plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "x" is not initialized.</source>
+      <translation>Sélectionnez la coordonnée x</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "y" is not initialized.</source>
+      <translation>Sélectionnez la coordonnée y</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "z" is not initialized.</source>
+      <translation>Sélectionnez la coordonnée z</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line:ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane:ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_1:ConstructionPlugin_ValidatorPointThreeNonParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_2:ConstructionPlugin_ValidatorPointThreeNonParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_3:ConstructionPlugin_ValidatorPointThreeNonParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:object_for_center_of_circle:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:creation_method</name>
+    <message>
+      <source>By X, Y, Z</source>
+      <translation>Par X, Y, Z</translation>
+    </message>
+    <message>
+      <source>By distance on edge</source>
+      <translation>Par distance au bord</translation>
+    </message>
+    <message>
+      <source>By geometrical property of object</source>
+      <translation>Par propriété géométrique d&apos;objet</translation>
+    </message>
+    <message>
+      <source>By intersection of objects</source>
+      <translation>Par intersection d&apos;objets</translation>
+    </message>
+    <message>
+      <source>By projection on edge or plane</source>
+      <translation>Par projection sur un bord ou un plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:geometrical_property_type</name>
+    <message>
+      <source>By center of circle</source>
+      <translation>Par centre de cercle</translation>
+    </message>
+    <message>
+      <source>By center of gravity</source>
+      <translation>Par centre de gravité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_line:ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane:ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_1:ConstructionPlugin_ValidatorPointThreeNonParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_2:ConstructionPlugin_ValidatorPointThreeNonParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_plane_3:ConstructionPlugin_ValidatorPointThreeNonParallelPlanes</name>
+    <message>
+      <source>One of the attribute is not initialized.</source>
+      <translation>Un des attributs n’est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:intersection_type</name>
+    <message>
+      <source>By line and plane intersection</source>
+      <translation>Par intersection d’une ligne et d&apos;un plan</translation>
+    </message>
+    <message>
+      <source>By three planes intersection</source>
+      <translation>Par intersection de trois plans</translation>
+    </message>
+    <message>
+      <source>By two lines intersection</source>
+      <translation>Par intersection de deux lignes</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:offset_type</name>
+    <message>
+      <source>Distance on edge by ratio</source>
+      <translation>Distance au bord par ratio</translation>
+    </message>
+    <message>
+      <source>Distance on edge by value</source>
+      <translation>Distance au bord par valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>Point:projection_type</name>
+    <message>
+      <source>By projection on edge</source>
+      <translation>Par projection sur une arête</translation>
+    </message>
+    <message>
+      <source>By projection on face</source>
+      <translation>Par projection sur la face</translation>
+    </message>
+  </context>
+</TS>
index 40039e71885fa0306cd3641ea9993978f3abe139..2f44779f636672972a0033253d19bdc013ade0ce 100644 (file)
Binary files a/src/ConstructionPlugin/doc/images/Point1.png and b/src/ConstructionPlugin/doc/images/Point1.png differ
index 217f6db5fbdc328f770e4826fa328e5b509ee897..95f456fcee68b13f5c7268af80e395e5330de929 100644 (file)
Binary files a/src/ConstructionPlugin/doc/images/Point2.png and b/src/ConstructionPlugin/doc/images/Point2.png differ
index 696ea99500a7fc8dbb928cc6c980455a7b204576..6d3d39aef6516258d2662c7e86f1ac87e368fe7a 100644 (file)
Binary files a/src/ConstructionPlugin/doc/images/Point3.png and b/src/ConstructionPlugin/doc/images/Point3.png differ
index 94d66b5893664ecee1f5f31827ed6fa055866bc8..3f649d6370f952ae387530421d42bef02de65911 100644 (file)
Binary files a/src/ConstructionPlugin/doc/images/Point4.png and b/src/ConstructionPlugin/doc/images/Point4.png differ
index c65d0588052aa707b49afc5441f5b7bf2e483253..0580696c0bd5ff0ae558f78943d1a2b414328ab3 100644 (file)
Binary files a/src/ConstructionPlugin/doc/images/Point5.png and b/src/ConstructionPlugin/doc/images/Point5.png differ
index dcffc622e5cb1e71df9d7bda0b91552fcc9b00b1..62ededcd19ba4e4f2eaf005693787630fe11bf65 100644 (file)
@@ -6,6 +6,7 @@
         title="Point"
         tooltip="Create point"
         icon="icons/Construction/point.png"
+        apply_continue="true"
         helpfile="pointFeature.html">
         <source path="point_widget.xml" />
       </feature>
index aa09fbbee2c4db7980b22df440d9a19642c4346a..5b543e58c54c666c7905784776e3fed70eca732b 100644 (file)
 //
 
 /* Events.i */
-%module EventsAPI
+%module(directors="1") EventsAPI
+%feature("director:except") {
+    if ($error != NULL) {
+      PyErr_Print();
+      std::cerr << std::endl;
+      throw Swig::DirectorMethodException();
+    }
+}
+
 %{
   #include "Events.h"
   #include "Events_InfoMessage.h"
+  #include "Events_Listener.h"
+  #include "Events_Loop.h"
   #include "Events_Message.h"
+  #include "Events_MessageGroup.h"
 %}
 
 
 %include "typemaps.i"
 %include "std_string.i"
 
+// directors
+%feature("director") Events_Listener;
+
 // all supported interfaces
 %include "Events_Message.h"
 %include "Events_InfoMessage.h"
+%include "Events_Listener.h"
+%include "Events_Loop.h"
+%include "Events_MessageGroup.h"
index 07fd93f97996dfe14b1b57b60f33c19937574698..a7da686f67fe6d272141daf1fdb84a8ae829f985 100644 (file)
@@ -38,7 +38,9 @@ class Events_Listener {
   /// map from event ID to groupped messages (for flush for groupMessages=true listeners)
   std::map<char*, std::shared_ptr<Events_Message> > myGroups;
 
- public:
+public:
+  virtual ~Events_Listener() {}
+
   //! This method is called by loop when the event is started to process.
   EVENTS_EXPORT virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage) = 0;
 
index fa1ab009e885ea54f52438e9754466c91d7dc332..2d764635a27b543c56fcc5f751cba48a17417922 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "ExchangeAPI_Export.h"
 //--------------------------------------------------------------------------------------
+#include <ExchangePlugin_ExportPart.h>
+//--------------------------------------------------------------------------------------
 #include <ModelAPI_Document.h>
 #include <ModelAPI_Feature.h>
 #include <ModelHighAPI_Tools.h>
@@ -188,4 +190,17 @@ ExportPtr exportToXAO(const std::shared_ptr<ModelAPI_Document> & thePart,
   return ExportPtr(new ExchangeAPI_Export(aFeature, theFilePath, theSelectedShape, "XAO"));
 }
 
+void exportPart(const std::shared_ptr<ModelAPI_Document> & thePart,
+                const std::string & theFilePath,
+                const std::list<ModelHighAPI_Selection> & theSelected)
+{
+  FeaturePtr aFeature = thePart->addFeature(ExchangePlugin_ExportPart::ID());
+  aFeature->string(ExchangePlugin_ExportPart::FILE_PATH_ID())->setValue(theFilePath);
+  if (!theSelected.empty()) {
+    fillAttribute(theSelected,
+        aFeature->selectionList(ExchangePlugin_ExportPart::SELECTION_LIST_ID()));
+  }
+  // restart transaction to execute and delete the macro-feature
+  apply();
+}
 //--------------------------------------------------------------------------------------
index 6cfddfd8f65d13500e2b984bb59d85dc39a4dff5..c976d43a31ecbed9b9c10ea39de875ea72e1e04f 100644 (file)
@@ -123,6 +123,15 @@ ExportPtr exportToXAO(const std::shared_ptr<ModelAPI_Document> & thePart,
   const std::string & theAuthor = std::string(),
   const std::string & theGeometryName = std::string());
 
+
+/** \ingroup CPPHighAPI
+ *  \brief Export selected features or the whole part to the binary file.
+ */
+EXCHANGEAPI_EXPORT void exportPart(
+    const std::shared_ptr<ModelAPI_Document> & thePart,
+    const std::string & theFilePath,
+    const std::list<ModelHighAPI_Selection> & theSelected = std::list<ModelHighAPI_Selection>());
+
 //--------------------------------------------------------------------------------------
 //--------------------------------------------------------------------------------------
 #endif /* SRC_EXCHANGEAPI_EXCHANGEAPI_EXPORT_H_ */
index d360c95a76ca54f2bc23866b2f33c8db82a49d2e..621ebcab56e9969f69b09a2a91fc8f28da72b721 100644 (file)
 
 #include "ExchangeAPI_Import.h"
 //--------------------------------------------------------------------------------------
+#include <ExchangePlugin_ImportPart.h>
+//--------------------------------------------------------------------------------------
 #include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Services.h>
 #include <ModelHighAPI_Tools.h>
 //--------------------------------------------------------------------------------------
+#include <ModelAPI_AttributeStringArray.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+//--------------------------------------------------------------------------------------
 #include <algorithm>
 
 ExchangeAPI_Import::ExchangeAPI_Import(
@@ -94,3 +101,42 @@ ImportPtr addImport(
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ExchangeAPI_Import::ID());
   return ImportPtr(new ExchangeAPI_Import(aFeature, theFilePath));
 }
+
+void importPart(const std::shared_ptr<ModelAPI_Document> & thePart,
+                const std::string & theFilePath,
+                const ModelHighAPI_Reference & theAfterThis)
+{
+  static const bool THE_VISIBLE_FEATURE = false;
+  FeaturePtr aCurrentFeature;
+  if (theAfterThis.feature()) {
+    aCurrentFeature = thePart->currentFeature(THE_VISIBLE_FEATURE);
+    thePart->setCurrentFeature(theAfterThis.feature(), THE_VISIBLE_FEATURE);
+  }
+
+  FeaturePtr aFeature = thePart->addFeature(ExchangePlugin_ImportPart::ID());
+  aFeature->string(ExchangePlugin_ImportPart::FILE_PATH_ID())->setValue(theFilePath);
+
+  // specify the ID of selected document
+  int aTargetPartIndex = 0;
+  SessionPtr aSession = ModelAPI_Session::get();
+  if (aSession->moduleDocument() == thePart) {
+    // Importing to PartSet has 2 choices: import directly to PartSet (if possible)
+    // or create a new part. Because then importing to existing part the document
+    // has to be specified explicitly.
+    // As a result, parse the list of possible target documents and generate new part
+    // if the import document is not applicable on PartSet level
+    // (there is no 'PartSet' in the list of applicable documents).
+    AttributeStringArrayPtr aDocsList =
+        aFeature->stringArray(ExchangePlugin_ImportPart::TARGET_PARTS_LIST_ID());
+    if (aDocsList->size() > 1 && aDocsList->value(1) == "PartSet")
+      aTargetPartIndex = 1;
+  }
+  aFeature->integer(ExchangePlugin_ImportPart::TARGET_PART_ID())->setValue(aTargetPartIndex);
+
+  // restart transaction to execute and delete the macro-feature
+  apply();
+
+  // restore current feature
+  if (aCurrentFeature)
+    thePart->setCurrentFeature(aCurrentFeature, THE_VISIBLE_FEATURE);
+}
index 1713c9271bfc4eba6b5ae063e06e4cd45829c825..57793c725c106343ab44a5ac76a2877248be9b93 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <ModelHighAPI_Interface.h>
 #include <ModelHighAPI_Macro.h>
+#include <ModelHighAPI_Reference.h>
+#include <ModelHighAPI_Selection.h>
 //--------------------------------------------------------------------------------------
 /**\class ExchangeAPI_Import
  * \ingroup CPPHighAPI
@@ -72,6 +74,14 @@ EXCHANGEAPI_EXPORT
 ImportPtr addImport(const std::shared_ptr<ModelAPI_Document> & thePart,
                     const std::string & theFilePath);
 
+/** \ingroup CPPHighAPI
+ *  \brief Import features from the file to the document after the current feature (or to the end).
+ */
+EXCHANGEAPI_EXPORT void importPart(
+    const std::shared_ptr<ModelAPI_Document> & thePart,
+    const std::string & theFilePath,
+    const ModelHighAPI_Reference & theAfterThis = ModelHighAPI_Reference());
+
 //--------------------------------------------------------------------------------------
 //--------------------------------------------------------------------------------------
 #endif /* SRC_EXCHANGEAPI_EXCHANGEAPI_IMPORT_H_ */
index 222f2e6eaea1ac3bea1cbbb0aa44e8d0b8465cd8..3c6692e59eb3a8ab31d25c336d76c6f069337ae7 100644 (file)
@@ -26,7 +26,10 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events
                     ${PROJECT_SOURCE_DIR}/src/ModelHighAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
+                    ${PROJECT_SOURCE_DIR}/src/GeomValidators
                     ${PROJECT_SOURCE_DIR}/src/XAO
+                    ${PROJECT_SOURCE_DIR}/src/ConstructionPlugin
+                    ${PROJECT_SOURCE_DIR}/src/PartSetPlugin
 )
 
 SET(PROJECT_HEADERS
@@ -37,6 +40,8 @@ SET(PROJECT_HEADERS
     ExchangePlugin_Validators.h
     ExchangePlugin_Tools.h
     ExchangePlugin_Dump.h
+    ExchangePlugin_ImportPart.h
+    ExchangePlugin_ExportPart.h
 )
 
 SET(PROJECT_SOURCES
@@ -46,6 +51,8 @@ SET(PROJECT_SOURCES
     ExchangePlugin_Validators.cpp
     ExchangePlugin_Tools.cpp
     ExchangePlugin_Dump.cpp
+    ExchangePlugin_ImportPart.cpp
+    ExchangePlugin_ExportPart.cpp
 )
 
 SET(XML_RESOURCES
@@ -55,6 +62,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     ExchangePlugin_msg_en.ts
+    ExchangePlugin_msg_fr.ts
 )
 
 SET(PROJECT_LIBRARIES
@@ -64,6 +72,7 @@ SET(PROJECT_LIBRARIES
     ModelHighAPI
     GeomAPI
     GeomAlgoAPI
+    GeomValidators
     XAOShaper
 )
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
@@ -78,11 +87,42 @@ INSTALL(FILES ${XML_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Exchange)
 INSTALL(FILES ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 
-ADD_UNIT_TESTS(TestImport.py
-               TestExport.py
-               Test2290.py
-               Test2459.py
-               TestExportToXAOWithFields.py
-               TestExportToXAOWithGroupNotUpdated.py
-               TestExport_FiniteValidator.py
+ADD_UNIT_TESTS(
+  TestImport.py
+  TestExport.py
+  Test2290.py
+  Test2459.py
+  TestExportToXAOWithFields.py
+  TestExportToXAOWithGroupNotUpdated.py
+  TestExport_FiniteValidator.py
+  TestExportPart_Failure_1.py
+  TestExportPart_Failure_2.py
+  TestExportPart_Failure_3.py
+  TestExportPart_FullPartSet.py
+  TestExportPart_FullPart_1.py
+  TestExportPart_FullPart_2.py
+  TestExportPart_PartSet.py
+  TestExportPart_Results_1.py
+  TestExportPart_Results_2.py
+  TestExportPart_Results_3.py
+  TestExportPart_Results_4.py
+  TestExportPart_Results_5.py
+  TestExportPart_Results_6.py
+  TestExportPart_Results_7.py
+  TestExportPart_Results_8.py
+  TestImportPart_AfterCurrent_1.py
+  TestImportPart_AfterCurrent_2.py
+  TestImportPart_AfterLast_1.py
+  TestImportPart_AfterLast_2.py
+  TestImportPart_AfterLast_3.py
+  TestImportPart_AfterLast_4.py
+  TestImportPart_AfterLast_5.py
+  TestImportPart_AfterLast_6.py
+  TestImportPart_Construction_1.py
+  TestImportPart_Construction_2.py
+  TestImportPart_Construction_3.py
+  TestImportPart_Construction_4.py
+  TestImportPart_Multiple.py
+  TestImportPart_ToEmptyPart.py
+  TestImportPart_ToEmptyPartSet.py
 )
diff --git a/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp b/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp
new file mode 100644 (file)
index 0000000..2957ce7
--- /dev/null
@@ -0,0 +1,278 @@
+// 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 <ExchangePlugin_ExportPart.h>
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <ConstructionPlugin_Axis.h>
+#include <ConstructionPlugin_Plane.h>
+#include <ConstructionPlugin_Point.h>
+
+#include <Events_InfoMessage.h>
+
+#include <PartSetPlugin_Part.h>
+
+#include <sstream>
+
+// Obtain all features to be exported to get the list of selected results.
+static void collectFeatures(DocumentPtr theDocument,
+                            AttributeSelectionListPtr theSelected,
+                            std::list<FeaturePtr>& theExport);
+// Obtain all constuction elements of the document.
+static void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport);
+// Check features could be exported. The following features cannot be exported:
+// * non-construction result (Part) when exporting the PartSet;
+// * features, which refer to objects from another document.
+// Returns true if all features can be exported.
+static bool verifyExport(const std::list<FeaturePtr>& theFeatures,
+                         std::list<FeaturePtr>& theExternalReferences,
+                         std::list<FeaturePtr>& theExportedParts);
+
+
+ExchangePlugin_ExportPart::ExchangePlugin_ExportPart()
+{
+}
+
+void ExchangePlugin_ExportPart::initAttributes()
+{
+  data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(FILE_FORMAT_ID(), ModelAPI_AttributeString::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FILE_FORMAT_ID());
+  data()->addAttribute(SELECTION_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SELECTION_LIST_ID());
+}
+
+void ExchangePlugin_ExportPart::execute()
+{
+  AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
+  std::string aFilename = aFilePathAttr->value();
+  if (aFilename.empty()) {
+    setError("File name is empty.");
+    return;
+  }
+
+  std::list<FeaturePtr> aFeaturesToExport;
+
+  DocumentPtr anExportDoc = document();
+  DocumentPtr aPartSetDoc = ModelAPI_Session::get()->moduleDocument();
+  AttributeSelectionListPtr aSelected = selectionList(SELECTION_LIST_ID());
+  if (aSelected && aSelected->size() == 0 && anExportDoc == aPartSetDoc) {
+    // no result is selected, thus have to export all features of the current document,
+    // but the document is a PartSet; and it is forbidden to copy results of Parts,
+    // thus copy construction elements only
+    collectConstructions(anExportDoc, aFeaturesToExport);
+  }
+  else
+    collectFeatures(anExportDoc, aSelected, aFeaturesToExport);
+
+  if (aFeaturesToExport.empty()) {
+    Events_InfoMessage(getKind(), "Selected features cannot be exported from the document.").send();
+    return;
+  }
+
+  // remove 'ExportPart' feature if any
+  if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID())
+    aFeaturesToExport.pop_back();
+
+  std::list<FeaturePtr> anExternalLinks, aReferredParts;
+  if (!verifyExport(aFeaturesToExport, anExternalLinks, 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 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();
+    }
+    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 aMessage = "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.";
+      Events_InfoMessage(getKind(), aMessage).arg(aListOfParts.str()).send();
+    }
+    // should not export anything
+    aFeaturesToExport.clear();
+  }
+
+  if (!aFeaturesToExport.empty()) {
+    // save the document
+    if (!anExportDoc->save(aFilename.c_str(), aFeaturesToExport))
+      setError("Cannot save the document.");
+  }
+}
+
+
+// ================================     Auxiliary functions     ===================================
+
+static bool isCoordinate(FeaturePtr theFeature)
+{
+  return !theFeature->isInHistory() &&
+          (theFeature->getKind() == ConstructionPlugin_Point::ID() ||
+           theFeature->getKind() == ConstructionPlugin_Axis::ID() ||
+           theFeature->getKind() == ConstructionPlugin_Plane::ID());
+}
+
+static void allReferencedFeatures(const std::set<FeaturePtr>& theFeatures,
+                                  std::set<FeaturePtr>& theReferencedFeatures)
+{
+  std::set<FeaturePtr> aReferences;
+  for (std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin();
+       anIt != theFeatures.end(); ++anIt) {
+    theReferencedFeatures.insert(*anIt);
+
+    std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+    (*anIt)->data()->referencesToObjects(aRefs);
+
+    for (std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
+         aRIt != aRefs.end(); ++aRIt) {
+      for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
+           anObjIt != aRIt->second.end(); ++anObjIt) {
+        FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
+        if (aFeature && !isCoordinate(aFeature) &&
+            theReferencedFeatures.find(aFeature) == theReferencedFeatures.end())
+          aReferences.insert(aFeature);
+      }
+    }
+  }
+
+  if (!aReferences.empty())
+    allReferencedFeatures(aReferences, theReferencedFeatures);
+}
+
+void collectFeatures(DocumentPtr theDocument,
+                     AttributeSelectionListPtr theSelected,
+                     std::list<FeaturePtr>& theExport)
+{
+  theExport = theDocument->allFeatures();
+
+  // remove all features after the current one
+  FeaturePtr aCurrentFeature = theDocument->currentFeature(false);
+  std::list<FeaturePtr>::iterator anIt = theExport.begin();
+  for (; anIt != theExport.end(); ++anIt)
+    if (*anIt == aCurrentFeature) {
+      theExport.erase(++anIt, theExport.end());
+      break;
+    }
+
+  if (!theSelected || theSelected->size() == 0) {
+    // nothing is selected, return all features of the document
+    return;
+  }
+
+  // collect initial list of features basing on the selected results
+  std::set<FeaturePtr> aFeaturesToExport;
+  for (int anIndex = 0, aSize = theSelected->size(); anIndex < aSize; ++anIndex) {
+    AttributeSelectionPtr aCurrent = theSelected->value(anIndex);
+    FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aCurrent->context());
+    if (aCurrentFeature)
+      aFeaturesToExport.insert(aCurrentFeature);
+  }
+  // recursively collect all features used for the selected results
+  allReferencedFeatures(aFeaturesToExport, aFeaturesToExport);
+
+  // remove the features which are not affect the selected results
+  anIt = theExport.begin();
+  while (anIt != theExport.end()) {
+    if (aFeaturesToExport.find(*anIt) == aFeaturesToExport.end()) {
+      std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
+      theExport.erase(aRemoveIt);
+    }
+    else
+      ++anIt;
+  }
+}
+
+void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport)
+{
+  theExport = theDocument->allFeatures();
+  // keep constructions only
+  std::list<FeaturePtr>::iterator anIt = theExport.begin();
+  while (anIt != theExport.end()) {
+    FeaturePtr aCurFeature = *anIt;
+    ResultPtr aCurResult = aCurFeature->lastResult();
+
+    bool isApplicable =
+        (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()) &&
+        !isCoordinate(aCurFeature);
+
+    if (isApplicable)
+      ++anIt;
+    else {
+      std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
+      theExport.erase(aRemoveIt);
+    }
+  }
+}
+
+bool verifyExport(const std::list<FeaturePtr>& theFeatures,
+                  std::list<FeaturePtr>& theExternalReferences,
+                  std::list<FeaturePtr>& theExportedParts)
+{
+  for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
+       anIt != theFeatures.end(); ++anIt) {
+    // full part should not be exported
+    if ((*anIt)->getKind() == PartSetPlugin_Part::ID())
+      theExportedParts.push_back(*anIt);
+
+    DocumentPtr aDoc = (*anIt)->document();
+
+    std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+    (*anIt)->data()->referencesToObjects(aRefs);
+    std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
+    for (;  aRIt != aRefs.end(); ++aRIt) {
+      for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
+           anObjIt != aRIt->second.end(); ++anObjIt) {
+        FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
+        if (aFeature) {
+          // feature refers to external entity,
+          // which is neither the Origin nor coordinate axis or plane
+          if (aFeature->document() != aDoc && !isCoordinate(aFeature))
+            theExternalReferences.push_back(*anIt);
+          // feature refers to result of a part
+          if (aFeature->getKind() == PartSetPlugin_Part::ID())
+            theExportedParts.push_back(*anIt);
+        }
+      }
+    }
+  }
+
+  return theExternalReferences.empty() && theExportedParts.empty();
+}
diff --git a/src/ExchangePlugin/ExchangePlugin_ExportPart.h b/src/ExchangePlugin/ExchangePlugin_ExportPart.h
new file mode 100644 (file)
index 0000000..504d777
--- /dev/null
@@ -0,0 +1,84 @@
+// 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 EXCHANGEPLUGIN_EXPORTPART_H_
+#define EXCHANGEPLUGIN_EXPORTPART_H_
+
+#include <ExchangePlugin.h>
+#include <ModelAPI_Feature.h>
+
+/**
+ * \class ExchangePlugin_ExportPart
+ * \ingroup Plugins
+ * \brief Feature for export some results of a Part to the binary format for the further import.
+ */
+class ExchangePlugin_ExportPart : public ModelAPI_Feature
+{
+public:
+  /// Feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_EXPORT_ID("ExportPart");
+    return MY_EXPORT_ID;
+  }
+  /// attribute name of file path
+  inline static const std::string& FILE_PATH_ID()
+  {
+    static const std::string MY_FILE_PATH_ID("file_path");
+    return MY_FILE_PATH_ID;
+  }
+  /// attribute name of file format
+  inline static const std::string& FILE_FORMAT_ID()
+  {
+    static const std::string MY_FILE_FORMAT_ID("file_format");
+    return MY_FILE_FORMAT_ID;
+  }
+  /// attribute name of selection list
+  inline static const std::string& SELECTION_LIST_ID()
+  {
+    static const std::string MY_SELECTION_LIST_ID("selection_list");
+    return MY_SELECTION_LIST_ID;
+  }
+  /// Default constructor
+  ExchangePlugin_ExportPart();
+
+  /// Returns the unique kind of a feature
+  EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    return ExchangePlugin_ExportPart::ID();
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes
+  EXCHANGEPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Computes or recomputes the results
+  EXCHANGEPLUGIN_EXPORT virtual void execute();
+
+  /// Returns true if this feature is used as macro: creates other features and then removed.
+  EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; }
+
+  /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false.
+  EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; }
+
+  /// Do not put in history.
+  /// Since it is not a macro, it is not deleted, but we don't want to see it.
+  bool isInHistory()  { return false; }
+};
+
+#endif /* EXCHANGEPLUGIN_EXPORTPART_H_ */
diff --git a/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp b/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp
new file mode 100644 (file)
index 0000000..3b9ec7e
--- /dev/null
@@ -0,0 +1,279 @@
+// 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 <ExchangePlugin_ImportPart.h>
+
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeStringArray.h>
+#include <ModelAPI_ResultPart.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+
+#include <PartSetPlugin_Part.h>
+
+#include <map>
+#include <sstream>
+
+static const std::string THE_NEW_PART_STR("New Part");
+static const std::string THE_PART_SET_STR("PartSet");
+
+// Update names of imported features/results concurent with existing objects.
+static void correntNonUniqueNames(DocumentPtr theDocument, std::list<FeaturePtr>& theImported);
+// Find the document according to its name or create the new one.
+static DocumentPtr findDocument(DocumentPtr thePartSetDoc, const std::string& thePartName);
+
+ExchangePlugin_ImportPart::ExchangePlugin_ImportPart()
+{
+}
+
+void ExchangePlugin_ImportPart::initAttributes()
+{
+  data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(TARGET_PART_ID(), ModelAPI_AttributeInteger::typeId());
+  data()->addAttribute(TARGET_PARTS_LIST_ID(), ModelAPI_AttributeStringArray::typeId());
+}
+
+
+void ExchangePlugin_ImportPart::execute()
+{
+  AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
+  std::string aFilename = aFilePathAttr->value();
+  if (aFilename.empty()) {
+    setError("File name is empty.");
+    return;
+  }
+
+  // get the document where to import
+  AttributeStringArrayPtr aPartsAttr = stringArray(TARGET_PARTS_LIST_ID());
+  AttributeIntegerPtr aTargetAttr = integer(TARGET_PART_ID());
+  SessionPtr aSession = ModelAPI_Session::get();
+  DocumentPtr aDoc =
+      findDocument(aSession->moduleDocument(), aPartsAttr->value(aTargetAttr->value()));
+
+  // load the file into the document
+  std::list<FeaturePtr> anImportedFeatures;
+  if (aDoc && aDoc->importPart(aFilename.c_str(), anImportedFeatures))
+    correntNonUniqueNames(aDoc, anImportedFeatures);
+  else
+    setError("Cannot import the document.");
+}
+
+void ExchangePlugin_ImportPart::attributeChanged(const std::string& theID)
+{
+  if (theID == FILE_PATH_ID()) {
+    AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
+    if (aFilePathAttr->value().empty())
+      return;
+
+    AttributeStringArrayPtr aPartsAttr = stringArray(TARGET_PARTS_LIST_ID());
+    AttributeIntegerPtr aTargetAttr = integer(TARGET_PART_ID());
+
+    // update the list of target parts
+    SessionPtr aSession = ModelAPI_Session::get();
+    DocumentPtr aDoc = document();
+    bool isPartSet = aDoc == aSession->moduleDocument();
+    if (isPartSet) {
+      std::list<std::string> anAcceptedValues;
+      anAcceptedValues.push_back(THE_NEW_PART_STR);
+
+      std::list<FeaturePtr> anImportedFeatures;
+      if (aDoc->importPart(aFilePathAttr->value().c_str(), anImportedFeatures, isPartSet))
+        anAcceptedValues.push_back(THE_PART_SET_STR);
+
+      // append names of all parts
+      std::list<FeaturePtr> aSubFeatures = aDoc->allFeatures();
+      for (std::list<FeaturePtr>::iterator aFIt = aSubFeatures.begin();
+           aFIt != aSubFeatures.end(); ++aFIt) {
+        if ((*aFIt)->getKind() == PartSetPlugin_Part::ID())
+          anAcceptedValues.push_back((*aFIt)->name());
+      }
+
+      if (aPartsAttr->size() != anAcceptedValues.size())
+        aTargetAttr->setValue(0);
+
+      aPartsAttr->setSize((int)anAcceptedValues.size());
+      std::list<std::string>::iterator anIt = anAcceptedValues.begin();
+      for (int anInd = 0; anIt != anAcceptedValues.end(); ++anIt, ++anInd)
+        aPartsAttr->setValue(anInd, *anIt);
+    }
+    else {
+      // keep only the name of the current part
+      if (aPartsAttr->size() == 0) {
+        FeaturePtr aPartFeature = ModelAPI_Tools::findPartFeature(aSession->moduleDocument(), aDoc);
+
+        aPartsAttr->setSize(1);
+        aPartsAttr->setValue(0, aPartFeature->name());
+        aTargetAttr->setValue(0);
+      }
+    }
+  }
+}
+
+
+// ================================     Auxiliary functions     ===================================
+
+DocumentPtr findDocument(DocumentPtr thePartSetDoc, const std::string& thePartName)
+{
+  DocumentPtr aDoc;
+  if (thePartName == THE_PART_SET_STR)
+    aDoc = thePartSetDoc;
+  else {
+    FeaturePtr aPartFeature;
+    if (thePartName == THE_NEW_PART_STR) {
+      // create new part
+      aPartFeature = thePartSetDoc->addFeature(PartSetPlugin_Part::ID());
+      if (aPartFeature)
+        aPartFeature->execute();
+    }
+    else {
+      // find existing part by its name
+      std::list<FeaturePtr> aSubFeatures = thePartSetDoc->allFeatures();
+      for (std::list<FeaturePtr>::iterator aFIt = aSubFeatures.begin();
+           aFIt != aSubFeatures.end(); ++aFIt) {
+        if ((*aFIt)->getKind() == PartSetPlugin_Part::ID() && (*aFIt)->name() == thePartName) {
+          aPartFeature = *aFIt;
+          break;
+        }
+      }
+    }
+
+    if (aPartFeature) {
+      ResultPartPtr aPartResult =
+          std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeature->lastResult());
+      if (aPartResult)
+        aDoc = aPartResult->partDoc();
+    }
+  }
+  return aDoc;
+}
+
+typedef std::map<std::string, std::map<std::string, std::set<int> > > ObjectNameMap;
+
+bool splitName(std::string& theName, int& theIndex)
+{
+  size_t aLastUndercore = theName.find_last_of('_');
+  bool isOk = aLastUndercore != std::string::npos;
+  if (isOk) {
+    char* isNumber;
+    std::string anIndexStr = theName.substr(aLastUndercore + 1);
+    theIndex = std::strtol(anIndexStr.c_str(), &isNumber, 10);
+    isOk = isNumber != 0;
+    if (isOk)
+      theName.erase(aLastUndercore);
+  }
+  return isOk;
+}
+
+void addIndexedName(const ObjectPtr& theObject, ObjectNameMap& theIndexedNames)
+{
+  std::string aName = theObject->data()->name();
+  std::string aGroup = theObject->groupName();
+  int anIndex = 0;
+  bool isIndexed = splitName(aName, anIndex);
+  std::set<int>& anIndices = theIndexedNames[aGroup][aName];
+  if (isIndexed)
+    anIndices.insert(anIndex);
+}
+
+// Collect names of features and results in the document before the import.
+// The name of indexed feature/result will be split to the name and the index. For example ,
+// 'Point_1', 'Point_2' will be placed at the same key with the set of corrsponding indices:
+// 'Point_1', 'Point_2' => {'Point', [1, 2]}.
+// Thus, the new point should have index 3 and therefore the name 'Point_3'.
+static void collectOldNames(DocumentPtr theDocument, std::list<FeaturePtr>& theAvoided,
+                            ObjectNameMap& theIndexedNames)
+{
+  std::list<FeaturePtr> anAllFeatures = theDocument->allFeatures();
+  std::list<FeaturePtr>::iterator aFIt = anAllFeatures.begin();
+  std::list<FeaturePtr>::iterator anAvoidIt = theAvoided.begin();
+  for (; aFIt != anAllFeatures.end(); ++aFIt) {
+    if (anAvoidIt != theAvoided.end() && *aFIt == *anAvoidIt) {
+      // skip this feature
+      ++anAvoidIt;
+      continue;
+    }
+
+    // store name of feature
+    addIndexedName(*aFIt, theIndexedNames);
+    // store names of results
+    const std::list<ResultPtr>& aResults = (*aFIt)->results();
+    for (std::list<ResultPtr>::const_iterator aRIt = aResults.begin();
+         aRIt != aResults.end(); ++aRIt)
+      addIndexedName(*aRIt, theIndexedNames);
+  }
+}
+
+static std::string uniqueName(const ObjectPtr& theObject, ObjectNameMap& theExistingNames)
+{
+  std::string aName = theObject->data()->name();
+  std::string aGroup = theObject->groupName();
+  int anIndex = 1;
+  splitName(aName, anIndex);
+
+  ObjectNameMap::iterator aFoundGroup = theExistingNames.find(aGroup);
+  bool isUnique = aFoundGroup == theExistingNames.end();
+
+  std::map<std::string, std::set<int> >::iterator aFound;
+  if (!isUnique) {
+    aFound = aFoundGroup->second.find(aName);
+    isUnique = aFound == aFoundGroup->second.end();
+  }
+
+  if (isUnique) {
+    // name is unique
+    aName = theObject->data()->name();
+    addIndexedName(theObject, theExistingNames);
+  }
+  else {
+    // search the appropriate index
+    std::set<int>::iterator aFoundIndex = aFound->second.find(anIndex);
+    for (; aFoundIndex != aFound->second.end(); ++aFoundIndex, ++anIndex)
+      if (anIndex != *aFoundIndex)
+        break;
+    // compose the new name
+    std::ostringstream aNewName;
+    aNewName << aName << "_" << anIndex;
+    aName = aNewName.str();
+    // add new index
+    aFound->second.insert(anIndex);
+  }
+
+  return aName;
+}
+
+void correntNonUniqueNames(DocumentPtr theDocument, std::list<FeaturePtr>& theImported)
+{
+  ObjectNameMap aNames;
+  collectOldNames(theDocument, theImported, aNames);
+
+  for (std::list<FeaturePtr>::iterator anIt = theImported.begin();
+       anIt != theImported.end(); ++anIt) {
+    // update name of feature
+    std::string aNewName = uniqueName(*anIt, aNames);
+    (*anIt)->data()->setName(aNewName);
+    // update names of results
+    const std::list<ResultPtr>& aResults = (*anIt)->results();
+    for (std::list<ResultPtr>::const_iterator aRIt = aResults.begin();
+         aRIt != aResults.end(); ++aRIt) {
+      aNewName = uniqueName(*aRIt, aNames);
+      (*aRIt)->data()->setName(aNewName);
+    }
+  }
+}
diff --git a/src/ExchangePlugin/ExchangePlugin_ImportPart.h b/src/ExchangePlugin/ExchangePlugin_ImportPart.h
new file mode 100644 (file)
index 0000000..25d4461
--- /dev/null
@@ -0,0 +1,84 @@
+// 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 EXCHANGEPLUGIN_IMPORTPART_H_
+#define EXCHANGEPLUGIN_IMPORTPART_H_
+
+#include <ExchangePlugin.h>
+#include <ModelAPI_Feature.h>
+
+/**
+ * \class ExchangePlugin_ImportPart
+ * \ingroup Plugins
+ * \brief Feature for import the structure of Part into the current document.
+ */
+class ExchangePlugin_ImportPart : public ModelAPI_Feature
+{
+public:
+  /// Feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_IMPORT_ID("ImportPart");
+    return MY_IMPORT_ID;
+  }
+  /// attribute name of file path
+  inline static const std::string& FILE_PATH_ID()
+  {
+    static const std::string MY_FILE_PATH_ID("file_path");
+    return MY_FILE_PATH_ID;
+  }
+  /// attribute name of target part
+  inline static const std::string& TARGET_PART_ID()
+  {
+    static const std::string MY_TARGET_PART_ID("target_part");
+    return MY_TARGET_PART_ID;
+  }
+  /// attribute name of list of target parts
+  inline static const std::string& TARGET_PARTS_LIST_ID()
+  {
+    static const std::string MY_TARGET_PARTS_LIST_ID("target_parts_list");
+    return MY_TARGET_PARTS_LIST_ID;
+  }
+  /// Default constructor
+  ExchangePlugin_ImportPart();
+
+  /// Returns the unique kind of a feature
+  EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    return ExchangePlugin_ImportPart::ID();
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes
+  EXCHANGEPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Called on change of any argument-attribute of this object
+  /// \param theID identifier of changed attribute
+  EXCHANGEPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Computes or recomputes the results
+  EXCHANGEPLUGIN_EXPORT virtual void execute();
+
+  /// Returns true if this feature is used as macro: creates other features and then removed.
+  EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; }
+
+  /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false.
+  EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; }
+};
+
+#endif /* EXCHANGEPLUGIN_IMPORTPART_H_ */
index 34c3c1b61a3f923ba84384e37867f86c1e235717..ccb5439e7b331337437d4a8b17ad19d2a0586693 100644 (file)
@@ -21,6 +21,8 @@
 #include <ExchangePlugin_Dump.h>
 #include <ExchangePlugin_ImportFeature.h>
 #include <ExchangePlugin_ExportFeature.h>
+#include <ExchangePlugin_ImportPart.h>
+#include <ExchangePlugin_ExportPart.h>
 #include <ExchangePlugin_Validators.h>
 
 #include <Config_PropManager.h>
@@ -43,6 +45,8 @@ ExchangePlugin_Plugin::ExchangePlugin_Plugin()
                               new ExchangePlugin_ImportFormatValidator);
   aFactory->registerValidator("ExchangePlugin_ExportFormat",
                               new ExchangePlugin_ExportFormatValidator);
+  aFactory->registerValidator("ExchangePlugin_InHistory",
+                              new ExchangePlugin_InHistoryValidator);
 }
 
 FeaturePtr ExchangePlugin_Plugin::createFeature(std::string theFeatureID)
@@ -53,6 +57,12 @@ FeaturePtr ExchangePlugin_Plugin::createFeature(std::string theFeatureID)
   if (theFeatureID == ExchangePlugin_ExportFeature::ID()) {
     return FeaturePtr(new ExchangePlugin_ExportFeature);
   } else
+  if (theFeatureID == ExchangePlugin_ImportPart::ID()) {
+    return FeaturePtr(new ExchangePlugin_ImportPart);
+  } else
+  if (theFeatureID == ExchangePlugin_ExportPart::ID()) {
+    return FeaturePtr(new ExchangePlugin_ExportPart);
+  } else
   if (theFeatureID == ExchangePlugin_Dump::ID()) {
     return FeaturePtr(new ExchangePlugin_Dump);
   }
index 33464e0874f11c3fe1661a83ae9819b0a0a968d7..68490efc6d0e659f48d267f811d6faf5b6f2584c 100644 (file)
@@ -27,6 +27,7 @@
 #include <ModelAPI_Object.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeSelectionList.h>
 
 #include <list>
 #include <string>
@@ -98,3 +99,45 @@ bool ExchangePlugin_FormatValidator::isValid(const AttributePtr& theAttribute,
   theError = "File name does not end with any available format.";
   return false;
 }
+
+
+bool ExchangePlugin_InHistoryValidator::isValid(const AttributePtr& theAttribute,
+                                                const std::list<std::string>& theArguments,
+                                                Events_InfoMessage& theError) const
+{
+  std::string anAttributeType = theAttribute->attributeType();
+  if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
+    AttributeSelectionPtr anAttrSelection =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+    ResultPtr aContext = anAttrSelection->context();
+    if (!aContext.get()) {
+      theError = "Error: Context is empty.";
+      return false;
+    }
+
+    FeaturePtr aFeature = ModelAPI_Feature::feature(aContext);
+    if (!aFeature->isInHistory()) {
+      theError = "Error: Feature is not in history.";
+      return false;
+    }
+  } else if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
+    AttributeSelectionListPtr anAttrSelectionList =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+
+    // All objects should not be result constructions.
+    for(int anIndex = 0, aSize = anAttrSelectionList->size(); anIndex < aSize; ++anIndex) {
+      AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
+      if(!isValid(anAttrSelection, theArguments, theError)) {
+        return false;
+      }
+    }
+  } else {
+// LCOV_EXCL_START
+    theError = "Error: Attribute \"%1\" does not supported by this validator.";
+    theError.arg(anAttributeType);
+    return false;
+// LCOV_EXCL_STOP
+  }
+
+  return true;
+}
index b8569a5db3c544a90b962a40c89be439284cd08a..9d0de6c6507d53cddb9c0a93fa3a99a6f3911614 100644 (file)
@@ -71,4 +71,20 @@ class ExchangePlugin_ExportFormatValidator : public ExchangePlugin_FormatValidat
 
 };
 
+/**
+ *  Check the selected result is in history (avoid Origin and coordinate axes and planes).
+ */
+class ExchangePlugin_InHistoryValidator : public ModelAPI_AttributeValidator
+{
+public:
+  /// \return True if the attribute is valid.
+  ///         It checks whether the selected object is in history.
+  /// \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
index 774af05d1efa1fd054a79aa5699b995bb3c6d5af..992e2357b8bce6ab31b7e56b96adf3e75b1578a2 100644 (file)
       <translation>Attribute %1 is not a string.</translation>
     </message>
   </context>
+
+  <context>
+    <name>Export:ExchangePlugin_ExportPart</name>
+    <message>
+      <source>Cannot save the document.</source>
+      <translation>Cannot save the document.</translation>
+    </message>
+    <message>
+      <source>Selected features cannot be exported from the document.</source>
+      <translation>Selected features cannot be exported from the 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>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>
+    </message>
+  </context>
+
+  <context>
+    <name>Import:ExchangePlugin_ImportPart</name>
+    <message>
+      <source>Cannot import the document.</source>
+      <translation>Cannot import the document.</translation>
+    </message>
+  </context>
 </TS>
diff --git a/src/ExchangePlugin/ExchangePlugin_msg_fr.ts b/src/ExchangePlugin/ExchangePlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..930ee4c
--- /dev/null
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Dump</source>
+      <translation>Déverser</translation>
+    </message>
+    <message>
+      <source>Export</source>
+      <translation>Export</translation>
+    </message>
+    <message>
+      <source>Import</source>
+      <translation>Import</translation>
+    </message>
+  </context>
+
+  <!-- Dump -->
+  <context>
+    <name>Dump</name>
+    <message>
+      <source>Dump</source>
+      <translation>Déverser</translation>
+    </message>
+    <message>
+      <source>Dump Python script</source>
+      <translation>Déverser dans un script Python</translation>
+    </message>
+  </context>
+  <context>
+    <name>Dump:file_format</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut "%1" n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Dump:file_path</name>
+    <message>
+      <source>Dump to file</source>
+      <translation>Déverser dans un fichier</translation>
+    </message>
+  </context>
+  <context>
+    <name>Dump:file_path:ExchangePlugin_ExportFormat</name>
+    <message>
+      <source>File name is empty.</source>
+      <translation>Le nom du fichier est vide.</translation>
+    </message>
+  </context>
+
+  <!-- Export -->
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "file_format" is not initialized.</source>
+      <translation>Le nom du fichier d&apos;export n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "selection_list" is not initialized.</source>
+      <translation>Les objets à exporter ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:file_path:ExchangePlugin_ExportFormat</name>
+    <message>
+      <source>File name is empty.</source>
+      <translation>Le nom du fichier d&apos;export n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:selection_list:GeomValidators_Finite</name>
+    <message>
+      <source>Infinite result is selected.</source>
+      <translation>Seules les formes finies peuvent être exportées</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "file_path" is not initialized.</source>
+      <translation>Définir le chemin du fichier exporté</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "selection_list" is not initialized.</source>
+      <translation>Les objets à exporter ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "xao_file_path" is not initialized.</source>
+      <translation>Définir le chemin du fichier XAO exporté</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "xao_author" is not initialized.</source>
+      <translation>Définir l&apos;auteur du fichier XAO</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "xao_geometry_name" is not initialized.</source>
+      <translation>Définir le nom de la géométrie du fichier XAO</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:ExchangePlugin_ExportFormat</name>
+    <message>
+      <source>%1 is not initialized.</source>
+      <translation>L&apos;attribut %1 n&apos;est pas initialisé.</translation>
+    </message>
+    <message>
+      <source>%1 is not a string attribute.</source>
+      <translation>L&apos;attribut %1 n&apos;est pas une chaîne.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export</name>
+    <message>
+      <source>Export</source>
+      <translation>Export</translation>
+    </message>
+    <message>
+      <source>Export to file</source>
+      <translation>Exporter dans un fichier</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:ExportType</name>
+    <message>
+      <source>BREP, STEP, IGES</source>
+      <translation>BREP, STEP, IGES</translation>
+    </message>
+    <message>
+      <source>XAO</source>
+      <translation>XAO</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:file_path</name>
+    <message>
+      <source>Export file</source>
+      <translation>Fichier d&apos;export</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:selection_list</name>
+    <message>
+      <source>Select a set of objects</source>
+      <translation>Sélectionnez un ensemble d&apos;objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:xao_author</name>
+    <message>
+      <source>Author</source>
+      <translation>Auteur</translation>
+    </message>
+    <message>
+      <source>Please input the author</source>
+      <translation>S&apos;il vous plaît saisissez l&apos;auteur</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:xao_file_path</name>
+    <message>
+      <source>Export file</source>
+      <translation>Fichier d&apos;export</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:xao_file_path:ExchangePlugin_ExportFormat</name>
+    <message>
+      <source>%1 is not initialized.</source>
+      <translation>%1 n&apos;est pas initialisé.</translation>
+    </message>
+    <message>
+      <source>File name is empty.</source>
+      <translation>Le nom du fichier est vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Export:xao_geometry_name</name>
+    <message>
+      <source>Geometry name</source>
+      <translation>Nom de la géométrie</translation>
+    </message>
+    <message>
+      <source>Please input the geometry name</source>
+      <translation>S&apos;il vous plaît entrer le nom de la géométrie</translation>
+    </message>
+  </context>
+
+  <!-- Import -->
+  <context>
+    <name>Import:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "file_path" is not initialized.</source>
+      <translation>Nom du fichier d&apos;entrée à importer</translation>
+    </message>
+  </context>
+  <context>
+    <name>Import:file_path:ExchangePlugin_ImportFormat</name>
+    <message>
+      <source>File name is empty.</source>
+      <translation>Nom du fichier d&apos;entrée à importer</translation>
+    </message>
+  </context>
+  <context>
+    <name>Import</name>
+    <message>
+      <source>Import</source>
+      <translation>Import</translation>
+    </message>
+    <message>
+      <source>Import a file</source>
+      <translation>Importer un fichier</translation>
+    </message>
+  </context>
+  <context>
+    <name>Import:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Importer le fichier</translation>
+    </message>
+  </context>
+
+</TS>
diff --git a/src/ExchangePlugin/Test/TestExportPart_Failure_1.py b/src/ExchangePlugin/Test/TestExportPart_Failure_1.py
new file mode 100644 (file)
index 0000000..65ce866
--- /dev/null
@@ -0,0 +1,72 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename, [Part_1.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting result of Part_1 should fail"
diff --git a/src/ExchangePlugin/Test/TestExportPart_Failure_2.py b/src/ExchangePlugin/Test/TestExportPart_Failure_2.py
new file mode 100644 (file)
index 0000000..ceca5f1
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Box_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} from document {} should fail".format(featureToExport.name(), Part_1.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Failure_3.py b/src/ExchangePlugin/Test/TestExportPart_Failure_3.py
new file mode 100644 (file)
index 0000000..8f3e467
--- /dev/null
@@ -0,0 +1,40 @@
+# 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 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)
+model.do()
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Part_1/[Box_1_1/Front][Box_1_1/Right][Box_1_1/Top]"))
+Translation_1 = model.addTranslation(partSet, [model.selection("COMPOUND", "Part_1/")], model.selection("EDGE", "Axis_4"), 10)
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of PartSet should fail"
diff --git a/src/ExchangePlugin/Test/TestExportPart_FullPartSet.py b/src/ExchangePlugin/Test/TestExportPart_FullPartSet.py
new file mode 100644 (file)
index 0000000..5e5f8ac
--- /dev/null
@@ -0,0 +1,72 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Failed to export full PartSet"
diff --git a/src/ExchangePlugin/Test/TestExportPart_FullPart_1.py b/src/ExchangePlugin/Test/TestExportPart_FullPart_1.py
new file mode 100644 (file)
index 0000000..e0eeee3
--- /dev/null
@@ -0,0 +1,72 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of Part_1 should fail"
diff --git a/src/ExchangePlugin/Test/TestExportPart_FullPart_2.py b/src/ExchangePlugin/Test/TestExportPart_FullPart_2.py
new file mode 100644 (file)
index 0000000..6b741ab
--- /dev/null
@@ -0,0 +1,72 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(Part_2_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export Part_2 to file {}".format(filename)
diff --git a/src/ExchangePlugin/Test/TestExportPart_PartSet.py b/src/ExchangePlugin/Test/TestExportPart_PartSet.py
new file mode 100644 (file)
index 0000000..3c8b142
--- /dev/null
@@ -0,0 +1,72 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename, [Axis_4.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export construction elements of PartSet"
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_1.py b/src/ExchangePlugin/Test/TestExportPart_Results_1.py
new file mode 100644 (file)
index 0000000..6c4266e
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Point_2
+
+model.begin()
+model.exportPart(partSet, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_2.py b/src/ExchangePlugin/Test/TestExportPart_Results_2.py
new file mode 100644 (file)
index 0000000..f2c9ac6
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Axis_4
+
+model.begin()
+model.exportPart(partSet, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_3.py b/src/ExchangePlugin/Test/TestExportPart_Results_3.py
new file mode 100644 (file)
index 0000000..0b723a2
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Sketch_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_4.py b/src/ExchangePlugin/Test/TestExportPart_Results_4.py
new file mode 100644 (file)
index 0000000..a02183e
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Extrusion_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} should fail".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_5.py b/src/ExchangePlugin/Test/TestExportPart_Results_5.py
new file mode 100644 (file)
index 0000000..b3753ed
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Sketch_2
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} should fail".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_6.py b/src/ExchangePlugin/Test/TestExportPart_Results_6.py
new file mode 100644 (file)
index 0000000..0afd739
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Revolution_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} should fail".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_7.py b/src/ExchangePlugin/Test/TestExportPart_Results_7.py
new file mode 100644 (file)
index 0000000..6dc1b76
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Box_1
+
+model.begin()
+model.exportPart(Part_2_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestExportPart_Results_8.py b/src/ExchangePlugin/Test/TestExportPart_Results_8.py
new file mode 100644 (file)
index 0000000..1a03585
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Translation_1
+
+model.begin()
+model.exportPart(Part_2_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterCurrent_1.py b/src/ExchangePlugin/Test/TestImportPart_AfterCurrent_1.py
new file mode 100644 (file)
index 0000000..0d104a8
--- /dev/null
@@ -0,0 +1,113 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+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)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export all features from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features from {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+model.end()
+
+# store features before the import
+featuresBeforeImportBegin = Part_1_doc.allFeatures()
+featuresBeforeImportBegin.pop_back() # remove Translation_1
+featuresBeforeImportBegin.pop_back() # remove Extrusion_1
+featuresBeforeImportFinish = [Translation_1.feature(), Extrusion_1.feature()]
+
+# import the document after Sketch_1
+model.begin()
+model.importPart(Part_1_doc, filename, Sketch_1)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImportBegin:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+for feat in featuresBeforeImportFinish:
+    if features.back().getKind() == feat.getKind() and features.back().name() == feat.name():
+        features.pop_back()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterCurrent_2.py b/src/ExchangePlugin/Test/TestImportPart_AfterCurrent_2.py
new file mode 100644 (file)
index 0000000..3f75cb3
--- /dev/null
@@ -0,0 +1,112 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+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)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export all features from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features from {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+model.end()
+
+# store features before the import
+featuresBeforeImportBegin = Part_1_doc.allFeatures()
+featuresBeforeImportBegin.pop_back() # remove Translation_1
+featuresBeforeImportFinish = [Translation_1.feature()]
+
+# import the document after Extrusion_1
+model.begin()
+model.importPart(Part_1_doc, filename, Extrusion_1)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImportBegin:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+for feat in featuresBeforeImportFinish:
+    if features.back().getKind() == feat.getKind() and features.back().name() == feat.name():
+        features.pop_back()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterLast_1.py b/src/ExchangePlugin/Test/TestImportPart_AfterLast_1.py
new file mode 100644 (file)
index 0000000..dd465a4
--- /dev/null
@@ -0,0 +1,137 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = [Point_2.feature(), Axis_4.feature()]
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export feature from PartSet
+featureToExport = Axis_4
+model.begin()
+model.exportPart(partSet, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterLast_2.py b/src/ExchangePlugin/Test/TestImportPart_AfterLast_2.py
new file mode 100644 (file)
index 0000000..218612e
--- /dev/null
@@ -0,0 +1,142 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Sketch_1
+
+# store the reference data
+sketch = featureToCompositeFeature(featureToExport.feature())
+features = [sketch]
+for i in range(0, sketch.numberOfSubs()):
+    features.append(sketch.subFeature(i))
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export sketch from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterLast_3.py b/src/ExchangePlugin/Test/TestImportPart_AfterLast_3.py
new file mode 100644 (file)
index 0000000..f3f4c10
--- /dev/null
@@ -0,0 +1,138 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Box_1
+
+# store the reference data
+features = [featureToExport.feature()]
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export feature from Part_2
+model.begin()
+model.exportPart(Part_2_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterLast_4.py b/src/ExchangePlugin/Test/TestImportPart_AfterLast_4.py
new file mode 100644 (file)
index 0000000..2116733
--- /dev/null
@@ -0,0 +1,138 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Translation_1
+
+# store the reference data
+features = [Box_1.feature(), Translation_1.feature()]
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export all features from Part_2
+model.begin()
+model.exportPart(Part_2_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterLast_5.py b/src/ExchangePlugin/Test/TestImportPart_AfterLast_5.py
new file mode 100644 (file)
index 0000000..1ad3b03
--- /dev/null
@@ -0,0 +1,137 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_2_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = [Box_1.feature(), Plane_4.feature()]
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export specified features from Part_2
+model.begin()
+model.exportPart(Part_2_doc, filename, [Box_1.result(), Plane_4.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features {} and {}".format(feature[0].name(), features[1].name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_AfterLast_6.py b/src/ExchangePlugin/Test/TestImportPart_AfterLast_6.py
new file mode 100644 (file)
index 0000000..58dac78
--- /dev/null
@@ -0,0 +1,138 @@
+# 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_2_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = [Box_1.feature(), Translation_1.feature()]
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+# export all features before the history line from Part_2
+model.begin()
+Part_2_doc.setCurrentFeature(Translation_1.feature(), False)
+model.exportPart(Part_2_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features {} and {}".format(feature[0].name(), features[1].name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+    if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+        features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_Construction_1.py b/src/ExchangePlugin/Test/TestImportPart_Construction_1.py
new file mode 100644 (file)
index 0000000..45b0529
--- /dev/null
@@ -0,0 +1,82 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# PartSet => PartSet
+
+model.begin()
+partSet = model.moduleDocument()
+Point_1 = model.addPoint(partSet, 100, 100, 100)
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+model.end()
+
+# store the reference data
+features = partSet.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export PartSet"
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+model.importPart(partSet, filename)
+model.end()
+
+# Test 1. No Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 0)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = partSet.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_Construction_2.py b/src/ExchangePlugin/Test/TestImportPart_Construction_2.py
new file mode 100644 (file)
index 0000000..bf0db67
--- /dev/null
@@ -0,0 +1,86 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# PartSet => Part
+
+model.begin()
+partSet = model.moduleDocument()
+Point_1 = model.addPoint(partSet, 100, 100, 100)
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+model.end()
+
+# store the reference data (without Origin, coordinate axes and planes)
+features = partSet.allFeatures()
+for i in range(0, 7):
+    features.pop_front()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export PartSet"
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# Test 1. No Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_Construction_3.py b/src/ExchangePlugin/Test/TestImportPart_Construction_3.py
new file mode 100644 (file)
index 0000000..5a84bd9
--- /dev/null
@@ -0,0 +1,87 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# Part => PartSet
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+model.importPart(partSet, filename)
+model.end()
+
+# Test 1. No new Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 0)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = partSet.allFeatures()
+for i in range(0, 7):
+    # exclude Origin, coordinate axes and planes
+    features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_Construction_4.py b/src/ExchangePlugin/Test/TestImportPart_Construction_4.py
new file mode 100644 (file)
index 0000000..ae3fa13
--- /dev/null
@@ -0,0 +1,86 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# Part => Part
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# Test 1. No new Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_Multiple.py b/src/ExchangePlugin/Test/TestImportPart_Multiple.py
new file mode 100644 (file)
index 0000000..7fdbc7e
--- /dev/null
@@ -0,0 +1,115 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+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)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Translation_1.setName("MovedBox")
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# export all features from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features from {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+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(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+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())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+model.end()
+
+
+def checkUniqueNames(theDocument):
+    features = theDocument.allObjects()
+    names = set()
+    for feat in features:
+        name = feat.data().name()
+        if not name == "":
+            assert(not name in names), "'{}' already exists in {}".format(name, names)
+            names.add(name)
+
+
+# import the document at the end
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+# import the document after Extrusion_1
+model.begin()
+model.importPart(Part_1_doc, filename, Extrusion_1)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+# import the document after Sketch_1
+model.begin()
+model.importPart(Part_1_doc, filename, Sketch_1)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+# import the document after Translation_1
+model.begin()
+model.importPart(Part_1_doc, filename, Translation_1)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_ToEmptyPart.py b/src/ExchangePlugin/Test/TestImportPart_ToEmptyPart.py
new file mode 100644 (file)
index 0000000..2df7249
--- /dev/null
@@ -0,0 +1,102 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "Axis_1"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# Test 1. No new Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/Test/TestImportPart_ToEmptyPartSet.py b/src/ExchangePlugin/Test/TestImportPart_ToEmptyPartSet.py
new file mode 100644 (file)
index 0000000..0f0fee8
--- /dev/null
@@ -0,0 +1,102 @@
+# 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "Axis_1"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+    res = []
+    for r in feat.results():
+        res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+    refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+model.importPart(partSet, filename)
+model.end()
+
+# Test 1. New Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+newPart = modelAPI_ResultPart(objectToResult(partSet.object(ModelAPI_ResultPart.group(), 0)))
+newPart_doc = newPart.partDoc()
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = newPart_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+    assert(feat.getKind() == ref[0])
+    for fv, rv in zip(feat.results(), ref[1]):
+        assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
diff --git a/src/ExchangePlugin/icons/export_part.png b/src/ExchangePlugin/icons/export_part.png
new file mode 100644 (file)
index 0000000..98e423e
Binary files /dev/null and b/src/ExchangePlugin/icons/export_part.png differ
diff --git a/src/ExchangePlugin/icons/import_part.png b/src/ExchangePlugin/icons/import_part.png
new file mode 100644 (file)
index 0000000..8443bd1
Binary files /dev/null and b/src/ExchangePlugin/icons/import_part.png differ
index 59a246ecdcbe081fbe1eaa540f736ffad1039893..ac0ad0711fc51012eed6a3f00254d01aaaaa232a 100644 (file)
@@ -12,7 +12,7 @@
         <source path="export_widget.xml" />
       </feature>
       <feature id="Dump" title="Dump" tooltip="Dump Python script" icon="icons/Exchange/dump.png"
-               helpfile="dumpFeature.html">
+               helpfile="dumpFeature.html" abort_confirmation="false">
         <export_file_selector id="file_path"
                               type="save"
                               title="Dump to file"
              tooltip="To use geometrical order for identification of selected shapes"
              default="false"/> -->
       </feature>
+
+      <feature id="ImportPart" title="Import part" tooltip="Import features from file" icon="icons/Exchange/import_part.png"
+               helpfile="importPart.html"
+               internal="1">
+        <file_selector id="file_path" title="Import file" path="">
+          <validator id="ExchangePlugin_ImportFormat" parameters="shaperpart:Part" />
+        </file_selector>
+        <choice id="target_part"
+                string_list_attribute="target_parts_list"
+                label="Import to"
+                tooltip="Select the part to import the document" />
+      </feature>
+      <feature id="ExportPart" title="Export part" tooltip="Export structure of the Part to file" icon="icons/Exchange/export_part.png"
+               helpfile="exportPart.html"
+               internal="1">
+        <export_file_selector id="file_path"
+                              type="save"
+                              title="Export file"
+                              path="">
+          <validator id="ExchangePlugin_ExportFormat"
+                     parameters="shaperpart:Part" />
+        </export_file_selector>
+        <multi_selector id="selection_list"
+                        tooltip="Select features or results"
+                        shape_types="Vertices Edges Faces Solids Compsolids Objects">
+          <validator id="GeomValidators_GlobalSelection" />
+          <validator id="ExchangePlugin_InHistory" />
+        </multi_selector>
+      </feature>
     </group>
   </workbench>
 </plugin>
\ No newline at end of file
index 934a9ae02e0c35113e8d653070896dbb6fd9f227..af4102734031cc1e34379f6061a6b9cfd9292c4e 100644 (file)
@@ -155,6 +155,8 @@ void FeaturesAPI_ExtrusionBoolean::dump(ModelHighAPI_Dumper& theDumper) const
 
     theDumper << ", " << anAttrToObject << ", " << anAttrToOffset <<
       ", " << anAttrFromObject << ", " << anAttrFromOffset;
+  } else {
+    // Through all
   }
 
   AttributeSelectionListPtr anAttrBoolObjects =
@@ -183,6 +185,20 @@ FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
   initialize();
 }
 
+//==================================================================================================
+FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
+  const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+: FeaturesAPI_ExtrusionBoolean(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theBaseObjects, mybaseObjects);
+    fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod);
+    setBooleanObjects(theBooleanObjects);
+  }
+}
+
 //==================================================================================================
 FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -198,6 +214,22 @@ FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
   }
 }
 
+//==================================================================================================
+FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
+  const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+  const ModelHighAPI_Selection& theDirection,
+  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+: FeaturesAPI_ExtrusionBoolean(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theBaseObjects, mybaseObjects);
+    fillAttribute(theDirection, mydirection);
+    fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod);
+    setBooleanObjects(theBooleanObjects);
+  }
+}
+
 //==================================================================================================
 FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -287,6 +319,17 @@ FeaturesAPI_ExtrusionCut::FeaturesAPI_ExtrusionCut(
   }
 }
 
+//==================================================================================================
+ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    thePart->addFeature(FeaturesPlugin_ExtrusionCut::ID());
+  return ExtrusionCutPtr(new FeaturesAPI_ExtrusionCut(aFeature, theBaseObjects,
+                                                      theBooleanObjects));
+}
+
 //==================================================================================================
 ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
                                 const std::list<ModelHighAPI_Selection>& theBaseObjects,
@@ -299,6 +342,18 @@ ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePar
                                                       theSize, theBooleanObjects));
 }
 
+//==================================================================================================
+ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const ModelHighAPI_Selection& theDirection,
+                                const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    thePart->addFeature(FeaturesPlugin_ExtrusionCut::ID());
+  return ExtrusionCutPtr(new FeaturesAPI_ExtrusionCut(aFeature, theBaseObjects, theDirection,
+                                                      theBooleanObjects));
+}
+
 //==================================================================================================
 ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
                                 const std::list<ModelHighAPI_Selection>& theBaseObjects,
@@ -394,6 +449,20 @@ FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
   initialize();
 }
 
+//==================================================================================================
+FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
+  const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+: FeaturesAPI_ExtrusionBoolean(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theBaseObjects, mybaseObjects);
+    fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod);
+    setBooleanObjects(theBooleanObjects);
+  }
+}
+
 //==================================================================================================
 FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -409,6 +478,22 @@ FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
   }
 }
 
+//==================================================================================================
+FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
+  const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+  const ModelHighAPI_Selection& theDirection,
+  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+: FeaturesAPI_ExtrusionBoolean(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theBaseObjects, mybaseObjects);
+    fillAttribute(theDirection, mydirection);
+    fillAttribute(FeaturesPlugin_Extrusion::CREATION_METHOD_THROUGH_ALL(), mycreationMethod);
+    setBooleanObjects(theBooleanObjects);
+  }
+}
+
 //==================================================================================================
 FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -498,6 +583,17 @@ FeaturesAPI_ExtrusionFuse::FeaturesAPI_ExtrusionFuse(
   }
 }
 
+//==================================================================================================
+ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    thePart->addFeature(FeaturesPlugin_ExtrusionFuse::ID());
+  return ExtrusionFusePtr(new FeaturesAPI_ExtrusionFuse(aFeature, theBaseObjects,
+                                                        theBooleanObjects));
+}
+
 //==================================================================================================
 ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                                   const std::list<ModelHighAPI_Selection>& theBaseObjects,
@@ -510,6 +606,18 @@ ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& theP
                                                         theSize, theBooleanObjects));
 }
 
+//==================================================================================================
+ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                  const ModelHighAPI_Selection& theDirection,
+                                  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    thePart->addFeature(FeaturesPlugin_ExtrusionFuse::ID());
+  return ExtrusionFusePtr(new FeaturesAPI_ExtrusionFuse(aFeature, theBaseObjects,
+                                                        theDirection, theBooleanObjects));
+}
+
 //==================================================================================================
 ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                                   const std::list<ModelHighAPI_Selection>& theBaseObjects,
index 42a4791195bcdabcdc8e9b4776fe5b2598e1ab68..c5777d3192130c161619a5ca0a1fbdfcedf1d507 100644 (file)
@@ -130,6 +130,12 @@ public:
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature);
 
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                    const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
   /// Constructor with values.
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -137,6 +143,13 @@ public:
                                     const ModelHighAPI_Double& theSize,
                                     const std::list<ModelHighAPI_Selection>& theBooleanObjects);
 
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                    const ModelHighAPI_Selection& theDirection,
+                                    const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
   /// Constructor with values.
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_ExtrusionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -187,6 +200,13 @@ public:
 /// Pointer on ExtrusionCut object.
 typedef std::shared_ptr<FeaturesAPI_ExtrusionCut> ExtrusionCutPtr;
 
+/// \ingroup CPPHighAPI
+/// \brief Create ExtrusionCut feature.
+FEATURESAPI_EXPORT
+ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
 /// \ingroup CPPHighAPI
 /// \brief Create ExtrusionCut feature.
 FEATURESAPI_EXPORT
@@ -195,6 +215,14 @@ ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePar
                                 const ModelHighAPI_Double& theSize,
                                 const std::list<ModelHighAPI_Selection>& theBooleanObjects);
 
+/// \ingroup CPPHighAPI
+/// \brief Create ExtrusionCut feature.
+FEATURESAPI_EXPORT
+ExtrusionCutPtr addExtrusionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                const ModelHighAPI_Selection& theDirection,
+                                const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
 /// \ingroup CPPHighAPI
 /// \brief Create ExtrusionCut feature.
 FEATURESAPI_EXPORT
@@ -259,6 +287,12 @@ public:
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature);
 
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                     const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
   /// Constructor with values.
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -266,6 +300,13 @@ public:
                                      const ModelHighAPI_Double& theSize,
                                      const std::list<ModelHighAPI_Selection>& theBooleanObjects);
 
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                     const ModelHighAPI_Selection& theDirection,
+                                     const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
   /// Constructor with values.
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_ExtrusionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -316,6 +357,13 @@ public:
 /// Pointer on ExtrusionFuse object.
 typedef std::shared_ptr<FeaturesAPI_ExtrusionFuse> ExtrusionFusePtr;
 
+/// \ingroup CPPHighAPI
+/// \brief Create ExtrusionFuse feature.
+FEATURESAPI_EXPORT
+ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                  const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
 /// \ingroup CPPHighAPI
 /// \brief Create ExtrusionFuse feature.
 FEATURESAPI_EXPORT
@@ -324,6 +372,14 @@ ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& theP
                                   const ModelHighAPI_Double& theSize,
                                   const std::list<ModelHighAPI_Selection>& theBooleanObjects);
 
+/// \ingroup CPPHighAPI
+/// \brief Create ExtrusionFuse feature.
+FEATURESAPI_EXPORT
+ExtrusionFusePtr addExtrusionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                  const ModelHighAPI_Selection& theDirection,
+                                  const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
 /// \ingroup CPPHighAPI
 /// \brief Create ExtrusionFuse feature.
 FEATURESAPI_EXPORT
index 385244275779ff6a8c4b0d2adf9dcc13dac69b18..3f595c2e933fffad62bf84828cee4dfcd6433aab 100644 (file)
@@ -94,7 +94,7 @@ void FeaturesAPI_RevolutionBoolean::setAngle(const ModelHighAPI_Double& theAngle
 //==================================================================================================
 void FeaturesAPI_RevolutionBoolean::setPlanesAndOffsets(const ModelHighAPI_Selection& theToObject,
                                                         const ModelHighAPI_Double& theToOffset,
-                                                      const ModelHighAPI_Selection& theFromObject,
+                                                        const ModelHighAPI_Selection& theFromObject,
                                                         const ModelHighAPI_Double& theFromOffset)
 {
   fillAttribute(FeaturesPlugin_Revolution::CREATION_METHOD_BY_PLANES(), mycreationMethod);
@@ -158,6 +158,8 @@ void FeaturesAPI_RevolutionBoolean::dump(ModelHighAPI_Dumper& theDumper) const
 
     theDumper << ", " << anAttrToObject << ", " << anAttrToOffset <<
       ", " << anAttrFromObject << ", " << anAttrFromOffset;
+  } else {
+    // Through All
   }
 
   AttributeSelectionListPtr anAttrBoolObjects =
@@ -185,6 +187,22 @@ FeaturesAPI_RevolutionCut::FeaturesAPI_RevolutionCut(
   initialize();
 }
 
+//==================================================================================================
+FeaturesAPI_RevolutionCut::FeaturesAPI_RevolutionCut(
+  const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+  const ModelHighAPI_Selection& theAxis,
+  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+: FeaturesAPI_RevolutionBoolean(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theBaseObjects, mybaseObjects);
+    fillAttribute(theAxis, myaxis);
+    fillAttribute(FeaturesPlugin_Revolution::CREATION_METHOD_THROUGH_ALL(), mycreationMethod);
+    setBooleanObjects(theBooleanObjects);
+  }
+}
+
 //==================================================================================================
 FeaturesAPI_RevolutionCut::FeaturesAPI_RevolutionCut(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -246,6 +264,18 @@ FeaturesAPI_RevolutionCut::FeaturesAPI_RevolutionCut(
   }
 }
 
+//==================================================================================================
+RevolutionCutPtr addRevolutionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                  const ModelHighAPI_Selection& theAxis,
+                                  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    thePart->addFeature(FeaturesPlugin_RevolutionCut::ID());
+  return RevolutionCutPtr(new FeaturesAPI_RevolutionCut(aFeature, theBaseObjects,
+                                                        theAxis, theBooleanObjects));
+}
+
 //==================================================================================================
 RevolutionCutPtr addRevolutionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
                                   const std::list<ModelHighAPI_Selection>& theBaseObjects,
@@ -308,6 +338,22 @@ FeaturesAPI_RevolutionFuse::FeaturesAPI_RevolutionFuse(
   initialize();
 }
 
+//==================================================================================================
+FeaturesAPI_RevolutionFuse::FeaturesAPI_RevolutionFuse(
+  const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+  const ModelHighAPI_Selection& theAxis,
+  const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+: FeaturesAPI_RevolutionBoolean(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theBaseObjects, mybaseObjects);
+    fillAttribute(theAxis, myaxis);
+    fillAttribute(FeaturesPlugin_Revolution::CREATION_METHOD_THROUGH_ALL(), mycreationMethod);
+    setBooleanObjects(theBooleanObjects);
+  }
+}
+
 //==================================================================================================
 FeaturesAPI_RevolutionFuse::FeaturesAPI_RevolutionFuse(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -371,6 +417,18 @@ FeaturesAPI_RevolutionFuse::FeaturesAPI_RevolutionFuse(
   }
 }
 
+//==================================================================================================
+RevolutionFusePtr addRevolutionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                    const ModelHighAPI_Selection& theAxis,
+                                    const std::list<ModelHighAPI_Selection>& theBooleanObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    thePart->addFeature(FeaturesPlugin_RevolutionFuse::ID());
+  return RevolutionFusePtr(new FeaturesAPI_RevolutionFuse(aFeature, theBaseObjects,
+                                                          theAxis, theBooleanObjects));
+}
+
 //==================================================================================================
 RevolutionFusePtr addRevolutionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                                     const std::list<ModelHighAPI_Selection>& theBaseObjects,
index cd7809176800c9941d44decdb3551cd953d0a469..5f636c0811c9ef21289a006d077d2b819e19d935 100644 (file)
@@ -127,6 +127,13 @@ public:
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_RevolutionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature);
 
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_RevolutionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                     const ModelHighAPI_Selection& theAxis,
+                                     const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
   /// Constructor with values.
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_RevolutionCut(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -159,6 +166,14 @@ public:
 /// Pointer on RevolutionCut object.
 typedef std::shared_ptr<FeaturesAPI_RevolutionCut> RevolutionCutPtr;
 
+/// \ingroup CPPHighAPI
+/// \brief Create RevolutionCut feature.
+FEATURESAPI_EXPORT
+RevolutionCutPtr addRevolutionCut(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                  const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                  const ModelHighAPI_Selection& theAxis,
+                                  const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
 /// \ingroup CPPHighAPI
 /// \brief Create RevolutionCut feature.
 FEATURESAPI_EXPORT
@@ -204,6 +219,13 @@ public:
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_RevolutionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature);
 
+  /// Constructor with values.
+  FEATURESAPI_EXPORT
+  explicit FeaturesAPI_RevolutionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                      const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                      const ModelHighAPI_Selection& theAxis,
+                                      const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
   /// Constructor with values.
   FEATURESAPI_EXPORT
   explicit FeaturesAPI_RevolutionFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -236,6 +258,14 @@ public:
 /// Pointer on RevolutionFuse object.
 typedef std::shared_ptr<FeaturesAPI_RevolutionFuse> RevolutionFusePtr;
 
+/// \ingroup CPPHighAPI
+/// \brief Create RevolutionFuse feature.
+FEATURESAPI_EXPORT
+RevolutionFusePtr addRevolutionFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                    const ModelHighAPI_Selection& theAxis,
+                                    const std::list<ModelHighAPI_Selection>& theBooleanObjects);
+
 /// \ingroup CPPHighAPI
 /// \brief Create RevolutionFuse feature.
 FEATURESAPI_EXPORT
index d2e81e3c48168db8513ddde581364ced19c30a32..ea14d9ea6191b21c6dcb092626702e2aecae0a7a 100644 (file)
@@ -139,6 +139,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     FeaturesPlugin_msg_en.ts
+    FeaturesPlugin_msg_fr.ts
     FeaturesPlugin_msg_ru.ts
 )
 
@@ -180,9 +181,11 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestExtrusionCut_BySize.py
                TestExtrusionCut_ByPlanesAndOffsets.py
                TestExtrusionCut_ByFaces.py
+               TestExtrusionCut_ThroughAll.py
                TestExtrusionFuse.py
                TestExtrusionFuse_BySize.py
                TestExtrusionFuse_ByPlanesAndOffsets.py
+               TestExtrusionFuse_ThroughAll.py
                TestExtrusion_ErrorMsg.py
                TestExtrusion_ZeroOffsetError.py
                TestExtrusion_ByFaces01.py
@@ -212,9 +215,11 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestRevolutionCut.py
                TestRevolutionCut_ByAngle.py
                TestRevolutionCut_ByPlanesAndOffsets.py
+               TestRevolutionCut_ThroughAll.py
                TestRevolutionFuse.py
                TestRevolutionFuse_ByAngle.py
                TestRevolutionFuse_ByPlanesAndOffsets.py
+               TestRevolutionFuse_ThroughAll.py
                TestCompositeFeaturesOnCompSolids.py
                TestPartition.py
                TestPartition_ErrorMsg.py
index 31bb1335d37a8671b9e7c52abdb2a2a420008795..c4c39566c262f186296217512791e44bfc1e3992 100644 (file)
@@ -83,7 +83,7 @@ public:
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 public:
index 76ffe70b1906a57e9df40350e908f77beb7f4fd8..c49a47666d7b9a5ae07ec24a3a0b84dc81ac4907 100644 (file)
@@ -49,7 +49,7 @@ public:
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 public:
index 386cb6ec6fb88c0dd9917c042da2b4c8590b03de..3e8d145e1e10448aa600ebce5ea623e161687164 100644 (file)
@@ -46,7 +46,7 @@ public:
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 public:
index ceaab696cda12416e929b0b3477ba9b8aeaf9d75..242629097c356f4da09edfce3d72be2deb57fcbb 100644 (file)
@@ -111,9 +111,10 @@ void FeaturesPlugin_BooleanFuse::execute()
 
   // Collecting solids from compsolids which will not be modified
   // in boolean operation and will be added to result.
+  bool isProcessCompsolid = !isSimpleCreation || aFuseVersion >= THE_VERSION_1;
   ListOfShape aShapesToAdd;
   for (ObjectHierarchy::Iterator anObjectsIt = anObjectsHierarchy.Begin();
-       !isSimpleCreation && anObjectsIt != anObjectsHierarchy.End();
+       isProcessCompsolid && anObjectsIt != anObjectsHierarchy.End();
        ++anObjectsIt) {
     GeomShapePtr anObject = *anObjectsIt;
     GeomShapePtr aParent = anObjectsHierarchy.Parent(anObject, false);
@@ -142,8 +143,11 @@ void FeaturesPlugin_BooleanFuse::execute()
       aMakeShapeList->appendAlgo(aCutAlgo);
     }
   }
-  anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
-                          anEdgesAndFaces.end());
+
+  if (aShapesToAdd.empty() || !aCuttedEdgesAndFaces) {
+    anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
+                            anEdgesAndFaces.end());
+  }
 
   // If we have compsolids then cut with not used solids all others.
   if (!aShapesToAdd.empty()) {
index a16c8781ae07eff63d923f11bfb36a3af5422998..db8c2d01d6eae9332032f41e873f9e7edd3c28b4 100644 (file)
@@ -88,7 +88,7 @@ public:
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 public:
index ed611c0aeccc8a202041893e3f7655a8c4971beb..ffdc4999be3453c756541e77eeae0cd31cafec96 100644 (file)
@@ -62,7 +62,7 @@ public:
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 public:
index cad7204e980f8507228a17aaa0b3e7e78ec41eb3..eea23daf7737c1aa00395697b83c090c096c82bc 100644 (file)
@@ -103,7 +103,7 @@ public:
     return MY_ANGLE_ID;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index 3c5681de0b6b4bb1a4383eac5d0ba8e1d5803d13..13a0434682055e820fe128239c3242b63e4acff3 100644 (file)
@@ -46,7 +46,7 @@ public:
     return MY_OBJECTS_ID;
   }
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void executeCompositeBoolean();
 
 protected:
index bfcbde007c375efe9356930b07a5597be1e84e97..57b1ba874b20897df91b6a0d5875b18093f244c9 100644 (file)
@@ -101,53 +101,20 @@ bool FeaturesPlugin_Extrusion::makeExtrusions(ListOfShape& theBaseShapes,
   getBaseShapes(theBaseShapes);
 
   //Getting direction.
-  static const std::string aSelectionError = "Error: The direction shape selection is bad.";
-  AttributeSelectionPtr aSelection = selection(DIRECTION_OBJECT_ID());
-  GeomShapePtr aShape = aSelection->value();
-  if (!aShape.get()) {
-    if (aSelection->context().get()) {
-      aShape = aSelection->context()->shape();
-    }
-  }
-
-  GeomEdgePtr anEdge;
-  if (aShape.get()) {
-    if (aShape->isEdge())
-    {
-      anEdge = aShape->edge();
-    }
-    else if (aShape->isCompound())
-    {
-      GeomAPI_ShapeIterator anIt(aShape);
-      anEdge = anIt.current()->edge();
-    }
-  }
-
   std::shared_ptr<GeomAPI_Dir> aDir;
-  if(anEdge.get()) {
-    if(anEdge->isLine()) {
-      aDir = anEdge->line()->direction();
-    }
-  }
+  getDirection(aDir);
 
   // Getting sizes.
   double aToSize = 0.0;
   double aFromSize = 0.0;
-
-  if(string(CREATION_METHOD())->value() == CREATION_METHOD_BY_SIZES()) {
-    aToSize = real(TO_SIZE_ID())->value();
-    aFromSize = real(FROM_SIZE_ID())->value();
-  } else {
-    aToSize = real(TO_OFFSET_ID())->value();
-    aFromSize = real(FROM_OFFSET_ID())->value();
-  }
+  getSizes(aToSize, aFromSize);
 
   // Getting bounding planes.
   GeomShapePtr aToShape;
   GeomShapePtr aFromShape;
 
   if(string(CREATION_METHOD())->value() == CREATION_METHOD_BY_PLANES()) {
-    aSelection = selection(TO_OBJECT_ID());
+    AttributeSelectionPtr aSelection = selection(TO_OBJECT_ID());
     if(aSelection.get()) {
       aToShape = std::dynamic_pointer_cast<GeomAPI_Shape>(aSelection->value());
       if(!aToShape.get() && aSelection->context().get()) {
@@ -214,3 +181,48 @@ void FeaturesPlugin_Extrusion::storeResultWithBoundaries(
 
   setResult(aResultBody, theIndex);
 }
+
+//=================================================================================================
+void FeaturesPlugin_Extrusion::getDirection(std::shared_ptr<GeomAPI_Dir>& theDir)
+{
+  static const std::string aSelectionError = "Error: The direction shape selection is bad.";
+  AttributeSelectionPtr aSelection = selection(DIRECTION_OBJECT_ID());
+  GeomShapePtr aShape = aSelection->value();
+  if (!aShape.get()) {
+    if (aSelection->context().get()) {
+      aShape = aSelection->context()->shape();
+    }
+  }
+
+  GeomEdgePtr anEdge;
+  if (aShape.get()) {
+    if (aShape->isEdge())
+    {
+      anEdge = aShape->edge();
+    }
+    else if (aShape->isCompound())
+    {
+      GeomAPI_ShapeIterator anIt(aShape);
+      anEdge = anIt.current()->edge();
+    }
+  }
+
+  if (anEdge.get()) {
+    if (anEdge->isLine()) {
+      theDir = anEdge->line()->direction();
+    }
+  }
+}
+
+//=================================================================================================
+void FeaturesPlugin_Extrusion::getSizes(double& theToSize, double& theFromSize)
+{
+  if (string(CREATION_METHOD())->value() == CREATION_METHOD_BY_SIZES()) {
+    theToSize = real(TO_SIZE_ID())->value();
+    theFromSize = real(FROM_SIZE_ID())->value();
+  } if (string(CREATION_METHOD())->value() == CREATION_METHOD_BY_PLANES()) {
+    theToSize = real(TO_OFFSET_ID())->value();
+    theFromSize = real(FROM_OFFSET_ID())->value();
+  } else {
+  }
+}
index d0a6e374530dcb3d161aa2397426660cb74691a1..1f657b30afceb5c7af7bcd94abf75c76f4300ce6 100644 (file)
@@ -67,6 +67,13 @@ public:
     return MY_CREATION_METHOD_ID;
   }
 
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_THROUGH_ALL()
+  {
+    static const std::string MY_CREATION_METHOD_ID("ThroughAll");
+    return MY_CREATION_METHOD_ID;
+  }
+
   /// Attribute name of an object to which the extrusion grows.
   inline static const std::string& DIRECTION_OBJECT_ID()
   {
@@ -126,7 +133,7 @@ public:
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 protected:
@@ -144,6 +151,12 @@ protected:
                                  const ListOfShape& theBoundaryShapes,
                                  const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
                                  const int theIndex = 0);
+
+  /// Retrieve direction argument.
+  void getDirection(std::shared_ptr<GeomAPI_Dir>& theDir);
+
+  /// Retrieve or calculate prism sizes.
+  virtual void getSizes(double& theToSize, double& theFromSize);
 };
 
 #endif
index edbdcf948aaeefa4c9a8c490237543c7a5eee256..7075175e3e40d71205c2945eb2bb9fd8497ea9dc 100644 (file)
 
 #include "FeaturesPlugin_ExtrusionBoolean.h"
 
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+
 //=================================================================================================
 void FeaturesPlugin_ExtrusionBoolean::initAttributes()
 {
@@ -42,3 +47,35 @@ void FeaturesPlugin_ExtrusionBoolean::storeGenerationHistory(ResultBodyPtr theRe
 {
   FeaturesPlugin_Extrusion::storeGenerationHistory(theResultBody, theBaseShape, theMakeShape);
 }
+
+//=================================================================================================
+void FeaturesPlugin_ExtrusionBoolean::getSizes(double& theToSize, double& theFromSize)
+{
+  if (string(CREATION_METHOD())->value() != CREATION_METHOD_THROUGH_ALL()) {
+    FeaturesPlugin_Extrusion::getSizes(theToSize, theFromSize);
+  } else {
+    // Getting objects.
+    ListOfShape anObjects;
+    AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID());
+    for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
+      AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
+      GeomShapePtr anObject = anObjectAttr->value();
+      if (!anObject.get()) {
+        myFeature->setError("Error: Could not get object.");
+        return;
+      }
+      anObjects.push_back(anObject);
+    }
+
+    // Getting prism bases.
+    ListOfShape aBaseShapes;
+    getBaseShapes(aBaseShapes);
+
+    // Getting prism direction.
+    std::shared_ptr<GeomAPI_Dir> aDir;
+    getDirection(aDir);
+
+    // Calculate sizes
+    GeomAlgoAPI_ShapeTools::computeThroughAll(anObjects, aBaseShapes, aDir, theToSize, theFromSize);
+  }
+}
index ee575471bf4ff6f92d3260e208671fa9e9938a82..ee624029b74738f9411e38db98ca51b9efadf092 100644 (file)
@@ -44,6 +44,10 @@ protected:
   void storeGenerationHistory(ResultBodyPtr theResultBody,
                               const GeomShapePtr theBaseShape,
                               const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape);
+
+  /// Calculate prism sizes to ensure that it passes through all objects
+  /// Redefined from FeaturesPlugin_Extrusion
+  virtual void getSizes(double& theToSize, double& theFromSize);
 };
 
 #endif
index 98707995e28f5466854e3a95ea7a68ad0c102697..6747937011da8c070393a88e78ce1de384a81f20 100644 (file)
@@ -46,7 +46,7 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 };
 
index 52461e30388f73559141f7991b4d2e94fd942d26..849e1cd4587c9660308f9bdaf10809e20488b882 100644 (file)
 
 #include "FeaturesPlugin_ExtrusionFuse.h"
 
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeSelectionList.h>
+
+#include <GeomAlgoAPI_Boolean.h>
+#include <GeomAlgoAPI_Prism.h>
+#include <GeomAlgoAPI_ThroughAll.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
+
 //=================================================================================================
 FeaturesPlugin_ExtrusionFuse::FeaturesPlugin_ExtrusionFuse()
 {
@@ -29,5 +37,129 @@ FeaturesPlugin_ExtrusionFuse::FeaturesPlugin_ExtrusionFuse()
 //=================================================================================================
 void FeaturesPlugin_ExtrusionFuse::execute()
 {
-  executeCompositeBoolean();
+  if (string(CREATION_METHOD())->value() != CREATION_METHOD_THROUGH_ALL())
+    executeCompositeBoolean();
+  else {
+    executeFuseThroughAll();
+  }
+}
+
+//=================================================================================================
+void FeaturesPlugin_ExtrusionFuse::executeFuseThroughAll()
+{
+  // Getting objects.
+  ListOfShape anObjects;
+  AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID());
+  for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
+    AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
+    GeomShapePtr anObject = anObjectAttr->value();
+    if (!anObject.get()) {
+      myFeature->setError("Error: Could not get object.");
+      return;
+    }
+    anObjects.push_back(anObject);
+  }
+
+  // Make generation.
+  ListOfShape aGenBaseShapes;
+  ListOfMakeShape aGenMakeShapes;
+  if (!makeGeneration(aGenBaseShapes, aGenMakeShapes)) {
+    return;
+  }
+
+  // Getting tools.
+  ListOfShape aNewTools;
+  ListOfMakeShape aToolsMakeShapes;
+  for (ListOfMakeShape::const_iterator
+         anIt = aGenMakeShapes.cbegin(); anIt != aGenMakeShapes.cend(); ++anIt) {
+    GeomMakeShapePtr anAlgo = (*anIt);
+    std::shared_ptr<GeomAlgoAPI_Prism> aPrismAlgo =
+        std::dynamic_pointer_cast<GeomAlgoAPI_Prism>(anAlgo);
+
+    // Cut the prism by all objects and throw away end pieces
+    std::shared_ptr<GeomAlgoAPI_ThroughAll> aToolAlgo (
+        new GeomAlgoAPI_ThroughAll(aPrismAlgo, anObjects));
+
+    // Checking that the algorithm worked properly
+    if (!aToolAlgo->isDone() || aToolAlgo->shape()->isNull() || !aToolAlgo->isValid()) {
+      myFeature->setError("Error: ThroughAll algorithm failed.");
+    } else {
+      GeomShapePtr aCuttedTool = aToolAlgo->shape();
+      aNewTools.push_back(aCuttedTool);
+      aToolsMakeShapes.push_back(aToolAlgo);
+    }
+  }
+
+  // Perform FeaturesPlugin_CompositeBoolean::makeBoolean() with new (cutted) tools
+  ListOfShape aBooleanObjects;
+  ListOfMakeShape aBooleanMakeShapes;
+  if (!makeBoolean(aNewTools, aBooleanObjects, aBooleanMakeShapes)) {
+    return;
+  }
+
+  if (myOperationType == BOOL_FUSE) {
+    aNewTools.splice(aNewTools.begin(), aBooleanObjects);
+    aBooleanObjects.splice(aBooleanObjects.begin(), aNewTools, aNewTools.begin());
+  }
+
+  // 4. Store result (like in FeaturesPlugin_CompositeBoolean::executeCompositeBoolean())
+  int aResultIndex = 0;
+  std::vector<ResultBaseAlgo> aResultBaseAlgoList;
+  ListOfShape aResultShapesList;
+  ListOfShape::const_iterator aBoolObjIt = aBooleanObjects.cbegin();
+  ListOfMakeShape::const_iterator aBoolMSIt = aBooleanMakeShapes.cbegin();
+  for(; aBoolObjIt != aBooleanObjects.cend() && aBoolMSIt != aBooleanMakeShapes.cend();
+      ++aBoolObjIt, ++aBoolMSIt) {
+
+    ResultBodyPtr aResultBody = myFeature->document()->createBody(myFeature->data(), aResultIndex);
+
+    if((*aBoolObjIt)->isEqual((*aBoolMSIt)->shape())) {
+      aResultBody->store((*aBoolMSIt)->shape(), false);
+    }
+    else
+    {
+      aResultBody->storeModified(*aBoolObjIt, (*aBoolMSIt)->shape());
+
+      // Store generation history.
+      ListOfShape::const_iterator aGenBaseIt = aGenBaseShapes.cbegin();
+      ListOfMakeShape::const_iterator aGenMSIt = aGenMakeShapes.cbegin();
+      for(; aGenBaseIt != aGenBaseShapes.cend() && aGenMSIt != aGenMakeShapes.cend();
+          ++aGenBaseIt, ++aGenMSIt) {
+
+        // ???
+        ListOfMakeShape::const_iterator aToolsMSIt = aToolsMakeShapes.cbegin();
+        for(; aToolsMSIt != aToolsMakeShapes.cend(); ++aToolsMSIt) {
+          std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMSList(new GeomAlgoAPI_MakeShapeList());
+
+          // prism generation
+          aMSList->appendAlgo(*aGenMSIt);
+
+          // tool modification (cut by objects)
+          aMSList->appendAlgo(*aToolsMSIt);
+
+          // bool fuse
+          aMSList->appendAlgo(*aBoolMSIt);
+          storeGenerationHistory(aResultBody, *aGenBaseIt, aMSList);
+        }
+      }
+
+      storeModificationHistory(aResultBody, *aBoolObjIt, aNewTools, *aBoolMSIt);
+
+      ResultBaseAlgo aRBA;
+      aRBA.resultBody = aResultBody;
+      aRBA.baseShape = *aBoolObjIt;
+      aRBA.makeShape = *aBoolMSIt;
+      aResultBaseAlgoList.push_back(aRBA);
+      aResultShapesList.push_back((*aBoolMSIt)->shape());
+    }
+
+    myFeature->setResult(aResultBody, aResultIndex++);
+  }
+
+  // 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);
+  storeDeletedShapes(aResultBaseAlgoList, aNewTools, aResultShapesCompound);
+
+  myFeature->removeResults(aResultIndex);
 }
index 55f5a671ee1a1f2fe3705f285a127cb991d6d308..9ac22764382020f89e9b4ebf11fb887d2253e6a6 100644 (file)
@@ -28,7 +28,7 @@
 ///        fuse result with other objects in a single operation.
 class FeaturesPlugin_ExtrusionFuse : public FeaturesPlugin_ExtrusionBoolean
 {
-public:
+ public:
   /// Use plugin manager for features creation.
   FeaturesPlugin_ExtrusionFuse();
 
@@ -46,8 +46,11 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
+
+ private:
+  void executeFuseThroughAll();
 };
 
 #endif
index 1b0cb782f82de9d56872adf8946fc0533a57f458..ac7be4493b6ea43e7259d3688ca5dcdb38f47b4f 100644 (file)
@@ -95,7 +95,7 @@ public:
     return START_RADIUS_ID();
   }
 
-  /// Creates a new part document if needed.
+  /// Performs the fillet 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.
index e84668d7dbe5790b559907a85abba107205bbb1f..06e20746fc36299d10c9b7b65b888b84d0964e2a 100644 (file)
@@ -173,7 +173,7 @@ public:
     return MY_RESULT_VALUES_ID;
   }
 
-  /// Creates a new part document if needed
+  /// 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
index f7dc3dc8d304ce105ca0011301e3959ab38b90e8..4b3cb965d80beb166b3aca07b69bdeb00797e7bb 100644 (file)
@@ -110,7 +110,7 @@ class FeaturesPlugin_MultiRotation : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index 9571ed3d218c91228b58167d2eadd62c5f625b32..6f817ce41f82351ee654dcb1e0c9a0069fefaf04 100644 (file)
@@ -104,7 +104,7 @@ class FeaturesPlugin_MultiTranslation : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index aee69380b230c82534e5913aac6f9fc85e18e463..b358831d0285bafaced16ff9fac42241a69e5161 100644 (file)
@@ -53,7 +53,7 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed
+  /// 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
index 078ae9f3c6570fd1d0378b13f2762b12f805977c..0ab1a9b6f6e3db8e97c9d771ba759e4e7901b912 100644 (file)
@@ -109,7 +109,7 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed
+  /// 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
index 9e1e4db74cdbc2075591d56a00f957a0bd60f92c..d09a0e3fb623c790f6b4e2e646c123500b55ba1f 100644 (file)
@@ -86,7 +86,7 @@ class FeaturesPlugin_Placement : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed
+  /// 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
index 8f23774452fbc8ba4c692c55d8c6f6b47673613f..d611bfaf7c7d541d0cadff9ba93b82ec55e614bb 100644 (file)
@@ -88,7 +88,7 @@ class FeaturesPlugin_Recover : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed
+  /// 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
index 15e51f32bcdd5d52c51c1a1ba0042d8226e76559..bfc04d0a81e780b236ea42f79ed39305702d7b11 100644 (file)
@@ -97,7 +97,7 @@ public:
   /// \param[in] theID identifier of changed attribute.
   FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 
 private:
index 9994cd900268067bdf4f7ed728600b7306da9945..1789039f5595192f14ed0b5caa5eb04e62553fcd 100644 (file)
@@ -139,12 +139,16 @@ bool FeaturesPlugin_Revolution::makeRevolutions(ListOfShape& theBaseShapes,
   double aToAngle = 0.0;
   double aFromAngle = 0.0;
 
-  if(string(CREATION_METHOD())->value() == CREATION_METHOD_BY_ANGLES()) {
+  if (string(CREATION_METHOD())->value() == CREATION_METHOD_BY_ANGLES()) {
     aToAngle = real(TO_ANGLE_ID())->value();
     aFromAngle = real(FROM_ANGLE_ID())->value();
-  } else {
+  } else if (string(CREATION_METHOD())->value() == CREATION_METHOD_BY_PLANES()) {
     aToAngle = real(TO_OFFSET_ID())->value();
     aFromAngle = real(FROM_OFFSET_ID())->value();
+  } else if (string(CREATION_METHOD())->value() == CREATION_METHOD_THROUGH_ALL()) {
+    aToAngle = 360.0;
+    aFromAngle = 0.0;
+  } else {
   }
 
   // Getting bounding planes.
index cd0b929fc777eefe1984a6e9a68b6703c5ec6367..9fd8ea09cd60474cb63bcadbc408153740be7f41 100644 (file)
@@ -48,6 +48,13 @@ public:
     return MY_CREATION_METHOD_ID;
   }
 
+  /// Attribute name for creation method.
+  inline static const std::string& CREATION_METHOD_THROUGH_ALL()
+  {
+    static const std::string MY_CREATION_METHOD_ID("ThroughAll");
+    return MY_CREATION_METHOD_ID;
+  }
+
   /// Attribute name for creation method.
   inline static const std::string& CREATION_METHOD_BY_ANGLES()
   {
@@ -118,7 +125,7 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index 5a255735a24cb962cb8f5ca92b4c33d90c117c16..12ed6b42e04be64b3f564b0203cd33c89083529a 100644 (file)
@@ -46,7 +46,7 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 };
 
index 81042b2b26fe559d71a14fc26f6f3369f78785dc..061b4564ccda92c6ef3112a495f8ee214490fa55 100644 (file)
@@ -46,7 +46,7 @@ class FeaturesPlugin_RevolutionFuse : public FeaturesPlugin_RevolutionBoolean
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// Performs the algorithm and stores results it in the data structure.
   FEATURESPLUGIN_EXPORT virtual void execute();
 };
 
index c6b80c35a42f79e3f8fb66cde21a1daac0822c68..e16601271c7ab00f7d2f0b298d00093e0f65b25f 100644 (file)
@@ -109,7 +109,7 @@ class FeaturesPlugin_Rotation : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index 873ae607537add0f02158ead1afdb500d259390d..a679a0cf8be08c4365d56b8952a0f82867146332 100644 (file)
@@ -110,7 +110,7 @@ class FeaturesPlugin_Scale : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index fb4b47da8a49e6fb11dabf1decabbad37500fdea..f91f29a2ae850cd5267e61e4234be13f5f7f2946 100644 (file)
@@ -113,7 +113,7 @@ class FeaturesPlugin_Symmetry : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index 257c681e09ca47bb78a14d0643e0f57f4c8056f9..3437c5be695285d7cbd1642f62816bc577b5e436 100644 (file)
@@ -130,7 +130,7 @@ class FeaturesPlugin_Translation : public ModelAPI_Feature
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed.
+  /// 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.
index 797a5573f12f685747202e9596a3d88c75e8cbf7..9ec3e432257e5d2301c2a8a9b07e46ba73341b8e 100644 (file)
@@ -50,7 +50,7 @@ public:
     return MY_KIND;
   }
 
-  /// Creates a new part document if needed
+  /// 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
index 44de21fb5ffc40aa01ab76d7432e6a4a2bf01a98..07db4dd86f32d32371a2dede20b1e61811bde22f 100644 (file)
@@ -1742,9 +1742,6 @@ bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
   if (anObjectsNb + aToolsNb < 2) {
     theError = "Not enough arguments for Fuse operation.";
     return false;
-  } else if (isAllInSameCompSolid) {
-    theError = "Operations only between sub-shapes of the same shape not allowed.";
-    return false;
   }
 
   return true;
diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..95b2e83
--- /dev/null
@@ -0,0 +1,5822 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <!-- workshop -->
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Features</source>
+      <translation>Caractéristiques</translation>
+    </message>
+    <message>
+      <source>Common</source>
+      <translation>Intersection</translation>
+    </message>
+    <message>
+      <source>Cut</source>
+      <translation>Découpe</translation>
+    </message>
+    <message>
+      <source>Extrusion</source>
+      <translation>Extrusion</translation>
+    </message>
+    <message>
+      <source>ExtrusionCut</source>
+      <translation>Enlèvement de matière extrudé</translation>
+    </message>
+    <message>
+      <source>ExtrusionFuse</source>
+      <translation>Bossage extrudé</translation>
+    </message>
+    <message>
+      <source>Fillet</source>
+      <translation>Congé</translation>
+    </message>
+    <message>
+      <source>Fuse</source>
+      <translation>Fusionner</translation>
+    </message>
+    <message>
+      <source>Fuse Faces</source>
+      <translation>Fusionner des faces</translation>
+    </message>
+    <message>
+      <source>Intersection</source>
+      <translation>Section</translation>
+    </message>
+    <message>
+      <source>Partition</source>
+      <translation>Partition</translation>
+    </message>
+    <message>
+      <source>Pipe</source>
+      <translation>Tuyau</translation>
+    </message>
+    <message>
+      <source>Recover</source>
+      <translation>Récupérer</translation>
+    </message>
+    <message>
+      <source>Remove Sub-Shapes</source>
+      <translation>Supprimer les sous-formes</translation>
+    </message>
+    <message>
+      <source>Revolution</source>
+      <translation>Révolution</translation>
+    </message>
+    <message>
+      <source>RevolutionCut</source>
+      <translation>Enlèvement de matière avec révolution</translation>
+    </message>
+    <message>
+      <source>RevolutionFuse</source>
+      <translation>Bossage avec révolution</translation>
+    </message>
+    <message>
+      <source>Scale</source>
+      <translation>Échelle</translation>
+    </message>
+    <message>
+      <source>Smash</source>
+      <translation>Smash</translation>
+    </message>
+    <message>
+      <source>Split</source>
+      <translation>Diviser</translation>
+    </message>
+    <message>
+      <source>Union</source>
+      <translation>Réunion</translation>
+    </message>
+    <!-- Part menu -->
+    <message>
+      <source>Angular Copy</source>
+      <translation>Copie angulaire</translation>
+    </message>
+    <message>
+      <source>Linear copy</source>
+      <translation>Copie linéaire</translation>
+    </message>
+    <message>
+      <source>Measurement</source>
+      <translation>Mesure</translation>
+    </message>
+    <message>
+      <source>Placement</source>
+      <translation>Placement</translation>
+    </message>
+    <message>
+      <source>Rotation</source>
+      <translation>Rotation</translation>
+    </message>
+    <message>
+      <source>Symmetry</source>
+      <translation>Symétrie</translation>
+    </message>
+    <message>
+      <source>Translation</source>
+      <translation>Translation</translation>
+    </message>
+  </context>
+
+  <!-- Common -->
+  <context>
+    <name>Common</name>
+    <message>
+      <source>Common</source>
+      <translation>Intersection</translation>
+    </message>
+    <message>
+      <source>Perform boolean common operation with objects</source>
+      <translation>Effectuer l’opération booléenne section avec des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Common:FeaturesPlugin_ValidatorBooleanCommonArguments</name>
+    <message>
+      <source>Not enough arguments for Fuse operation.</source>
+      <translation>Pas assez d&apos;arguments pour l&apos;opération Fusionner.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Common:creation_method</name>
+    <message>
+      <source>Simple</source>
+      <translation>Simple</translation>
+    </message>
+    <message>
+      <source>advanced</source>
+      <translation>avancée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Common:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Objects</source>
+      <translation>Objets</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Common:tool_objects</name>
+    <message>
+      <source>Select tools</source>
+      <translation>Sélectionnez des outils</translation>
+    </message>
+    <context>
+      <name>Common:tool_objects</name>
+      <message>
+        <source>Attribute "%1" is not initialized.</source>
+        <translation>Sélectionnez des outils.</translation>
+      </message>
+    </context>
+    <message>
+      <source>Tool objects</source>
+      <translation>Objets outils</translation>
+    </message>
+  </context>
+  <context>
+    <name>Model_Data</name>
+    <message>
+      <source>%1 has failed during the update</source>
+      <translation>%1 a échoué lors de la mise à jour</translation>
+    </message>
+  </context>
+
+  <!-- Cut -->
+  <context>
+    <name>Cut</name>
+    <message>
+      <source>Cut</source>
+      <translation>Découpe</translation>
+    </message>
+    <message>
+      <source>Perform boolean cut operation with objects</source>
+      <translation>Effectuer l’opération booléenne découpe avec des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cut:FeaturesPlugin_ValidatorBooleanArguments</name>
+    <message>
+      <source>Objects not selected.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cut:FeaturesPlugin_ValidatorBooleanArguments</name>
+    <message>
+      <source>Tools not selected.</source>
+      <translation>Les objets outils ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cut:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cut:tool_objects</name>
+    <message>
+      <source>Select tools</source>
+      <translation>Sélectionnez des outils</translation>
+    </message>
+    <message>
+      <source>Tool objects</source>
+      <translation>Objets outils</translation>
+    </message>
+  </context>
+
+  <!-- Extrusion -->
+  <context>
+    <name>Extrusion</name>
+    <message>
+      <source>Create a solid by extrusion of a face</source>
+      <translation>Créer un solide par extrusion d&apos;une face</translation>
+    </message>
+    <message>
+      <source>Extrusion</source>
+      <translation>Extrusion</translation>
+    </message>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:CreationMethod</name>
+    <message>
+      <source>By bounding faces and offsets</source>
+      <translation>En délimitant les faces et les décalages</translation>
+    </message>
+    <message>
+      <source>By sizes</source>
+      <translation>Par tailles</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base</name>
+    <message>
+      <source>Base objects:</source>
+      <translation>Objets de base:</translation>
+    </message>
+    <message>
+      <source>Select a base objects</source>
+      <translation>Sélectionnez un objet de base</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un objet de base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object</name>
+    <message>
+      <source>Direction</source>
+      <translation>Direction</translation>
+    </message>
+    <message>
+      <source>Select an edge for direction</source>
+      <translation>Sélectionnez une arête pour la direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object</name>
+    <message>
+      <source>From face</source>
+      <translation>À l’angle</translation>
+    </message>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_offset</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Offset for "from" bounding plane</source>
+      <translation>Décalage pour &quot;à partir&quot; du plan englobant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_size</name>
+    <message>
+      <source>From size</source>
+      <translation>À partir de la taille</translation>
+    </message>
+    <message>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object</name>
+    <message>
+      <source>To face</source>
+      <translation>Jusqu’à la face</translation>
+    </message>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_offset</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Offset for "to" bounding plane</source>
+      <translation>Décalage pour &quot;au&quot; plan englobant</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_size</name>
+    <message>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+    <message>
+      <source>To size</source>
+      <translation>À la taille</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object</name>
+    <message>
+      <source>&lt;base normal&gt;</source>
+      <translation>&lt;base normale&gt;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:sketch</name>
+    <message>
+      <source>Select:&lt;br /&gt; 1. Planar face of non-sketch object or a plane. Sketch creation will be started.&lt;br /&gt; 2. An existing sketch face or contour. Extrusion will be filled by it.&lt;br /&gt; 3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it.</source>
+      <translation>Sélectionnez : &lt;br /&gt; 1. Face plane d&apos;un objet non esquissé ou d&apos;un plan. La création de l’esquisse sera lancée. &lt;br /&gt; 2. Une face ou un contour d’esquisse existant. L&apos;extrusion sera remplie par elle. &lt;br /&gt; 3. Une forme de résultat existante de type: contours / arête / sommets. L&apos;extrusion sera remplie par elle.</translation>
+    </message>
+  </context>
+
+  <!-- ExtrusionCut -->
+  <context>
+    <name>ExtrusionCut</name>
+    <message>
+      <source>ExtrusionCut</source>
+      <translation>Enlèvement de matière extrudé</translation>
+    </message>
+    <message>
+      <source>Cuts an extrusion from a solid</source>
+      <translation>Coupe une extrusion d&apos;un solide</translation>
+    </message>
+    <message>
+      <source>Extrusion</source>
+      <translation>Extrusion</translation>
+    </message>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:CreationMethod</name>
+    <message>
+      <source>By bounding faces and offsets</source>
+      <translation>En délimitant les faces et les décalages</translation>
+    </message>
+    <message>
+      <source>By sizes</source>
+      <translation>Par tailles</translation>
+    </message>
+    <message>
+      <source>Through all</source>
+      <translation>À travers tous</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base</name>
+    <message>
+      <source>Select a sketch face</source>
+      <translation>Sélectionnez une face d&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez une face d&apos;esquisse.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object</name>
+    <message>
+      <source>&lt;base normal&gt;</source>
+      <translation>&lt;base normale&gt;</translation>
+    </message>
+    <message>
+      <source>Direction</source>
+      <translation>Direction</translation>
+    </message>
+    <message>
+      <source>Select an edge for direction</source>
+      <translation>Sélectionnez une arête pour la direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object</name>
+    <message>
+      <source>From face</source>
+      <translation>À l’angle</translation>
+    </message>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_offset</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Offset for bounding plane</source>
+      <translation>Décalage pour le plan englobant</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_size</name>
+    <message>
+      <source>From size</source>
+      <translation>À partir de la taille</translation>
+    </message>
+    <message>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects</name>
+    <message>
+      <source>Cut from:</source>
+      <translation>Coupé de:</translation>
+    </message>
+    <message>
+      <source>Objects to Cut</source>
+      <translation>Objets à couper</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object</name>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+    <message>
+      <source>To face</source>
+      <translation>Jusqu’à la face</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_offset</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Offset for bounding plane</source>
+      <translation>Décalage pour le plan englobant</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_size</name>
+    <message>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+    <message>
+      <source>To size</source>
+      <translation>À la taille</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:sketch</name>
+    <message>
+      <source>Select:&lt;br /&gt; 1. Planar face of non-sketch object or a plane. Sketch creation will be started.&lt;br /&gt; 2. An existing sketch face or contour. Extrusion will be filled by it.&lt;br /&gt; 3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it.</source>
+      <translation>Sélectionnez : &lt;br /&gt; 1. Face plane d&apos;un objet non esquissé ou d&apos;un plan. La création de l’esquisse sera lancée. &lt;br /&gt; 2. Une face ou un contour d’esquisse existant. L&apos;extrusion sera remplie par elle. &lt;br /&gt; 3. Une forme de résultat existante de type: contours / arête / sommets. L&apos;extrusion sera remplie par elle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object:FeaturesPlugin_ValidatorExtrusionBoundary</name>
+    <message>
+      <source>Error: Extrusion algorithm failed.</source>
+      <translation>Erreur : l&apos;algorithme d&apos;extrusion a échoué.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Les objets principaux ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object:FeaturesPlugin_ValidatorExtrusionBoundary</name>
+    <message>
+      <source>Error: Extrusion algorithm failed.</source>
+      <translation>Erreur : l&apos;algorithme d&apos;extrusion a échoué.</translation>
+    </message>
+  </context>
+
+  <!-- ExtrusionFuse -->
+  <context>
+    <name>ExtrusionFuse</name>
+    <message>
+      <source>ExtrusionFuse</source>
+      <translation>Bossage extrudé</translation>
+    </message>
+    <message>
+      <source>Fuses an extrusion with a solid</source>
+      <translation>Fusionne une extrusion avec un solide</translation>
+    </message>
+    <message>
+      <source>Extrusion</source>
+      <translation>Extrusion</translation>
+    </message>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:CreationMethod</name>
+    <message>
+      <source>By bounding faces and offsets</source>
+      <translation>En délimitant les faces et les décalages</translation>
+    </message>
+    <message>
+      <source>By sizes</source>
+      <translation>Par tailles</translation>
+    </message>
+    <message>
+      <source>Through all</source>
+      <translation>À travers tous</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base</name>
+    <message>
+      <source>Select a sketch face</source>
+      <translation>Sélectionnez une face d&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object</name>
+    <message>
+      <source>&lt;base normal&gt;</source>
+      <translation>&lt;base normale&gt;</translation>
+    </message>
+    <message>
+      <source>Direction</source>
+      <translation>Direction</translation>
+    </message>
+    <message>
+      <source>Select an edge for direction</source>
+      <translation>Sélectionnez une arête pour la direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object</name>
+    <message>
+      <source>From face</source>
+      <translation>À l’angle</translation>
+    </message>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_offset</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Offset for bounding plane</source>
+      <translation>Décalage pour le plan englobant</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_size</name>
+    <message>
+      <source>From size</source>
+      <translation>À partir de la taille</translation>
+    </message>
+    <message>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects</name>
+    <message>
+      <source>Fuse with:</source>
+      <translation>Fusionner avec:</translation>
+    </message>
+    <message>
+      <source>Objects to Fuse</source>
+      <translation>Objets à fusionner</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object</name>
+    <message>
+      <source>To face</source>
+      <translation>Jusqu’à la face</translation>
+    </message>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_offset</name>
+    <message>
+      <source>Offset</source>
+      <translation>Décalage</translation>
+    </message>
+    <message>
+      <source>Offset for bounding plane</source>
+      <translation>Décalage pour le plan englobant</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_size</name>
+    <message>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+    <message>
+      <source>To size</source>
+      <translation>À la taille</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:sketch</name>
+    <message>
+      <source>Select:&lt;br /&gt; 1. Planar face of non-sketch object or a plane. Sketch creation will be started.&lt;br /&gt; 2. An existing sketch face or contour. Extrusion will be filled by it.&lt;br /&gt; 3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it.</source>
+      <translation>Sélectionnez : &lt;br /&gt; 1. Face plane d&apos;un objet non esquissé ou d&apos;un plan. La création de l’esquisse sera lancée. &lt;br /&gt; 2. Une face ou un contour d’esquisse existant. L&apos;extrusion sera remplie par elle. &lt;br /&gt; 3. Une forme de résultat existante de type: contours / arête / sommets. L&apos;extrusion sera remplie par elle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionner des objets de base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object:FeaturesPlugin_ValidatorExtrusionBoundary</name>
+    <message>
+      <source>Error: Extrusion algorithm failed.</source>
+      <translation>Erreur : l&apos;algorithme d&apos;extrusion a échoué.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Les objets principaux ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object:FeaturesPlugin_ValidatorExtrusionBoundary</name>
+    <message>
+      <source>Error: Extrusion algorithm failed.</source>
+      <translation>Erreur : l&apos;algorithme d&apos;extrusion a échoué.</translation>
+    </message>
+  </context>
+
+
+  <!-- Fillet -->
+  <context>
+    <name>Fillet</name>
+    <message>
+      <source>Fillet</source>
+      <translation>Congé</translation>
+    </message>
+    <message>
+      <source>Perform fillet on face or edge</source>
+      <translation>Effectuer un congé sur la face ou le bord</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet:creation_method</name>
+    <message>
+      <source>Fixed radius</source>
+      <translation>Rayon fixe</translation>
+    </message>
+    <message>
+      <source>Varying radius</source>
+      <translation>Rayon variable</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet:main_objects</name>
+    <message>
+      <source>Faces or/and edges</source>
+      <translation>Faces ou/et bords</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet:radius1</name>
+    <message>
+      <source>Fillet radius at start point.</source>
+      <translation>Rayon du congé au point de départ.</translation>
+    </message>
+    <message>
+      <source>Fillet radius.</source>
+      <translation>Rayon du congé.</translation>
+    </message>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+    <message>
+      <source>Start radius</source>
+      <translation>Rayon de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fillet:radius2</name>
+    <message>
+      <source>End radius</source>
+      <translation>Rayon de fin</translation>
+    </message>
+    <message>
+      <source>Fillet radius at end point.</source>
+      <translation>Rayon du congé au point final.</translation>
+    </message>
+  </context>
+
+  <!-- Fuse -->
+  <context>
+    <name>Fuse</name>
+    <message>
+      <source>Fuse</source>
+      <translation>Fusionner</translation>
+    </message>
+    <message>
+      <source>Perform boolean fuse operation with objects</source>
+      <translation>Effectuer l’opération booléenne fusion avec des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fuse:FeaturesPlugin_ValidatorBooleanFuseArguments</name>
+    <message>
+      <source>Not enough arguments for Fuse operation.</source>
+      <translation>Pas assez d&apos;arguments pour l&apos;opération Fusionner.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fuse:creation_method</name>
+    <message>
+      <source>Simple</source>
+      <translation>Simple</translation>
+    </message>
+    <message>
+      <source>advanced</source>
+      <translation>avancée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fuse:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Objects</source>
+      <translation>Objets</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fuse:remove_intersection_edges</name>
+    <message>
+      <source>Remove intersection edges</source>
+      <translation>Supprimer les arêtes d&apos;intersection</translation>
+    </message>
+    <message>
+      <source>Remove intersection edges if they laying on the same surface</source>
+      <translation>Supprimez les arêtes d&apos;intersection si elles reposent sur la même surface</translation>
+    </message>
+  </context>
+  <context>
+    <name>Fuse:tool_objects</name>
+    <message>
+      <source>Select tools</source>
+      <translation>Sélectionnez des outils</translation>
+    </message>
+    <message>
+      <source>Tool objects</source>
+      <translation>Objets outils</translation>
+    </message>
+  </context>
+
+  <!-- FusionFaces -->
+  <context>
+    <name>FusionFaces</name>
+    <message>
+      <source>Fuse Faces</source>
+      <translation>Fusionner des faces</translation>
+    </message>
+    <message>
+      <source>Performs fusion of connected faces</source>
+      <translation>Effectue la fusion de faces connectées</translation>
+    </message>
+  </context>
+  <context>
+    <name>FusionFaces:base_shape</name>
+    <message>
+      <source>Select a shape to modify.</source>
+      <translation>Sélectionnez une forme à modifier.</translation>
+    </message>
+    <message>
+      <source>Shape:</source>
+      <translation>Forme:</translation>
+    </message>
+  </context>
+  <context>
+    <name>FusionFaces:base_shape:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Context is empty.</source>
+      <translation>Erreur : le contexte est vide.</translation>
+    </message>
+  </context>
+
+  <!-- Intersection -->
+  <context>
+    <name>Intersection</name>
+    <message>
+      <source>Intersect objects with tools</source>
+      <translation>Intersection d&apos;objets avec des outils</translation>
+    </message>
+    <message>
+      <source>Intersection</source>
+      <translation>Section</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects</name>
+    <message>
+      <source>Objects</source>
+      <translation>Objets</translation>
+    </message>
+    <message>
+      <source>Select objects (compounds, compsolids, solids, shells, faces or edges)</source>
+      <translation>Sélectionner des objets (assemblages, solides composites, coques, faces ou arêtes)</translation>
+    </message>
+  </context>
+
+  <!-- Partition -->
+  <context>
+    <name>Partition</name>
+    <message>
+      <source>Partition</source>
+      <translation>Partition</translation>
+    </message>
+    <message>
+      <source>Perform partition operations with solids</source>
+      <translation>Effectuer des opérations de partition avec des solides</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Attribute "%1" should contain at least %2 items.</source>
+      <translation>Erreur : l&apos;attribut &quot;%1&quot; doit contenir au moins %2 éléments.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:base_objects</name>
+    <message>
+      <source>Base objects:</source>
+      <translation>Objets de base:</translation>
+    </message>
+    <message>
+      <source>Select objects for partitioning.</source>
+      <translation>Sélectionner des objets pour le partitionnement.</translation>
+    </message>
+  </context>
+
+  <!-- Pipe -->
+  <context>
+    <name>Pipe</name>
+    <message>
+      <source>Generates extrusion along a path</source>
+      <translation>Génère une extrusion le long d&apos;un chemin</translation>
+    </message>
+    <message>
+      <source>Pipe</source>
+      <translation>Tuyau</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects</name>
+    <message>
+      <source>Base objects:</source>
+      <translation>Objets de base:</translation>
+    </message>
+    <message>
+      <source>Select a base objects</source>
+      <translation>Sélectionnez un objet de base</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal</name>
+    <message>
+      <source>Bi-Normal:</source>
+      <translation>Bi-normal:</translation>
+    </message>
+    <message>
+      <source>Select an edge for Bi-Normal</source>
+      <translation>Sélectionnez une arête pour Bi-Normal</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:creation_method</name>
+    <message>
+      <source>Pipe by objects, path and Bi-Normal</source>
+      <translation>Tyau par objets, chemin et Bi-Normal</translation>
+    </message>
+    <message>
+      <source>Pipe by objects, path and locations</source>
+      <translation>Tuyau par objets, chemins et emplacements</translation>
+    </message>
+    <message>
+      <source>Simple pipe by objects and path</source>
+      <translation>Tuyau simple par objets et chemin</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:locations_objects</name>
+    <message>
+      <source>Locations:</source>
+      <translation>Emplacements:</translation>
+    </message>
+    <message>
+      <source>Select one or more vertices to specify the locations</source>
+      <translation>Sélectionnez un ou plusieurs sommets pour spécifier les emplacements</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:locations_objects:FeaturesPlugin_ValidatorPipeLocations</name>
+    <message>
+      <source>Error: Empty selection context.</source>
+      <translation>Erreur : contexte de sélection vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:path_object</name>
+    <message>
+      <source>Path object:</source>
+      <translation>Objet chemin:</translation>
+    </message>
+    <message>
+      <source>Select an edge or wire for path</source>
+      <translation>Sélectionnez une arête ou un contour pour le chemin</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionner des objets de base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le vecteur binormal n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:path_object</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez une arête ou un contour pour le chemin.</translation>
+    </message>
+  </context>
+
+  <!-- Recover -->
+  <context>
+    <name>Recover</name>
+    <message>
+      <source>Recover</source>
+      <translation>Récupérer</translation>
+    </message>
+    <message>
+      <source>Visualize concealed objects</source>
+      <translation>Visualiser les objets cachés</translation>
+    </message>
+  </context>
+  <context>
+    <name>Recover:base_feature</name>
+    <message>
+      <source>Feature:</source>
+      <translation>Fonctionnalité:</translation>
+    </message>
+    <message>
+      <source>Select a feature that conceals results.</source>
+      <translation>Sélectionnez une fonctionnalité qui cache les résultats.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Recover:base_feature:FeaturesPlugin_ValidatorConcealedResult</name>
+    <message>
+      <source>Error: Empty feature.</source>
+      <translation>Erreur : fonction vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Recover:method</name>
+    <message>
+      <source>Concealed compounds</source>
+      <translation>Assemblages cachés</translation>
+    </message>
+    <message>
+      <source>Concealed results</source>
+      <translation>Résultats cachés</translation>
+    </message>
+  </context>
+
+  <!-- Remove_SubShapes -->
+  <context>
+    <name>Remove_SubShapes</name>
+    <message>
+      <source>Allows to remove sub-shapes from wires, shells, compsolids and compounds</source>
+      <translation>Permet de supprimer les sous formes de fils, coques, solides composites et assemblages</translation>
+    </message>
+    <message>
+      <source>Remove Sub-Shapes</source>
+      <translation>Supprimer les sous-formes</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape</name>
+    <message>
+      <source>Select a shape to modify.</source>
+      <translation>Sélectionnez une forme à modifier.</translation>
+    </message>
+    <message>
+      <source>Shape:</source>
+      <translation>Forme:</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:creation_method</name>
+    <message>
+      <source>By keeping sub-shapes</source>
+      <translation>En gardant les sous-formes</translation>
+    </message>
+    <message>
+      <source>By removing sub-shapes</source>
+      <translation>En supprimant les sous-formes</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes_to_keep</name>
+    <message>
+      <source>Select shapes to keep.</source>
+      <translation>Sélectionnez des formes à conserver.</translation>
+    </message>
+    <message>
+      <source>Sub-Shapes to keep:</source>
+      <translation>Sous-formes à garder:</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes_to_keep:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes_to_remove</name>
+    <message>
+      <source>Select shapes to remove.</source>
+      <translation>Sélectionnez les formes à supprimer.</translation>
+    </message>
+    <message>
+      <source>Sub-Shapes to remove:</source>
+      <translation>Sous-formes à supprimer:</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes_to_remove:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+
+  <!-- Revolution -->
+  <context>
+    <name>Revolution</name>
+    <message>
+      <source>Create a solid by revolution of a face</source>
+      <translation>Créer un solide par révolution d&apos;une face</translation>
+    </message>
+    <message>
+      <source>Revolution</source>
+      <translation>Révolution</translation>
+    </message>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:CreationMethod</name>
+    <message>
+      <source>By angles</source>
+      <translation>Par angles</translation>
+    </message>
+    <message>
+      <source>By bounding planes and angles</source>
+      <translation>En délimitant des plans et des angles</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for axis</source>
+      <translation>Sélectionnez une arête pour l&apos;axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base</name>
+    <message>
+      <source>Base objects:</source>
+      <translation>Objets de base:</translation>
+    </message>
+    <message>
+      <source>Select a base objects</source>
+      <translation>Sélectionnez un objet de base</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>From angle</source>
+      <translation>De l&apos;angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_object</name>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_offset</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for "from" bounding plane</source>
+      <translation>Angle pour &quot;à partir du&quot; plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>To angle</source>
+      <translation>Jusqu’à l’angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object</name>
+    <message>
+      <source>&lt;base sketch&gt;</source>
+      <translation>&lt;esquisse de base&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_offset</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for "to" bounding plane</source>
+      <translation>Angle pour &quot;à&quot; plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:sketch</name>
+    <message>
+      <source>Select:&lt;br /&gt; 1. Planar face of non-sketch object or a plane. Sketch creation will be started.&lt;br /&gt; 2. An existing sketch face or contour. Extrusion will be filled by it.&lt;br /&gt; 3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it.</source>
+      <translation>Sélectionnez : &lt;br /&gt; 1. Face plane d&apos;un objet non esquissé ou d&apos;un plan. La création de l’esquisse sera lancée. &lt;br /&gt; 2. Une face ou un contour d’esquisse existant. L&apos;extrusion sera remplie par elle. &lt;br /&gt; 3. Une forme de résultat existante de type: contours / arête / sommets. L&apos;extrusion sera remplie par elle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+
+  <!-- RevolutionCut -->
+  <context>
+    <name>RevolutionCut</name>
+    <message>
+      <source>RevolutionCut</source>
+      <translation>Enlèvement de matière avec révolution</translation>
+    </message>
+    <message>
+      <source>Cuts a revolution from a solid</source>
+      <translation>Coupe une révolution d&apos;un solide</translation>
+    </message>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>Revolution</source>
+      <translation>Révolution</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:CreationMethod</name>
+    <message>
+      <source>By angles</source>
+      <translation>Par angles</translation>
+    </message>
+    <message>
+      <source>By bounding planes and angles</source>
+      <translation>En délimitant des plans et des angles</translation>
+    </message>
+    <message>
+      <source>Through all</source>
+      <translation>À travers tous</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for axis</source>
+      <translation>Sélectionnez une arête pour l&apos;axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base</name>
+    <message>
+      <source>Select a sketch face</source>
+      <translation>Sélectionnez une face d&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>From angle</source>
+      <translation>De l&apos;angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_object</name>
+    <message>
+      <source>&lt;sketch&gt;</source>
+      <translation>&lt;esquisse&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_offset</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for "from" bounding plane</source>
+      <translation>Angle pour &quot;à partir du&quot; plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects</name>
+    <message>
+      <source>Cut from:</source>
+      <translation>Coupé de:</translation>
+    </message>
+    <message>
+      <source>Objects to Cut</source>
+      <translation>Objets à couper</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>To angle</source>
+      <translation>Jusqu’à l’angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_object</name>
+    <message>
+      <source>&lt;sketch&gt;</source>
+      <translation>&lt;esquisse&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_offset</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for "to" bounding plane</source>
+      <translation>Angle pour &quot;à&quot; plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:sketch</name>
+    <message>
+      <source>Select:&lt;br /&gt; 1. Planar face of non-sketch object or a plane. Sketch creation will be started.&lt;br /&gt; 2. An existing sketch face or contour. Extrusion will be filled by it.&lt;br /&gt; 3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it.</source>
+      <translation>Sélectionnez : &lt;br /&gt; 1. Face plane d&apos;un objet non esquissé ou d&apos;un plan. La création de l’esquisse sera lancée. &lt;br /&gt; 2. Une face ou un contour d’esquisse existant. L&apos;extrusion sera remplie par elle. &lt;br /&gt; 3. Une forme de résultat existante de type: contours / arête / sommets. L&apos;extrusion sera remplie par elle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Les objets principaux ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+
+  <!-- RevolutionFuse -->
+  <context>
+    <name>RevolutionFuse</name>
+    <message>
+      <source>RevolutionFuse</source>
+      <translation>Bossage avec révolution</translation>
+    </message>
+    <message>
+      <source>Fuses a revolution with a solid</source>
+      <translation>Fusionne une révolution avec un solide</translation>
+    </message>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>Revolution</source>
+      <translation>Révolution</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:CreationMethod</name>
+    <message>
+      <source>By angles</source>
+      <translation>Par angles</translation>
+    </message>
+    <message>
+      <source>By bounding planes and angles</source>
+      <translation>En délimitant des plans et des angles</translation>
+    </message>
+    <message>
+      <source>Through all</source>
+      <translation>À travers tous</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for axis</source>
+      <translation>Sélectionnez une arête pour l&apos;axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base</name>
+    <message>
+      <source>Select a sketch face</source>
+      <translation>Sélectionnez une face d&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>From angle</source>
+      <translation>De l&apos;angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_object</name>
+    <message>
+      <source>&lt;sketch&gt;</source>
+      <translation>&lt;esquisse&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_offset</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for "from" bounding plane</source>
+      <translation>Angle pour &quot;à partir du&quot; plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects</name>
+    <message>
+      <source>Fuse with:</source>
+      <translation>Fusionner avec:</translation>
+    </message>
+    <message>
+      <source>Objects to Fuse</source>
+      <translation>Objets à fusionner</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>To angle</source>
+      <translation>Jusqu’à l’angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_object</name>
+    <message>
+      <source>&lt;sketch&gt;</source>
+      <translation>&lt;esquisse&gt;</translation>
+    </message>
+    <message>
+      <source>Bounding plane (select a planar face)</source>
+      <translation>Plan englobant (sélectionnez une face plane)</translation>
+    </message>
+    <message>
+      <source>Plane face</source>
+      <translation>Face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_offset</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angle for "to" bounding plane</source>
+      <translation>Angle pour &quot;à&quot; plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:sketch</name>
+    <message>
+      <source>Select:&lt;br /&gt; 1. Planar face of non-sketch object or a plane. Sketch creation will be started.&lt;br /&gt; 2. An existing sketch face or contour. Extrusion will be filled by it.&lt;br /&gt; 3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it.</source>
+      <translation>Sélectionnez : &lt;br /&gt; 1. Face plane d&apos;un objet non esquissé ou d&apos;un plan. La création de l’esquisse sera lancée. &lt;br /&gt; 2. Une face ou un contour d’esquisse existant. L&apos;extrusion sera remplie par elle. &lt;br /&gt; 3. Une forme de résultat existante de type: contours / arête / sommets. L&apos;extrusion sera remplie par elle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Les objets principaux ne sont pas sélectionnés</translation>
+    </message>
+  </context>
+
+  <!-- Scale -->
+  <context>
+    <name>Scale</name>
+    <message>
+      <source>Perform scale objects</source>
+      <translation>Effectuer un changement d’échelle des objets</translation>
+    </message>
+    <message>
+      <source>Scale</source>
+      <translation>Échelle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:CreationMethod</name>
+    <message>
+      <source>By one common factor for the three directions</source>
+      <translation>Par un facteur commun aux trois directions</translation>
+    </message>
+    <message>
+      <source>Different factors for the three directions</source>
+      <translation>Différents facteurs pour les trois directions</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:center_point</name>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+    <message>
+      <source>Select the center point</source>
+      <translation>Sélectionnez le point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:scale_factor</name>
+    <message>
+      <source>Scale factor</source>
+      <translation>Facteur d&apos;échelle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:scale_factor_x</name>
+    <message>
+      <source>Scale factor in X</source>
+      <translation>Facteur d&apos;échelle suivant X</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:scale_factor_y</name>
+    <message>
+      <source>Scale factor in Y</source>
+      <translation>Facteur d&apos;échelle suivant Y</translation>
+    </message>
+  </context>
+  <context>
+    <name>Scale:scale_factor_z</name>
+    <message>
+      <source>Scale factor in Z</source>
+      <translation>Facteur d&apos;échelle suivant Z</translation>
+    </message>
+  </context>
+
+  <!-- Smash -->
+  <context>
+    <name>Smash</name>
+    <message>
+      <source>Perform boolean smash operation with objects</source>
+      <translation>Effectuer l’opération booléenne smash avec des objets</translation>
+    </message>
+    <message>
+      <source>Smash</source>
+      <translation>Smash</translation>
+    </message>
+  </context>
+  <context>
+    <name>Smash:FeaturesPlugin_ValidatorBooleanArguments</name>
+    <message>
+      <source>Objects not selected.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Smash:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Smash:tool_objects</name>
+    <message>
+      <source>Select tools</source>
+      <translation>Sélectionnez des outils</translation>
+    </message>
+    <message>
+      <source>Tool objects</source>
+      <translation>Objets outils</translation>
+    </message>
+  </context>
+  <context>
+    <name>Smash:FeaturesPlugin_ValidatorBooleanArguments</name>
+    <message>
+      <source>Tools not selected.</source>
+      <translation>Les objets outils ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+
+  <!-- Split -->
+  <context>
+    <name>Split</name>
+    <message>
+      <source>Perform boolean split operation with objects</source>
+      <translation>Effectuer l’opération booléenne division avec des objets</translation>
+    </message>
+    <message>
+      <source>Split</source>
+      <translation>Diviser</translation>
+    </message>
+  </context>
+  <context>
+    <name>Split:FeaturesPlugin_ValidatorBooleanArguments</name>
+    <message>
+      <source>Objects not selected.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Split:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Split:tool_objects</name>
+    <message>
+      <source>Select tools</source>
+      <translation>Sélectionnez des outils</translation>
+    </message>
+    <message>
+      <source>Tool objects</source>
+      <translation>Objets outils</translation>
+    </message>
+  </context>
+
+  <!-- Union -->
+  <context>
+    <name>Union</name>
+    <message>
+      <source>Perform union operations with shapes</source>
+      <translation>Effectuer des opérations réunion avec des formes</translation>
+    </message>
+    <message>
+      <source>Union</source>
+      <translation>Réunion</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:base_objects</name>
+    <message>
+      <source>Base objects:</source>
+      <translation>Objets de base:</translation>
+    </message>
+    <message>
+      <source>Select solids for union.</source>
+      <translation>Sélectionner les solides pour la réunion.</translation>
+    </message>
+  </context>
+
+  <!-- Validators -->
+
+  <context>
+    <name>Scale:center_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;objet de base pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToSize = -FromSize.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Validator should be used with 2 parameters for extrusion.</source>
+      <translation>Validateur &quot;FeaturesPlugin_ValidatorExtrusionDir&quot; doit être utilisé avec 2 paramètres d&apos;extrusion.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Direction is parallel to one of the selected face or face on selected shell.</source>
+      <translation>La direction est parallèle à l&apos;une des faces sélectionnées ou à la face de la coque sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "sketch" is not initialized.</source>
+      <translation>L&apos;objet de base pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base" is not initialized.</source>
+      <translation>L&apos;objet de base pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "direction_object" is not initialized.</source>
+      <translation>L&apos;objet Direction pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_object" is not initialized.</source>
+      <translation>L’objet de départ pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_object" is not initialized.</source>
+      <translation>L’objet destination de l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: The attribute with the %1 type is not processed</source>
+      <translation>Erreur : l&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: Wrong parameters in XML definition for %1 type</source>
+      <translation>Erreur : paramètres incorrects dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Wrong parameters in XML definition for %1 type</source>
+      <translation>Mauvais paramètres dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Le type d’une forme sélectionnée n’est pas acceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Erreur : attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute have empty context.</source>
+      <translation>Erreur : l&apos;attribut a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Objet de direction non sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Objet de direction non sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Objet de direction non sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Nombre incorrect d&apos;arguments de validation dans XML (9 prévus).</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToSize = -FromSize.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Base objects list contains vertex or edge, so attribute "direction_object" can not be used with default value. Select direction for extrusion.</source>
+      <translation>La liste des objets de base contient un sommet ou une arête, ainsi la direction par défaut ne peut pas être utilisée. Sélectionnez la direction d&apos;extrusion.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object:FeaturesPlugin_ValidatorExtrusionBoundary</name>
+    <message>
+      <source>Error: Extrusion algorithm failed.</source>
+      <translation>Erreur : l&apos;algorithme d&apos;extrusion a échoué.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object:FeaturesPlugin_ValidatorExtrusionBoundary</name>
+    <message>
+      <source>Error: Extrusion algorithm failed.</source>
+      <translation>Erreur : l&apos;algorithme d&apos;extrusion a échoué.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source> Attribute "base" is not initialized.</source>
+      <translation>L&apos;objet de base pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: </source>
+      <translation>Les objets sélectionnés contiennent un élément avec un type de forme non autorisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Validator should be used with 2 parameters for extrusion.</source>
+      <translation>Validateur &quot;FeaturesPlugin_ValidatorExtrusionDir&quot; doit être utilisé avec 2 paramètres d&apos;extrusion.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Direction is parallel to one of the selected face or face on selected shell.</source>
+      <translation>La direction est parallèle à l&apos;une des faces sélectionnées ou à la face de la coque sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "sketch" is not initialized.</source>
+      <translation>L&apos;objet de base pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "direction_object" is not initialized.</source>
+      <translation>L&apos;objet Direction pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_object" is not initialized.</source>
+      <translation>L’objet de départ pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_object" is not initialized.</source>
+      <translation>L’objet destination de l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_offset" is not initialized.</source>
+      <translation>Entrez le décalage &quot;jusqu’à&quot;.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Les objets à couper ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: The attribute with the %1 type is not processed</source>
+      <translation>Erreur : l&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: Wrong parameters in XML definition for %1 type</source>
+      <translation>Erreur : paramètres incorrects dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Wrong parameters in XML definition for %1 type</source>
+      <translation>Mauvais paramètres dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Le type d’une forme sélectionnée n’est pas acceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Sélectionner des objets de base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut</name>
+    <message>
+      <source>base - FeaturesPlugin_ValidatorBaseForGeneration: Error: Attribute have empty context.</source>
+      <translation>L&apos;objet sélectionné est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Nombre incorrect d&apos;arguments de validation dans XML (9 prévus).</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToSize = -FromSize.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Nombre incorrect d&apos;arguments du validateur &quot;GeomValidators_ZeroOffset&quot; en XML (9 attendus).</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToAngle = -FromAngle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "sketch" is not initialized.</source>
+      <translation>L&apos;objet de base pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base" is not initialized.</source>
+      <translation>L&apos;objet de base pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_object" is not initialized.</source>
+      <translation>L&apos;objet de départ pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_object" is not initialized.</source>
+      <translation>L’objet destination de la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: The attribute with the %1 type is not processed</source>
+      <translation>Erreur : l&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: Wrong parameters in XML definition for %1 type</source>
+      <translation>Erreur : paramètres incorrects dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Wrong parameters in XML definition for %1 type</source>
+      <translation>Mauvais paramètres dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Le type d’une forme sélectionnée n’est pas acceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Erreur : attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute have empty context.</source>
+      <translation>Erreur : l&apos;attribut a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromAngle = -ToAngle et les plans englobants coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: </source>
+      <translation>Les objets sélectionnés contiennent un élément avec un type de forme non autorisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Nombre incorrect d&apos;arguments du validateur &quot;GeomValidators_ZeroOffset&quot; en XML (9 attendus).</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToAngle = -FromAngle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "sketch" is not initialized.</source>
+      <translation>L&apos;objet de base pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base" is not initialized.</source>
+      <translation>L&apos;objet de base pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_object" is not initialized.</source>
+      <translation>L&apos;objet de départ pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_object" is not initialized.</source>
+      <translation>L’objet destination de la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>L’objet à couper n’est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: The attribute with the %1 type is not processed</source>
+      <translation>Erreur : l&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: Wrong parameters in XML definition for %1 type</source>
+      <translation>Erreur : paramètres incorrects dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Wrong parameters in XML definition for %1 type</source>
+      <translation>Mauvais paramètres dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Le type d’une forme sélectionnée n’est pas acceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Erreur : attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute have empty context.</source>
+      <translation>Erreur : l&apos;attribut a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base" is not initialized.</source>
+      <translation>Les objets de base pour l&apos;extrusion ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: </source>
+      <translation>Les objets sélectionnés contiennent un élément avec un type de forme non autorisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Validator should be used with 2 parameters for extrusion.</source>
+      <translation>Validateur &quot;FeaturesPlugin_ValidatorExtrusionDir&quot; doit être utilisé avec 2 paramètres d&apos;extrusion.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:FeaturesPlugin_ValidatorExtrusionDir</name>
+    <message>
+      <source>Error: Direction is parallel to one of the selected face or face on selected shell.</source>
+      <translation>La direction est parallèle à l&apos;une des faces sélectionnées ou à la face de la coque sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "sketch" is not initialized.</source>
+      <translation>L&apos;objet de base pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base" is not initialized.</source>
+      <translation>Les objets de base pour l&apos;extrusion ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "direction_object" is not initialized.</source>
+      <translation>L&apos;objet Direction pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_object" is not initialized.</source>
+      <translation>L’objet de départ pour l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_object" is not initialized.</source>
+      <translation>L’objet destination de l&apos;extrusion n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Les objets à fusionner ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: The attribute with the %1 type is not processed</source>
+      <translation>Erreur : l&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: Wrong parameters in XML definition for %1 type</source>
+      <translation>Erreur : paramètres incorrects dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Wrong parameters in XML definition for %1 type</source>
+      <translation>Mauvais paramètres dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Le type d’une forme sélectionnée n’est pas acceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Erreur : attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute have empty context.</source>
+      <translation>Erreur : l&apos;attribut a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:direction_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Nombre incorrect d&apos;arguments de validation dans XML (9 prévus).</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToSize = -FromSize.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromSize = -ToSize et les plans de délimitation coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>FromSize = -ToSize and bounding planes are coincident.</source>
+      <translation>FromAngle = -ToAngle et les plans englobants coïncident.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: </source>
+      <translation>Les objets sélectionnés contiennent un élément avec un type de forme non autorisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Nombre incorrect d&apos;arguments du validateur &quot;GeomValidators_ZeroOffset&quot; en XML (9 attendus).</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>ToSize = -FromSize.</source>
+      <translation>ToAngle = -FromAngle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>From face selection is invalid.</source>
+      <translation>La face de départ sélectionnée est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:GeomValidators_ZeroOffset</name>
+    <message>
+      <source>To face selection is invalid.</source>
+      <translation>La sélection de la face finale est invalide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "sketch" is not initialized.</source>
+      <translation>L&apos;objet de base pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base" is not initialized.</source>
+      <translation>L&apos;objet de base pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_object" is not initialized.</source>
+      <translation>L&apos;objet de départ pour la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_object" is not initialized.</source>
+      <translation>L’objet destination de la révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Les objets à fusionner ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: The attribute with the %1 type is not processed</source>
+      <translation>Erreur : l&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Error: Wrong parameters in XML definition for %1 type</source>
+      <translation>Erreur : paramètres incorrects dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:sketch:FeaturesPlugin_ValidatorCompositeLauncher</name>
+    <message>
+      <source>Wrong parameters in XML definition for %1 type</source>
+      <translation>Mauvais paramètres dans la définition XML pour le type %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Le type d’une forme sélectionnée n’est pas acceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Erreur : attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute have empty context.</source>
+      <translation>Erreur : l&apos;attribut a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de révolution n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>La forme n&apos;est pas un cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>La forme n&apos;est pas une face disponible.</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:main_objects:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean</name>
+    <message>
+      <source>Boolean</source>
+      <translation>Booléen</translation>
+    </message>
+    <message>
+      <source>Boolean operations with objects</source>
+      <translation>Opérations booléennes avec des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:bool_type</name>
+    <message>
+      <source>Operation type</source>
+      <translation>Type d&apos;opération</translation>
+    </message>
+    <message>
+      <source>Type of boolean operation</source>
+      <translation>Type d&apos;opération booléenne</translation>
+    </message>
+    <message>
+      <source>Cut</source>
+      <translation>Découpe</translation>
+    </message>
+    <message>
+      <source>Fuse</source>
+      <translation>Fusionner</translation>
+    </message>
+    <message>
+      <source>Common</source>
+      <translation>Intersection</translation>
+    </message>
+    <message>
+      <source>Fill</source>
+      <translation>Remplir</translation>
+    </message>
+    <message>
+      <source>Smash</source>
+      <translation>Smash</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:main_objects:FeaturesPlugin_ValidatorBooleanSelection</name>
+    <message>
+      <source>Error: Empty attribute selection.</source>
+      <translation>Sélectionner des objets.</translation>
+    </message>
+    <message>
+      <source>Error: Empty selection context.</source>
+      <translation>Objet sélectionné invalide.</translation>
+    </message>
+    <message>
+      <source>Error: Result construction not allowed for selection.</source>
+      <translation>Résultat de construction non autorisé pour la sélection.</translation>
+    </message>
+    <message>
+      <source>Error: Empty shape.</source>
+      <translation>Objet sélectionné invalide.</translation>
+    </message>
+    <message>
+      <source>Error: Local selection not allowed.</source>
+      <translation>Sélection locale non autorisée.</translation>
+    </message>
+    <message>
+      <source>Error: Selected shape has the wrong type.</source>
+      <translation>La forme sélectionnée est du mauvais type.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:tool_objects</name>
+    <message>
+      <source>Tool objects</source>
+      <translation>Objets outils</translation>
+    </message>
+    <message>
+      <source>Select tools</source>
+      <translation>Sélectionnez des outils</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:tool_objects:FeaturesPlugin_ValidatorBooleanSelection</name>
+    <message>
+      <source>Error: Empty attribute selection.</source>
+      <translation>Sélectionnez des outils.</translation>
+    </message>
+    <message>
+      <source>Error: Empty selection context.</source>
+      <translation>Outil sélectionné non valide.</translation>
+    </message>
+    <message>
+      <source>Error: Result construction not allowed for selection.</source>
+      <translation>Résultat de construction non autorisé pour la sélection.</translation>
+    </message>
+    <message>
+      <source>Error: Empty shape.</source>
+      <translation>Outil sélectionné non valide.</translation>
+    </message>
+    <message>
+      <source>Error: Local selection not allowed.</source>
+      <translation>Sélection locale non autorisée.</translation>
+    </message>
+    <message>
+      <source>Error: Selected shape has the wrong type.</source>
+      <translation>La forme sélectionnée est du mauvais type.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:GeomValidators_BooleanArguments</name>
+    <message>
+      <source>Not enough arguments</source>
+      <translation>Pas assez d&apos;arguments.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Boolean:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "bool_type" is not initialized.</source>
+      <translation>Sélectionnez le type d&apos;opération.</translation>
+    </message>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Sélectionner des objets.</translation>
+    </message>
+    <message>
+      <source>Attribute "tool_objects" is not initialized.</source>
+      <translation>Sélectionnez des outils.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Attribute \"%1\" should contain at least %2 items.</source>
+      <translation>Au moins %2 objets doivent être sélectionnés dans &quot;%1&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Wrong number of arguments (expected 2): selection list id and min number of objects</source>
+      <translation>Nombre incorrect de validateurs &quot;GeomValidators_MinObjectsSelected&quot; (2 attendus) : id de la liste de sélection et nombre minimal d&apos;objets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Could not get attribute \"%1\".</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:base_objects:FeaturesPlugin_ValidatorPartitionSelection</name>
+    <message>
+      <source>Error: This validator can only work with selection list in \"Partition\" feature.</source>
+      <translation>Erreur : ce validateur ne peut fonctionner qu&apos;avec une liste de sélection dans la fonctionnalité \"Partition\".</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:base_objects:FeaturesPlugin_ValidatorPartitionSelection</name>
+    <message>
+      <source>Error: Only body shapes and construction planes are allowed for selection.</source>
+      <translation>Seuls les formes et les plans de construction sont autorisés pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Partition:base_objects:FeaturesPlugin_ValidatorPartitionSelection</name>
+    <message>
+      <source>Error: Only body shapes and construction planes are allowed for selection.</source>
+      <translation>Seuls les formes et les plans de construction sont autorisés pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>L&apos;objet de base pour le tuyau n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "binormal" is not initialized.</source>
+      <translation>Le vecteur binormal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "path_object" is not initialized.</source>
+      <translation>L&apos;objet pour le chemin de canal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le vecteur binormal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:path_object:FeaturesPlugin_ValidatorPipePath</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>L&apos;objet pour le chemin de canal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:FeaturesPlugin_ValidatorPipeLocations</name>
+    <message>
+      <source>Error: Could not get \"%1\" attribute.</source>
+      <translation>Impossible d&apos;obtenir l&apos;attribut &quot; %1&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:FeaturesPlugin_ValidatorPipeLocations</name>
+    <message>
+      <source>Error: Number of locations should be the same as base objects.</source>
+      <translation>Le nombre d&apos;emplacements doit être identique à celui des objets de base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>L&apos;objet de base pour le tuyau n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "path_object" is not initialized.</source>
+      <translation>L&apos;objet pour le chemin de canal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "binormal" is not initialized.</source>
+      <translation>Le vecteur binormal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "locations_objects" is not initialized.</source>
+      <translation>Emplacements non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Validator parameters is empty.</source>
+      <translation>Erreur : les paramètres du validateur sont vides.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute contains unacceptable shape.</source>
+      <translation>Erreur : l&apos;attribut contient une forme inacceptable.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>Erreur : contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Compound should contain only faces, edges or vertices.</source>
+      <translation>L’assemblage doit contenir uniquement des faces, des arêtes ou des sommets.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Object from this sketch is already selected. Sketch is not allowed for selection.</source>
+      <translation>L&apos;objet de cette esquisse est déjà sélectionné. L&apos;esquisse n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Whole sketch with this object is already selected. Don't allow to select this object.</source>
+      <translation>L&apos;esquisse entière avec cet objet est déjà sélectionnée. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Wire with wrong orientation selected.</source>
+      <translation>Contour avec mauvaise orientation sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Les objets de ce contour sont déjà sélectionnés. Ne pas autoriser à sélectionner cet objet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty attribute.</source>
+      <translation>Erreur : attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Attribute have empty context.</source>
+      <translation>Erreur : l&apos;attribut a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Empty shape selected</source>
+      <translation>Erreur : forme vide sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Infinite constructions is not allowed as base.</source>
+      <translation>Les constructions infinies ne sont pas autorisées comme base.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape is in the local selection. Only global selection is allowed.</source>
+      <translation>La forme sélectionnée est dans la sélection locale. Seule la sélection globale est autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
+    <message>
+      <source>Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, whole sketch (if it has at least one face), and whole objects with shape types: %1</source>
+      <translation>Le type de la forme sélectionnée n’est pas autorisé. Les types acceptables sont les suivants: faces ou contours sur l&apos;esquisse, esquisse entière (si elle possède au moins une face) et objets entiers des types de forme: %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:path_object:FeaturesPlugin_ValidatorPipePath</name>
+    <message>
+      <source>Error: This validator can only work with path selector in \"Pipe\" feature.</source>
+      <translation>Erreur : ce validateur ne peut fonctionner qu&apos;avec le sélecteur de chemin dans la fonctionnalité \"Tuyau\".</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:path_object:FeaturesPlugin_ValidatorPipePath</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>L&apos;objet pour le chemin de canal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:path_object:FeaturesPlugin_ValidatorPipePath</name>
+    <message>
+      <source>Error: Local selection of wires not allowed.</source>
+      <translation>Sélection locale des contours non autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le vecteur binormal n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Pipe:binormal:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:FeaturesPlugin_ValidatorRemoveSubShapesResult</name>
+    <message>
+      <source>Error: Base shape is empty.</source>
+      <translation>La forme de base n&apos;est pas sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Context is empty.</source>
+      <translation>L&apos;objet sélectionné a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>L&apos;objet sélectionné a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:FeaturesPlugin_ValidatorRemoveSubShapesResult</name>
+    <message>
+      <source>Error: Could not get \"%1\" attribute.</source>
+      <translation>Impossible d&apos;obtenir l&apos;attribut &quot; %1&quot;.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:FeaturesPlugin_ValidatorRemoveSubShapesResult</name>
+    <message>
+      <source>Error: Base shape is empty.</source>
+      <translation>La forme de base n&apos;est pas sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:FeaturesPlugin_ValidatorRemoveSubShapesResult</name>
+    <message>
+      <source>Error: Resulting shape is not valid.</source>
+      <translation>La forme résultante n&apos;est pas valide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_shape" is not initialized.</source>
+      <translation>La forme de base n&apos;est pas sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "subshapes" is not initialized.</source>
+      <translation>Les sous-formes ne sont pas sélectionnées.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La forme est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Context is empty.</source>
+      <translation>L&apos;objet sélectionné a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:base_shape:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Result construction selected.</source>
+      <translation>Erreur : construction du résultat sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.</source>
+      <translation>Erreur : ce validateur ne peut fonctionner qu&apos;avec la liste de sélection de la fonction \"Supprimer les sous-formes\".</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Could not get \"%1\" attribute.</source>
+      <translation>Erreur : impossible d&apos;obtenir l&apos;attribut \"%1\".</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Empty context.</source>
+      <translation>L&apos;objet sélectionné a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Empty base shape.</source>
+      <translation>Forme de base non sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
+    <message>
+      <source>Error: Only sub-shapes of selected shape is allowed for selection.</source>
+      <translation>Seules les sous-formes de la forme sélectionnée sont autorisées pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Les objets principaux ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "tool_objects" is not initialized.</source>
+      <translation>Les objets outils ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty selection.</source>
+      <translation>Sélection vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty attribute selection.</source>
+      <translation>La sélection d&apos;attribut est vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty selection context.</source>
+      <translation>L&apos;objet sélectionné a un contexte vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty feature.</source>
+      <translation>Les objets sélectionnés ont une fonctionnalité vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: %1 shape is not allowed for selection.</source>
+      <translation>La forme %1 n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty shape.</source>
+      <translation>Forme vide sélectionnée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: selected shape has the wrong type.</source>
+      <translation>La forme sélectionnée est du mauvais type.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Les objets principaux ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "tool_objects" is not initialized.</source>
+      <translation>Les objets outils ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty selection.</source>
+      <translation>Erreur : sélection vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty attribute selection.</source>
+      <translation>Erreur : sélection d&apos;attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty selection context.</source>
+      <translation>Erreur : contexte de sélection vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty feature.</source>
+      <translation>Erreur : fonctionnalité vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: %1 shape is not allowed for selection.</source>
+      <translation>La forme %1 n&apos;est pas autorisée pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: empty shape.</source>
+      <translation>Erreur : forme vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: Local selection not allowed.</source>
+      <translation>Sélection locale non autorisée.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Intersection:main_objects:GeomValidators_IntersectionSelection</name>
+    <message>
+      <source>Error: selected shape has the wrong type.</source>
+      <translation>La forme sélectionnée est du mauvais type.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "placement_end_shape" is not initialized.</source>
+      <translation>La forme du placement final n&apos;est pas définie.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_end_shape:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one shape in placement_end_shape and placement_start_shape attributes.</source>
+      <translation>Les formes de placement de début et de fin sont les mêmes.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "placement_objects_list" is not initialized.</source>
+      <translation>Les objets à placer ne sont pas sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_objects_list:FeaturesPlugin_ValidatorTransform</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_objects_list:FeaturesPlugin_ValidatorTransform</name>
+    <message>
+      <source>Objects from the %1 group can be selected in the %2 document, but an objects from the %3 group is selected.</source>
+      <translation>Les objets du groupe %1 peuvent être sélectionnés dans le document %2, mais un objet du groupe %3 est sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "placement_start_shape" is not initialized.</source>
+      <translation>La forme de départ n&apos;est pas définie.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "angle" is not initialized.</source>
+      <translation>L&apos;angle n&apos;est pas défini.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de rotation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de rotation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Les objets sélectionnés contiennent un élément avec un type de forme non autorisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de rotation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;axe de rotation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;axe de rotation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de rotation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "angle" is not initialized.</source>
+      <translation>L&apos;angle n&apos;est pas défini.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:main_objects:FeaturesPlugin_ValidatorTransform</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:main_objects:FeaturesPlugin_ValidatorTransform</name>
+    <message>
+      <source>Objects from the %1 group can be selected in the %2 document, but an objects from the %3 group is selected.</source>
+      <translation>Les objets du groupe %1 peuvent être sélectionnés dans le document %2, mais un objet du groupe %3 est sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>L&apos;axe de translation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;axe de translation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Il ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Il fait référence à un attribut vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is \"%1\", it should be \"%2\"</source>
+      <translation>Le type de forme est &quot;%1&quot;, il devrait être &quot;%2&quot;.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;axe de translation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;axe de translation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;axe de translation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:main_objects:FeaturesPlugin_ValidatorTransform</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:main_objects:FeaturesPlugin_ValidatorTransform</name>
+    <message>
+      <source>Objects from the %1 group can be selected in the %2 document, but an objects from the %3 group is selected.</source>
+      <translation>Les objets du groupe %1 peuvent être sélectionnés dans le document %2, mais un objet du groupe %3 est sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:FeaturesPlugin_ValidatorUnionArguments</name>
+    <message>
+      <source>Error: Could not get \"%1\" attribute.</source>
+      <translation>Impossible d&apos;obtenir l&apos;attribut &quot; %1&quot;.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:FeaturesPlugin_ValidatorUnionArguments</name>
+    <message>
+      <source>Error: Not all shapes have shared topology.</source>
+      <translation>La topologie n&apos;est pas partagée par toutes les formes.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_objects" is not initialized.</source>
+      <translation>Objets non sélectionnés.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:base_objects:FeaturesPlugin_ValidatorUnionSelection</name>
+    <message>
+      <source>Error: This validator can only work with selection list in \"%1\" feature.</source>
+      <translation>Erreur : ce validateur ne peut fonctionner qu&apos;avec la liste de sélection dans la fonctionnalité \"%1\".</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:base_objects:FeaturesPlugin_ValidatorUnionSelection</name>
+    <message>
+      <source>Error: Whole compsolids not allowed for selection.</source>
+      <translation>Solides composites entiers non autorisés pour la sélection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Wrong number of arguments (expected 2): selection list id and min number of objects</source>
+      <translation>Erreur : Nombre d&apos;arguments incorrect (2 attendus): id de la liste de sélection et nombre minimal d&apos;objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>Union:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Could not get attribute \"%1\".</source>
+      <translation>Erreur : impossible d&apos;obtenir l&apos;attribut \"%1\".</translation>
+    </message>
+  </context>
+  <context>
+    <name>FusionFaces:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "base_shape" is not initialized.</source>
+      <translation>La forme de base n&apos;est pas sélectionnée.</translation>
+    </message>
+  </context>
+
+  <!-- Part menu -->
+
+  <!-- AngularCopy -->
+  <context>
+    <name>AngularCopy</name>
+    <message>
+      <source>Angular Copy</source>
+      <translation>Copie angulaire</translation>
+    </message>
+    <message>
+      <source>Perform copy and rotate</source>
+      <translation>Effectuer une copie et une rotation</translation>
+    </message>
+  </context>
+  <context>
+    <name>AngularCopy:axis_angular</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for the axis of rotation</source>
+      <translation>Sélectionnez une arête pour l&apos;axe de rotation</translation>
+    </message>
+  </context>
+  <context>
+    <name>AngularCopy:axis_angular:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>AngularCopy:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>AngularCopy:nb_angular</name>
+    <message>
+      <source>Nb copies</source>
+      <translation>Nb copies</translation>
+    </message>
+    <message>
+      <source>Number of copies for the angular copy</source>
+      <translation>Nombre de copies pour la copie angulaire</translation>
+    </message>
+  </context>
+  <context>
+    <name>AngularCopy:step_angular</name>
+    <message>
+      <source>Angular step</source>
+      <translation>Pas angulaire</translation>
+    </message>
+    <message>
+      <source>Step for the angular direction</source>
+      <translation>Pas pour la direction angulaire</translation>
+    </message>
+  </context>
+
+  <!-- LinearCopy -->
+  <context>
+    <name>LinearCopy</name>
+    <message>
+      <source>Linear copy</source>
+      <translation>Copie linéaire</translation>
+    </message>
+    <message>
+      <source>Perform copy and translate</source>
+      <translation>Effectuer la copie et la translation</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:axis_first_dir</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for the first direction</source>
+      <translation>Sélectionnez une arête pour la première direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:axis_first_dir:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:axis_second_dir</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for the second direction</source>
+      <translation>Sélectionnez une arête pour la deuxième direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:nb_first_dir</name>
+    <message>
+      <source>Nb copies</source>
+      <translation>Nb copies</translation>
+    </message>
+    <message>
+      <source>Number of copies for the first direction</source>
+      <translation>Nombre de copies pour la première direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:nb_second_dir</name>
+    <message>
+      <source>Nb copies</source>
+      <translation>Nb copies</translation>
+    </message>
+    <message>
+      <source>Number of copies for the second direction</source>
+      <translation>Nombre de copies pour la deuxième direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:step_first_dir</name>
+    <message>
+      <source>Step</source>
+      <translation>Étape</translation>
+    </message>
+    <message>
+      <source>Step for the first direction</source>
+      <translation>Pas pour la première direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:step_second_dir</name>
+    <message>
+      <source>Step</source>
+      <translation>Étape</translation>
+    </message>
+    <message>
+      <source>Step for the second direction</source>
+      <translation>Pas pour la deuxième direction</translation>
+    </message>
+  </context>
+  <context>
+    <name>LinearCopy:use_second_dir</name>
+    <message>
+      <source>Second direction</source>
+      <translation>Deuxième direction</translation>
+    </message>
+  </context>
+
+  <!-- Measurement -->
+  <context>
+    <name>Measurement</name>
+    <message>
+      <source>Calculate properties of objects</source>
+      <translation>Calculer les propriétés des objets</translation>
+    </message>
+    <message>
+      <source>Measurement</source>
+      <translation>Mesure</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:MeasureKind</name>
+    <message>
+      <source>Angle between edges</source>
+      <translation>Angle entre les bords</translation>
+    </message>
+    <message>
+      <source>Angle by 3 points</source>
+      <translation>Angle de 3 points</translation>
+    </message>
+    <message>
+      <source>Distance between objects</source>
+      <translation>Distance entre objets</translation>
+    </message>
+    <message>
+      <source>Edge length</source>
+      <translation>Longueur de bord</translation>
+    </message>
+    <message>
+      <source>Radius of circular edge, cylindrical surface or sphere</source>
+      <translation>Rayon du bord circulaire, de la surface cylindrique ou de la sphère</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_from</name>
+    <message>
+      <source>First edge</source>
+      <translation>Premier bord</translation>
+    </message>
+    <message>
+      <source>Select an edge</source>
+      <translation>Sélectionnez une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_from:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_point_1</name>
+    <message>
+      <source>Select a point</source>
+      <translation>Sélectionnez un point</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_point_1:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_point_2</name>
+    <message>
+      <source>Angle apex</source>
+      <translation>Sommet de l’angle</translation>
+    </message>
+    <message>
+      <source>Select a point</source>
+      <translation>Sélectionnez un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_point_2:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_point_3</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+    <message>
+      <source>Select a point</source>
+      <translation>Sélectionnez un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_point_3:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_to</name>
+    <message>
+      <source>Second edge</source>
+      <translation>Deuxième bord</translation>
+    </message>
+    <message>
+      <source>Select an edge</source>
+      <translation>Sélectionnez une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:angle_to:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:circular</name>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Select an edge or face</source>
+      <translation>Sélectionnez une arête ou une face</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:distance_from</name>
+    <message>
+      <source>From</source>
+      <translation>De</translation>
+    </message>
+    <message>
+      <source>Select a shape</source>
+      <translation>Sélectionnez une forme</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:distance_to</name>
+    <message>
+      <source>Select a shape</source>
+      <translation>Sélectionnez une forme</translation>
+    </message>
+    <message>
+      <source>To</source>
+      <translation>À</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:edge_for_length</name>
+    <message>
+      <source>Edge</source>
+      <translation>Bord</translation>
+    </message>
+    <message>
+      <source>Select an edge</source>
+      <translation>Sélectionnez une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>Measurement:edge_for_length:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+
+  <!-- Placement -->
+  <context>
+    <name>Placement</name>
+    <message>
+      <source>Place objects relatively to another one</source>
+      <translation>Placez les objets l&apos;un par rapport à l&apos;autre</translation>
+    </message>
+    <message>
+      <source>Placement</source>
+      <translation>Placement</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_centering</name>
+    <message>
+      <source>Center faces under placement</source>
+      <translation>Faces centrales en cours de placement</translation>
+    </message>
+    <message>
+      <source>Centering</source>
+      <translation>Centrage</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_end_shape</name>
+    <message>
+      <source>Select an end face, edge or vertex</source>
+      <translation>Sélectionnez une extrémité, une arête ou un sommet</translation>
+    </message>
+    <message>
+      <source>Select an object</source>
+      <translation>Sélectionnez un objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_end_shape:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Context is empty.</source>
+      <translation>Erreur : le contexte est vide.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_objects_list</name>
+    <message>
+      <source>Select objects</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+    <message>
+      <source>Select objects to move</source>
+      <translation>Sélectionnez les objets à déplacer</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_reverse_direction</name>
+    <message>
+      <source>Reverse</source>
+      <translation>Sens inverse</translation>
+    </message>
+    <message>
+      <source>Reverse placement direction</source>
+      <translation>Sens de placement inverse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_start_shape</name>
+    <message>
+      <source>Select a start face, edge or vertex</source>
+      <translation>Sélectionnez une face de début, une arête ou un sommet</translation>
+    </message>
+    <message>
+      <source>Select an object</source>
+      <translation>Sélectionnez un objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>Placement:placement_start_shape:GeomValidators_BodyShapes</name>
+    <message>
+      <source>Error: Context is empty.</source>
+      <translation>Erreur : le contexte est vide.</translation>
+    </message>
+  </context>
+
+  <!-- Rotation -->
+  <context>
+    <name>Rotation</name>
+    <message>
+      <source>Perform rotation of objects around the axis to specified angle</source>
+      <translation>Effectuer une rotation des objets autour de l&apos;axe avec l&apos;angle spécifié</translation>
+    </message>
+    <message>
+      <source>Rotation</source>
+      <translation>Rotation</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:CreationMethod</name>
+    <message>
+      <source>By a center and two points</source>
+      <translation>Par un centre et deux points</translation>
+    </message>
+    <message>
+      <source>By an axis and an angle</source>
+      <translation>Par un axe et un angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:axis_object</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for axis</source>
+      <translation>Sélectionnez une arête pour l&apos;axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:center_point</name>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+    <message>
+      <source>Select a center point</source>
+      <translation>Sélectionnez un point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:center_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:end_point</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+    <message>
+      <source>Select an end point</source>
+      <translation>Sélectionnez un point d&apos;arrivée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:end_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select solid objects</source>
+      <translation>Sélectionner des objets solides</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:start_point</name>
+    <message>
+      <source>Select a starting point</source>
+      <translation>Sélectionnez un point de départ</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>Rotation:start_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+
+  <!-- Symmetry -->
+  <context>
+    <name>Symmetry</name>
+    <message>
+      <source>Perform symmetry with respect to a point, an axis or a plane</source>
+      <translation>Effectuer une symétrie par rapport à un point, un axe ou un plan</translation>
+    </message>
+    <message>
+      <source>Symmetry</source>
+      <translation>Symétrie</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:CreationMethod</name>
+    <message>
+      <source>Axis reflection</source>
+      <translation>Axe de réflexion</translation>
+    </message>
+    <message>
+      <source>Plane reflection</source>
+      <translation>Réflexion plane</translation>
+    </message>
+    <message>
+      <source>Point reflection</source>
+      <translation>Point de réflexion</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:axis_object</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an axis</source>
+      <translation>Sélectionnez un axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:axis_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:keep_original</name>
+    <message>
+      <source>Do not remove original shape</source>
+      <translation>Ne pas enlever la forme originale</translation>
+    </message>
+    <message>
+      <source>Keep original result</source>
+      <translation>Conserver le résultat original</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select solid objects</source>
+      <translation>Sélectionner des objets solides</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:plane_object</name>
+    <message>
+      <source>Plane</source>
+      <translation>Plan</translation>
+    </message>
+    <message>
+      <source>Select a plane</source>
+      <translation>Sélectionnez un plan</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:point_object</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+    <message>
+      <source>Select a point</source>
+      <translation>Sélectionnez un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Symmetry:point_object:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+
+  <!-- Translation -->
+  <context>
+    <name>Translation</name>
+    <message>
+      <source>Perform translation of objects along the axis to specified distance</source>
+      <translation>Effectuer la translation des objets le long de l&apos;axe à la distance spécifiée</translation>
+    </message>
+    <message>
+      <source>Translation</source>
+      <translation>Translation</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:CreationMethod</name>
+    <message>
+      <source>By X, Y and Z dimensions</source>
+      <translation>Par dimensions X, Y et Z</translation>
+    </message>
+    <message>
+      <source>By an axis and a distance</source>
+      <translation>Par un axe et une distance</translation>
+    </message>
+    <message>
+      <source>By two points</source>
+      <translation>Par deux points</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:axis_object</name>
+    <message>
+      <source>Axis</source>
+      <translation>Axe</translation>
+    </message>
+    <message>
+      <source>Select an edge for axis</source>
+      <translation>Sélectionnez une arête pour l&apos;axe</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;axe de translation n&apos;est pas sélectionné.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:distance</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:dx</name>
+    <message>
+      <source>DX</source>
+      <translation>DX</translation>
+    </message>
+    <message>
+      <source>Dimension in X</source>
+      <translation>Dimension en X</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:dy</name>
+    <message>
+      <source>DY</source>
+      <translation>DY</translation>
+    </message>
+    <message>
+      <source>Dimension in Y</source>
+      <translation>Dimension en Y</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:dz</name>
+    <message>
+      <source>DZ</source>
+      <translation>DZ</translation>
+    </message>
+    <message>
+      <source>Dimension in Z</source>
+      <translation>Dimension en Z</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:end_point</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+    <message>
+      <source>Select the end point to define the axis</source>
+      <translation>Sélectionnez le point final pour définir l&apos;axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:end_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:main_objects</name>
+    <message>
+      <source>Main objects</source>
+      <translation>Objets principaux</translation>
+    </message>
+    <message>
+      <source>Select solid objects</source>
+      <translation>Sélectionner des objets solides</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:start_point</name>
+    <message>
+      <source>Select the start point to define the axis</source>
+      <translation>Sélectionnez le point de départ pour définir l&apos;axe</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>Translation:start_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+
+</TS>
index 6ed38227224ad719726a55562dff460d5a878c58..ee29a96b32cb8ea0c421b6164c648bbd5bcbc11f 100644 (file)
@@ -60,6 +60,12 @@ model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [32])
 model.testResultsVolumes(Fuse_1, [785.398163397447774514148477465])
 
 Fuse_2 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1_3"), model.selection("SOLID", "Extrusion_1_1_1")], [model.selection("FACE", "Fuse_1_1_1")])
-assert(Fuse_2.feature().error() != "")
 
+model.testNbResults(Fuse_2, 1)
+model.testNbSubResults(Fuse_2, [2])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.FACE, [19])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.EDGE, [82])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.VERTEX, [164])
+model.testResultsVolumes(Fuse_2, [25803.607097738855372881516814232])
 model.end()
index d69e7931494a687e747740b268920875aceca73c..b90c2f27624ef3cf1cbac1e5d8aab1728447c81d 100644 (file)
@@ -31,11 +31,13 @@ assert(Fuse_1.feature().error() != "")
 Part_1_doc.removeFeature(Fuse_1.feature())
 
 Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Partition_1_1_1"), model.selection("SOLID", "Partition_1_1_2")])
-assert(Fuse_1.feature().error() != "")
+# after merging Union and Fuse features, fusing of solids in the same composolid should work (issue #3062)
+assert(Fuse_1.feature().error() == "")
 Part_1_doc.removeFeature(Fuse_1.feature())
 
 Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Partition_1_1_1")], [model.selection("SOLID", "Partition_1_1_2")])
-assert(Fuse_1.feature().error() != "")
+# after merging Union and Fuse features, fusing of solids in the same composolid should work (issue #3062)
+assert(Fuse_1.feature().error() == "")
 Part_1_doc.removeFeature(Fuse_1.feature())
 model.end()
 
index 87e7b0c90571ccbcfbca6aefbb1b52e003b851da..ce912b897f573cb18f6ed18704bb5ae0482e2642 100644 (file)
@@ -39,7 +39,7 @@ model.end()
 from GeomAPI import  GeomAPI_Shape
 
 model.testNbResults(Fuse_1, 1)
-model.testNbSubResults(Fuse_1, [1])
+model.testNbSubResults(Fuse_1, [0])
 model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [0])
 model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [1])
 model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [2])
index 64de0bacc28028fc518661fe1cf6f9c9c7ce3982..c6ba22f70ed70ff444f971aa7b89cb00019d25a9 100644 (file)
@@ -78,4 +78,12 @@ Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrus
 Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True)
 model.end()
 
-assert(Fuse_1.feature().error() != "")
+from GeomAPI import *
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [16])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [78])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [156])
+model.testResultsVolumes(Fuse_1, [1589.048622670478835])
index 44d89830efcb41b6996156b913e9fedbb307da9e..22569aa811f77c048e4e207e7bd16be38feb578e 100644 (file)
@@ -86,10 +86,10 @@ from GeomAPI import GeomAPI_Shape
 
 model.testNbResults(Fuse_1, 1)
 model.testNbSubResults(Fuse_1, [2])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [6])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [23])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [70])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [140])
-model.testResultsVolumes(Fuse_1, [5016.039439659862])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [7])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [31])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [108])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [216])
+model.testResultsVolumes(Fuse_1, [5516.039439659862])
 
 assert(model.checkPythonDump())
index ee3b2a827f283190702e0dfc548c258baa73a0e8..2e80098ba9f3d874105dfc8a811377a7a3031896 100644 (file)
@@ -78,4 +78,12 @@ Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrus
 Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True, keepSubResults = True)
 model.end()
 
-assert(Fuse_1.feature().error() != "")
+from GeomAPI import *
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [4])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [9])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [44])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [160])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [320])
+model.testResultsVolumes(Fuse_1, [6516.03943965772123])
diff --git a/src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py b/src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py
new file mode 100644 (file)
index 0000000..ce66b25
--- /dev/null
@@ -0,0 +1,71 @@
+# Copyright (C) 2018-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 GeomAPI import *
+
+import math
+
+def checkMiddlePoint(shape, x, y, z, tolerance = 1.e-7):
+    assert(shape is not None)
+    middlePoint = shape.middlePoint()
+    assert(math.fabs(middlePoint.x() - x) < tolerance), "{} != {}".format(middlePoint.x(), x)
+    assert(math.fabs(middlePoint.y() - y) < tolerance), "{} != {}".format(middlePoint.y(), y)
+    assert(math.fabs(middlePoint.z() - z) < tolerance), "{} != {}".format(middlePoint.z(), z)
+
+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)
+Axis_1 = model.addAxis(Part_1_doc, 0, -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/Left"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "[Box_1_1/Left][Box_1_1/Top]"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(5, 10, 2)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.result(), SketchCircle_1.center())
+ExtrusionCut_1.setNestedSketch(Sketch_1)
+model.do()
+Shape = ExtrusionCut_1.results()[0].resultSubShapePair()[0].shape()
+checkMiddlePoint(Shape, 5.0, 5.0, 4.97049495)
+
+ExtrusionCut_1.setDirection(model.selection("EDGE", "Axis_1"))
+model.do()
+Shape = ExtrusionCut_1.results()[0].resultSubShapePair()[0].shape()
+checkMiddlePoint(Shape, 4.99796028, 5.00196717, 4.97487226)
+
+ExtrusionCut_2 = model.addExtrusionCut(Part_1_doc, [], [model.selection("SOLID", "ExtrusionCut_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Front"))
+SketchCircle_2 = Sketch_2.addCircle(2, 7, 1.5)
+ExtrusionCut_2.setNestedSketch(Sketch_2)
+model.do()
+
+ExtrusionCut_3 = model.addExtrusionCut(Part_1_doc, [], [model.selection("SOLID", "ExtrusionCut_2_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionCut_2_1/Modified_Face&Box_1_1/Front"))
+SketchCircle_3 = Sketch_3.addCircle(7, 2, 1.5)
+ExtrusionCut_3.setNestedSketch(Sketch_3)
+model.do()
+Shape = ExtrusionCut_3.results()[0].resultSubShapePair()[0].shape()
+checkMiddlePoint(Shape, 4.99787246, 4.92218515, 4.91081244)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py b/src/FeaturesPlugin/Test/TestExtrusionFuse_ThroughAll.py
new file mode 100644 (file)
index 0000000..e84a50b
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (C) 2018-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 GeomAPI import *
+
+import math
+
+def checkMiddlePoint(shape, x, y, z, tolerance = 1.e-7):
+    assert(shape is not None)
+    middlePoint = shape.middlePoint()
+    assert(math.fabs(middlePoint.x() - x) < tolerance), "{} != {}".format(middlePoint.x(), x)
+    assert(math.fabs(middlePoint.y() - y) < tolerance), "{} != {}".format(middlePoint.y(), y)
+    assert(math.fabs(middlePoint.z() - z) < tolerance), "{} != {}".format(middlePoint.z(), z)
+
+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)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Box_3 = model.addBox(Part_1_doc, 20, 20, 20)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_2_1")], 20, 10, 0)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], 40, 20, 0)
+Edge_1 = model.addEdge(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Back][Box_1_1/Left][Box_1_1/Bottom]"), model.selection("VERTEX", "[Translation_2_1/MF:Translated&Box_3_1/Front][Translation_2_1/MF:Translated&Box_3_1/Right][Translation_2_1/MF:Translated&Box_3_1/Top]"))
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Back"))
+SketchCircle_1 = Sketch_1.addCircle(2.134236344973221, -2.430731739079631, 1.564909384334321)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")])
+ExtrusionFuse_1_objects_2 = [model.selection("SOLID", "Box_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Translation_2_1")]
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [model.selection("FACE", "Face_1_1")], model.selection("EDGE", "Edge_1_1"), ExtrusionFuse_1_objects_2)
+
+model.do()
+Shape = ExtrusionFuse_1.results()[0].resultSubShapePair()[0].shape()
+checkMiddlePoint(Shape, 37.46245068, 23.05267081, 8.52187757)
+
+model.end()
+
+assert(model.checkPythonDump())
index 39971790686a1080b78419d4bc15eb11d16be888..5fa0b85fb9f76f7912244d82c701a0fbb5afbcdb 100644 (file)
@@ -45,9 +45,9 @@ SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_1.
 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.setAngleBackward(SketchLine_1.result(), SketchLine_2.result(), 120)
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), 120)
 SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 120)
-SketchConstraintAngle_3 = Sketch_1.setAngleBackward(SketchLine_3.result(), SketchLine_4.result(), 120)
+SketchConstraintAngle_3 = Sketch_1.setAngle(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)
index e0718b88893a348c31adf9b6f2faf1bf5a3c7eeb..fa9939162b5815330e89904ce2c34ca88ee33479 100644 (file)
@@ -127,15 +127,16 @@ aBaseObject = aRecover.reference("base_feature")
 aBaseObject.setValue(aPipeFeature)
 aRecoveredObjects = aRecover.reflist("recovered")
 aRecoveredObjects.append(aFaceResult1)
+aRecoveredObjects.append(aWireResult)
 aSession.finishOperation()
 
 # Create pipe with bi-normal
 aSession.startOperation()
 aPipeFeature = aPart.addFeature("Pipe")
 aBaseObjectsList = aPipeFeature.selectionList("base_objects")
-aBaseObjectsList.append(aRecover.firstResult(), None)
+aBaseObjectsList.append(aRecover.lastResult(), None)
 aPathObjectSelection = aPipeFeature.selection("path_object")
-aPathObjectSelection.setValue(aWireResult, None)
+aPathObjectSelection.setValue(aRecover.firstResult(), None)
 aPipeFeature.string("creation_method").setValue("binormal")
 aBinormalObjectSelection = aPipeFeature.selection("binormal")
 aShapeExplorer = GeomAPI_ShapeExplorer(aSketchShape, GeomAPI_Shape.EDGE)
@@ -153,6 +154,7 @@ aBaseObject = aRecover2.reference("base_feature")
 aBaseObject.setValue(aPipeFeature)
 aRecoveredObjects = aRecover2.reflist("recovered")
 aRecoveredObjects.append(aRecover.firstResult())
+aRecoveredObjects.append(aRecover.lastResult())
 aSession.finishOperation()
 
 # Create pipe with locations
@@ -193,7 +195,7 @@ aBaseObjectsList = aPipeFeature.selectionList("base_objects")
 aBaseObjectsList.append(aRecover2.firstResult(), None)
 aBaseObjectsList.append(aFaceResult2, None)
 aPathObjectSelection = aPipeFeature.selection("path_object")
-aPathObjectSelection.setValue(aWireResult, None)
+aPathObjectSelection.setValue(aRecover2.lastResult(), None)
 aPipeFeature.string("creation_method").setValue("locations")
 aSession.finishOperation()
 
diff --git a/src/FeaturesPlugin/Test/TestRevolutionCut_ThroughAll.py b/src/FeaturesPlugin/Test/TestRevolutionCut_ThroughAll.py
new file mode 100644 (file)
index 0000000..837f0a4
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2018-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
+
+import math
+
+def checkMiddlePoint(shape, x, y, z, tolerance = 1.e-7):
+    assert(shape is not None)
+    middlePoint = shape.middlePoint()
+    assert(math.fabs(middlePoint.x() - x) < tolerance), "{} != {}".format(middlePoint.x(), x)
+    assert(math.fabs(middlePoint.y() - y) < tolerance), "{} != {}".format(middlePoint.y(), y)
+    assert(math.fabs(middlePoint.z() - z) < tolerance), "{} != {}".format(middlePoint.z(), z)
+
+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"), 2, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], 5, 5, 0)
+
+RevolutionCut_1 = model.addRevolutionCut(Part_1_doc, [], model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), [model.selection("SOLID", "Box_1_1")])
+
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_2"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]__cc"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]"), False)
+SketchCircle_1 = SketchProjection_2.createdFeature()
+SketchCircle_2 = Sketch_1.addCircle(5, 5, 2)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_2.center())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+
+RevolutionCut_1.setNestedSketch(Sketch_1)
+
+model.do()
+
+Shape = RevolutionCut_1.results()[0].resultSubShapePair()[0].shape()
+checkMiddlePoint(Shape, 5.13562827, 5.0, 5.13562827)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestRevolutionFuse_ThroughAll.py b/src/FeaturesPlugin/Test/TestRevolutionFuse_ThroughAll.py
new file mode 100644 (file)
index 0000000..2f1d342
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2018-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
+
+import math
+
+def checkMiddlePoint(shape, x, y, z, tolerance = 1.e-7):
+    assert(shape is not None)
+    middlePoint = shape.middlePoint()
+    assert(math.fabs(middlePoint.x() - x) < tolerance), "{} != {}".format(middlePoint.x(), x)
+    assert(math.fabs(middlePoint.y() - y) < tolerance), "{} != {}".format(middlePoint.y(), y)
+    assert(math.fabs(middlePoint.z() - z) < tolerance), "{} != {}".format(middlePoint.z(), z)
+
+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"), 2, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], 5, 5, 0)
+
+RevolutionFuse_1 = model.addRevolutionFuse(Part_1_doc, [], model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), [model.selection("SOLID", "Box_1_1")])
+
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_2"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]__cc"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]"), False)
+SketchCircle_1 = SketchProjection_2.createdFeature()
+SketchCircle_2 = Sketch_1.addCircle(5, 5, 2)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_2.center())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+
+RevolutionFuse_1.setNestedSketch(Sketch_1)
+
+model.do()
+
+Shape = RevolutionFuse_1.results()[0].resultSubShapePair()[0].shape()
+checkMiddlePoint(Shape, 7.01705635, 5.0, 7.01705635)
+
+model.end()
+
+assert(model.checkPythonDump())
index ccb6e644b85c7df2cad239ee2bb2cdced28beb74..14b0973da9b0808e3823208b4dd305c12b9000d2 100644 (file)
@@ -84,10 +84,12 @@ anExtrusionResult = modelAPI_ResultBody(anExtrusionFeature.firstResult())
 # Make union on extrusion
 #=========================================================================
 aSession.startOperation()
-aUnionFeature = aPart.addFeature("Union")
-aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(0), None);
-aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(1), None);
-aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(2), None);
+aUnionFeature = aPart.addFeature("Fuse")
+aUnionFeature.string("creation_method").setValue("simple")
+aUnionFeature.selectionList("main_objects").append(anExtrusionResult.subResult(0), None);
+aUnionFeature.selectionList("main_objects").append(anExtrusionResult.subResult(1), None);
+aUnionFeature.selectionList("main_objects").append(anExtrusionResult.subResult(2), None);
+aUnionFeature.boolean("remove_intersection_edges").setValue(False)
 aSession.finishOperation()
 assert (len(aUnionFeature.results()) > 0)
 anUnionResult = modelAPI_ResultBody(aUnionFeature.firstResult())
index fbcf82f5256d9866af98b726a341e05bf24a20ae..f2b650ec86521cf2a8ea077ce9311d70281cdc2a 100644 (file)
@@ -37,7 +37,7 @@ model.do()
 Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")])
 Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OY"), 200, 0)
 Partition_1 = model.addPartition(Part_1_doc, [model.selection("FACE", "PartSet/XOZ"), model.selection("FACE", "Revolution_1_1")])
-Union_1 = model.addUnion(Part_1_doc, [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_2")])
+Union_1 = model.addFuse(Part_1_doc, [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_2")], True)
 model.do()
 
 model.checkResult(Union_1,model,1,[0],[0],[1],[4],[8])
index 8679aeb10773f4647f398d539825c2f4f21c678c..c1082408cf4d30b1fdc0d68551901cd6905e7532 100644 (file)
@@ -39,7 +39,7 @@ Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("EDGE", "Edge_1_
 Partition_1_objects = [model.selection("FACE", "PartSet/YOZ"), model.selection("FACE", "PartSet/XOZ"), model.selection("FACE", "PartSet/XOY"), model.selection("FACE", "Revolution_1_1")]
 Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects)
 Union_1_objects = [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_2"), model.selection("FACE", "Partition_1_1_3"), model.selection("FACE", "Partition_1_1_4")]
-Union_1 = model.addUnion(Part_1_doc, Union_1_objects)
+Union_1 = model.addFuse(Part_1_doc, Union_1_objects, True)
 model.testHaveNamingSubshapes(Union_1,model,Part_1_doc)
 model.do()
 model.end()
index 0f43467578b3154f770d196f66c73237d55b107a..593eec77c56934e087d049281f362bcc6e5ec466 100644 (file)
@@ -57,11 +57,11 @@ Face_2 = model.addFace(Part_1_doc, Face_2_objects)
 Partition_1_objects = [model.selection("FACE", "Face_2_1"), model.selection("FACE", "Face_1_1"), model.selection("FACE", "PartSet/YOZ")]
 Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects)
 Union_1_objects = [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_3"), model.selection("FACE", "Partition_1_1_4")]
-Union_1 = model.addUnion(Part_1_doc, Union_1_objects)
+Union_1 = model.addFuse(Part_1_doc, Union_1_objects, True, keepSubResults = True)
 model.do()
 
 model.checkResult(Union_1,model,1,[2],[0],[2],[13],[26])
-#model.testHaveNamingSubshapes(Union_1,model,Part_1_doc)
+model.testHaveNamingSubshapes(Union_1,model,Part_1_doc)
 
 model.end()
 
index 6d44cb3dcdc42ddd07332e8ab7d44c252edbf86c..e5b3bf643750cef749cd117ae0f5ba7c7d072fe7 100644 (file)
@@ -28,8 +28,8 @@ Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Left"), 5,
 Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Front"), 5, True)
 Partition_1_objects = [model.selection("FACE", "Plane_1"), model.selection("FACE", "Plane_2"), model.selection("SOLID", "Box_1_1")]
 Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects)
-Union_1 = model.addUnion(Part_1_doc, [model.selection("SOLID", "Partition_1_1_3"), model.selection("SOLID", "Partition_1_1_1")])
-Union_2 = model.addUnion(Part_1_doc, [model.selection("SOLID", "Union_1_1_2"), model.selection("SOLID", "Union_1_1_1")])
+Union_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Partition_1_1_3"), model.selection("SOLID", "Partition_1_1_1")], False, keepSubResults = True)
+Union_2 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Fuse_1_1_2"), model.selection("SOLID", "Fuse_1_1_1")], False, keepSubResults = True)
 model.do()
 model.end()
 
diff --git a/src/FeaturesPlugin/doc/TUI_extrusionCutThroughAll.rst b/src/FeaturesPlugin/doc/TUI_extrusionCutThroughAll.rst
new file mode 100644 (file)
index 0000000..c5ff730
--- /dev/null
@@ -0,0 +1,12 @@
+
+  .. _tui_create_extrusion_cut_through_all:
+
+Create Extrusion Cut through all objects
+========================================
+
+.. literalinclude:: examples/extrusion_cut_through_all.py 
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/extrusion_cut_through_all.py>`
+   
diff --git a/src/FeaturesPlugin/doc/TUI_extrusionFuseThroughAll.rst b/src/FeaturesPlugin/doc/TUI_extrusionFuseThroughAll.rst
new file mode 100644 (file)
index 0000000..a65ce34
--- /dev/null
@@ -0,0 +1,12 @@
+
+  .. _tui_create_extrusion_fuse_through_all:
+
+Create Extrusion Fuse through all objects
+========================================
+
+.. literalinclude:: examples/extrusion_fuse_through_all.py 
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/extrusion_fuse_through_all.py>`
+   
diff --git a/src/FeaturesPlugin/doc/TUI_revolutionCutThroughAll.rst b/src/FeaturesPlugin/doc/TUI_revolutionCutThroughAll.rst
new file mode 100644 (file)
index 0000000..b7e158e
--- /dev/null
@@ -0,0 +1,12 @@
+
+  .. _tui_create_revolution_cut_through_all:
+
+Create Revolution Cut by 360 degrees
+====================================
+
+.. literalinclude:: examples/revolution_cut_through_all.py 
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/revolution_cut_through_all.py>`
+   
diff --git a/src/FeaturesPlugin/doc/TUI_revolutionFuseThroughAll.rst b/src/FeaturesPlugin/doc/TUI_revolutionFuseThroughAll.rst
new file mode 100644 (file)
index 0000000..047d25d
--- /dev/null
@@ -0,0 +1,12 @@
+
+  .. _tui_create_revolution_fuse_through_all:
+
+Create Revolution Fuse by 360 degrees
+=====================================
+
+.. literalinclude:: examples/revolution_fuse_through_all.py 
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/revolution_fuse_through_all.py>`
+   
diff --git a/src/FeaturesPlugin/doc/examples/extrusion_cut_through_all.py b/src/FeaturesPlugin/doc/examples/extrusion_cut_through_all.py
new file mode 100644 (file)
index 0000000..d9f380b
--- /dev/null
@@ -0,0 +1,17 @@
+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(5, 0, 2)
+ExtrusionCut_1.setNestedSketch(Sketch_1)
+model.do()
+model.end()
diff --git a/src/FeaturesPlugin/doc/examples/extrusion_fuse_through_all.py b/src/FeaturesPlugin/doc/examples/extrusion_fuse_through_all.py
new file mode 100644 (file)
index 0000000..f64d433
--- /dev/null
@@ -0,0 +1,36 @@
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+# Objects to be cut
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Box_3 = model.addBox(Part_1_doc, 20, 20, 20)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_2_1")], 20, 10, 0)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], 40, 20, 0)
+ExtrusionFuse_1_objects_2 = [model.selection("SOLID", "Box_1_1"),
+                             model.selection("SOLID", "Translation_1_1"),
+                             model.selection("SOLID", "Translation_2_1")]
+
+# Extrusion direction
+Point_1 = model.addPoint(Part_1_doc, 0, 0, 0)
+Point_2 = model.addPoint(Part_1_doc, 60, 40, 20)
+Edge_1 = model.addEdge(Part_1_doc, model.selection("VERTEX", "Point_1"), model.selection("VERTEX", "Point_2"))
+
+# Base object for extrusion
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Back"))
+SketchCircle_1 = Sketch_1.addCircle(2.13, -2.43, 1.6)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")])
+
+# Extrusion fuse through all
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc,
+                                         [model.selection("FACE", "Face_1_1")],
+                                         model.selection("EDGE", "Edge_1_1"),
+                                         ExtrusionFuse_1_objects_2)
+
+model.do()
+model.end()
diff --git a/src/FeaturesPlugin/doc/examples/revolution_cut_through_all.py b/src/FeaturesPlugin/doc/examples/revolution_cut_through_all.py
new file mode 100644 (file)
index 0000000..508147e
--- /dev/null
@@ -0,0 +1,13 @@
+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)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Top"))
+SketchCircle_1 = Sketch_1.addCircle(5, 5, 2.5)
+model.do()
+RevolutionCut_1 = model.addRevolutionCut(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), [model.selection("SOLID", "Box_1_1")])
+model.do()
+model.end()
diff --git a/src/FeaturesPlugin/doc/examples/revolution_fuse_through_all.py b/src/FeaturesPlugin/doc/examples/revolution_fuse_through_all.py
new file mode 100644 (file)
index 0000000..fad51a6
--- /dev/null
@@ -0,0 +1,13 @@
+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)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Top"))
+SketchCircle_1 = Sketch_1.addCircle(5, 5, 2.5)
+model.do()
+RevolutionFuse_1 = model.addRevolutionFuse(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Top]"), [model.selection("SOLID", "Box_1_1")])
+model.do()
+model.end()
index ca3499c2cbb63382f402fb81c647fbd5f0b45817..fb6a4dee4127118616897bb4653b224fb1b61449 100644 (file)
@@ -18,7 +18,7 @@ The following property panel will be opened:
 .. centered::
   Start sketch
 
-There are two variants of the property panel for Extrusion Cut depending on the chosen option:
+There are three variants of the property panel for Extrusion Cut depending on the chosen option:
 
 .. image:: images/extrusion_by_sizes.png
    :align: left
@@ -28,6 +28,10 @@ There are two variants of the property panel for Extrusion Cut depending on the
    :align: left
 **By Bounding Planes** extrudes objects by specifying bounding planes and offsets.
 
+.. image:: images/extrusion_through_all.png
+   :align: left
+**Through All** extrudes base objects through all objects to be cut.
+
 
 By sizes
 --------
@@ -42,7 +46,7 @@ By sizes
 - **Axis** - if selected, it will be the direction of extrusion, otherwise objects normals will be used.
 - **To size**  - size for extrusion in the direction.
 - **From size** - size for extrusion in the opposite direction.
-- **Cut from** - contains a list of objects which will be cut from the result of extrusion.
+- **Cut from** - contains a list of objects to be cut by the result of extrusion.
 
 **TUI Commands**:  
 
@@ -110,7 +114,7 @@ By bounding planes
 - **To offset** - offset for extrusion or for a bounding plane, if selected.
 - **From plane** - a planar face can be selected to bound extrusion from the other side.
 - **From offset** - offset for extrusion or for a bounding plane, if selected.
-- **Cut from** - contains a list of objects which will be cut from the result of extrusion.
+- **Cut from** - contains a list of objects which will be cut by the result of extrusion.
 
 **TUI Commands**:
 
@@ -149,3 +153,46 @@ The Result of the operation will be an extruded shape:
    **Created Extrusion Cut**
 
 **See Also** a sample TUI Script of :ref:`tui_create_extrusion_cut_by_bounding_planes` operation.
+
+Through all
+-----------
+
+.. image:: images/ExtrusionCut3.png
+  :align: center
+
+.. centered::
+  Extrusion Cut: definition through all objects
+
+- **Base objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be extruded.
+- **Axis** - if selected, it will be the direction of extrusion, otherwise objects normals will be used.
+- **Cut from** - contains a list of objects to be cut by the result of extrusion.
+
+**TUI Commands**:  
+
+.. py:function:: model.addExtrusionCut(part, objectsToExtrude, objectsToCut)
+
+    :param part: The current part object.
+    :param list: A list of objects for extrusion.
+    :param list: A list of objects to cut from.
+    :return: Created object.
+
+.. py:function:: model.addExtrusionCut(part, objects, direction, objectsToCut)
+
+    :param part: The current part object.
+    :param list: A list of objects for extrusion.
+    :param object: A direction of extrusion
+    :param list: A list of objects to cut from.
+    :return: Created object.
+
+Result
+""""""
+
+The Result of the operation will be an extruded shape:
+
+.. image:: images/extrusion_cut_through_all_result.png
+          :align: center
+
+.. centered::
+   **Created Extrusion Cut**
+
+**See Also** a sample TUI Script of :ref:`tui_create_extrusion_cut_through_all` operation.
index 65d971a871b21f82f4358dd120fbcacf9c3ad18c..59d49043e4fb252d961d51e94d3a7bbc0a64a045 100644 (file)
@@ -18,7 +18,7 @@ The following property panel will be opened:
 .. centered::
   Start sketch
 
-There are two variants of the property panel for Extrusion Fuse depending on the chosen option:
+There are three variants of the property panel for Extrusion Fuse depending on the chosen option:
 
 .. image:: images/extrusion_by_sizes.png
    :align: left
@@ -28,6 +28,10 @@ There are two variants of the property panel for Extrusion Fuse depending on the
    :align: left
 **By Bounding Planes** extrudes objects by specifying bounding planes and offsets.
 
+.. image:: images/extrusion_through_all.png
+   :align: left
+**Through All** extrudes base objects to pass through all objects fuse with.
+
 
 By sizes
 --------
@@ -149,3 +153,46 @@ The Result of the operation will be an extruded shape:
    **Extrusion Fuse created**
 
 **See Also** a sample TUI Script of :ref:`tui_create_extrusion_fuse_by_bounding_planes` operation.
+
+Through all
+-----------
+
+.. image:: images/ExtrusionFuse3.png
+  :align: center
+
+.. centered::
+  Extrusion Fuse: definition through all objects
+
+- **Base objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be extruded.
+- **Axis** - if selected, it will be the direction of extrusion, otherwise objects normals will be used.
+- **Fuse with** - contains a list of objects which will be fused with the result of extrusion.
+
+**TUI Commands**:
+
+.. py:function:: model.addExtrusionFuse(part, objectsToExtrude, objectsToFuse)
+
+    :param part: The current part object.
+    :param list: A list of objects for extrusion.
+    :param list: A list of objects to fuse with.
+    :return: Created object.
+
+.. py:function:: model.addExtrusionFuse(part, objectsToExtrude, direction, objectsToFuse)
+
+    :param part: The current part object.
+    :param list: A list of objects for extrusion.
+    :param object: A direction of extrusion
+    :param list: A list of objects to fuse with.
+    :return: Created object.
+
+Result
+""""""
+
+The Result of the operation will be an extruded shape:
+
+.. image:: images/extrusion_fuse_through_all_result.png
+          :align: center
+
+.. centered::
+   **Extrusion Fuse created**
+
+**See Also** a sample TUI Script of :ref:`tui_create_extrusion_fuse_through_all` operation.
index bb5d5f05454086fea481ffdf2a9f75d9f077c0e6..0370f02e705e6f9a9f18fe5c1a6832c8201dd7eb 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/ExtrusionCut1.png and b/src/FeaturesPlugin/doc/images/ExtrusionCut1.png differ
index 348f12c0f66a556a0b1f37b814787c2c9bc77c12..cb725f5507e6a125ec0dd211e2f40432b4c00ccc 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/ExtrusionCut2.png and b/src/FeaturesPlugin/doc/images/ExtrusionCut2.png differ
diff --git a/src/FeaturesPlugin/doc/images/ExtrusionCut3.png b/src/FeaturesPlugin/doc/images/ExtrusionCut3.png
new file mode 100644 (file)
index 0000000..8f1388d
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/ExtrusionCut3.png differ
index 33c2445f872f8e284734c7a66d00503ffc884a16..8cb3cd9652570abe47bb406c6a00b5d20d2f203f 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/ExtrusionFuse1.png and b/src/FeaturesPlugin/doc/images/ExtrusionFuse1.png differ
index f38e71c162cf067d0fe41ba0c01aabed64578c37..62e4559ae0167c02472b85daa919ccffbcb220aa 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/ExtrusionFuse2.png and b/src/FeaturesPlugin/doc/images/ExtrusionFuse2.png differ
diff --git a/src/FeaturesPlugin/doc/images/ExtrusionFuse3.png b/src/FeaturesPlugin/doc/images/ExtrusionFuse3.png
new file mode 100644 (file)
index 0000000..a3fdd99
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/ExtrusionFuse3.png differ
index 8c7a2885ab7b1972802567b1ff30b806b77bfc97..e97241e7716210237d9b3dba9a12dab73e1a0b5a 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/RevolutionCut1.png and b/src/FeaturesPlugin/doc/images/RevolutionCut1.png differ
index 5cdf5d832b91c8e67126731af5ba5776a8fd7095..fd8889bfaf841978fb8c833641a5a9fc93379947 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/RevolutionCut2.png and b/src/FeaturesPlugin/doc/images/RevolutionCut2.png differ
diff --git a/src/FeaturesPlugin/doc/images/RevolutionCut3.png b/src/FeaturesPlugin/doc/images/RevolutionCut3.png
new file mode 100644 (file)
index 0000000..d2de5bb
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/RevolutionCut3.png differ
index 600d78e685d8586b752f280ea9e5a13a7ae6639c..bd074071e5f519536956d2bcedbb24271421c50e 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/RevolutionFuse1.png and b/src/FeaturesPlugin/doc/images/RevolutionFuse1.png differ
index 87fc70918afd448e7f03bb82f49f095dbe498801..1316c378d8c57353889885e849678dbed3c201f3 100644 (file)
Binary files a/src/FeaturesPlugin/doc/images/RevolutionFuse2.png and b/src/FeaturesPlugin/doc/images/RevolutionFuse2.png differ
diff --git a/src/FeaturesPlugin/doc/images/RevolutionFuse3.png b/src/FeaturesPlugin/doc/images/RevolutionFuse3.png
new file mode 100644 (file)
index 0000000..eef253a
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/RevolutionFuse3.png differ
diff --git a/src/FeaturesPlugin/doc/images/extrusion_cut_through_all_result.png b/src/FeaturesPlugin/doc/images/extrusion_cut_through_all_result.png
new file mode 100644 (file)
index 0000000..99c1b8d
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/extrusion_cut_through_all_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png b/src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png
new file mode 100644 (file)
index 0000000..d043450
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/extrusion_fuse_through_all_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/extrusion_through_all.png b/src/FeaturesPlugin/doc/images/extrusion_through_all.png
new file mode 100644 (file)
index 0000000..6ecb152
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/extrusion_through_all.png differ
diff --git a/src/FeaturesPlugin/doc/images/revolution_cut_through_all_result.png b/src/FeaturesPlugin/doc/images/revolution_cut_through_all_result.png
new file mode 100644 (file)
index 0000000..6905721
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/revolution_cut_through_all_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/revolution_fuse_through_all_result.png b/src/FeaturesPlugin/doc/images/revolution_fuse_through_all_result.png
new file mode 100644 (file)
index 0000000..f1f549d
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/revolution_fuse_through_all_result.png differ
diff --git a/src/FeaturesPlugin/doc/images/revolution_through_all.png b/src/FeaturesPlugin/doc/images/revolution_through_all.png
new file mode 100644 (file)
index 0000000..3c75206
Binary files /dev/null and b/src/FeaturesPlugin/doc/images/revolution_through_all.png differ
index b2f5d47049c71a3a9992e50010785e1608d8692e..da86d155e6db03adfa7c873c61f2e51c2764aadd 100644 (file)
@@ -18,7 +18,7 @@ The following property panel will be opened:
 .. centered::
   Start sketch
 
-There are two variants of the property panel for Revolution Cut depending on the chosen option:
+There are three variants of the property panel for Revolution Cut depending on the chosen option:
 
 .. image:: images/revolution_by_angles.png
    :align: left
@@ -28,6 +28,10 @@ There are two variants of the property panel for Revolution Cut depending on the
    :align: left
 **By Bounding Planes** revolves objects by specifying bounding planes and angles.
 
+.. image:: images/revolution_through_all.png
+   :align: left
+**Through All** revolves objects by 360 degrees.
+
 
 By angles
 --------
@@ -120,4 +124,40 @@ The Result of the operation will be a revolved shape:
 .. centered::
    **Revolution Cut created**
 
-**See Also** a sample TUI Script of :ref:`tui_create_revolution_cut_by_bounding_planes` operation.
\ No newline at end of file
+**See Also** a sample TUI Script of :ref:`tui_create_revolution_cut_by_bounding_planes` operation.
+
+Through all
+--------
+
+.. image:: images/RevolutionCut3.png
+  :align: center
+
+.. centered::
+  Revolution Cut: revolving through all the space
+
+- **Base objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be revolved.
+- **Axis** - axis of revolution.
+- **Cut from** - contains a list of objects which will but cut with the result of revolution.
+
+**TUI Commands**:
+
+.. py:function:: model.addRevolutionCut(part, objectsToRevolve, axis, objectToCut)
+
+    :param part: The current part object.
+    :param list: A list of objects for revolution.
+    :param object: An axis.
+    :param list: A list of objects to cut from.
+    :return: Created object.
+
+Result
+""""""
+
+The Result of the operation will be a revolved shape:
+
+.. image:: images/revolution_cut_through_all_result.png
+          :align: center
+
+.. centered::
+   **Revolution Cut created**
+
+**See Also** a sample TUI Script of :ref:`tui_create_revolution_cut_through_all` operation.
index 3ef022a8affefe51ddbc04687c35ff20d73e6160..a608a03d9c735a0686f84bcfbeba86c5e274c4a7 100644 (file)
@@ -18,7 +18,7 @@ The following property panel will be opened:
 .. centered::
   Start sketch
   
-There are two variants of the property panel for Revolution Fuse depending on the chosen option:
+There are three variants of the property panel for Revolution Fuse depending on the chosen option:
 
 .. image:: images/revolution_by_angles.png
    :align: left
@@ -28,6 +28,10 @@ There are two variants of the property panel for Revolution Fuse depending on th
    :align: left
 **By Bounding Planes** revolves objects by specifying bounding planes and angles.
 
+.. image:: images/revolution_through_all.png
+   :align: left
+**Through All** revolves objects by 360 degrees.
+
 
 By angles
 --------
@@ -120,4 +124,40 @@ The Result of the operation will be a revolved shape:
 .. centered::
    **Revolution Fuse created**
 
-**See Also** a sample TUI Script of :ref:`tui_create_revolution_fuse_by_bounding_planes` operation.
\ No newline at end of file
+**See Also** a sample TUI Script of :ref:`tui_create_revolution_fuse_by_bounding_planes` operation.
+
+Through All
+-----------
+
+.. image:: images/RevolutionFuse3.png
+  :align: center
+
+.. centered::
+  Revolution Fuse: definition by bounding planes
+
+- **Base objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be revolved.
+- **Axis** - axis of revolution.
+- **Fuse with** - contains a list of objects which will be fused with the result of revolution.
+
+**TUI Command**:
+
+.. py:function:: model.addRevolutionFuse(part, objectsToRevolve, axis, objectToFuse)
+
+    :param part: The current part object.
+    :param list: A list of objects for revolution.
+    :param object: An axis.
+    :param list: A list of objects to fuse with.
+    :return: Created object.
+
+Result
+""""""
+
+The Result of the operation will be a revolved shape:
+
+.. image:: images/revolution_fuse_through_all_result.png
+          :align: center
+
+.. centered::
+   **Revolution Fuse created**
+
+**See Also** a sample TUI Script of :ref:`tui_create_revolution_fuse_through_all` operation.
index c8561193e7c5879980a62224f52b4d6385c44cf7..bbbf73dd86acfdb799be51dc52b2ae2f5c7d63d4 100644 (file)
@@ -83,6 +83,8 @@
           </doublevalue>
         </groupbox>
       </box>
+      <box id="ThroughAll" title="Through all" icon="icons/Features/extrusion_throughall_32x32.png">
+      </box>
     </toolbox>
   </groupbox>
   <multi_selector id="main_objects"
index b0c18a5c4d981744eb6f254aadf17ea394058c08..5e9d7355698c63a689089848627233e0230331e6 100644 (file)
@@ -83,6 +83,8 @@
           </doublevalue>
         </groupbox>
       </box>
+      <box id="ThroughAll" title="Through all" icon="icons/Features/extrusion_throughall_32x32.png">
+      </box>
     </toolbox>
   </groupbox>
   <multi_selector id="main_objects"
diff --git a/src/FeaturesPlugin/icons/extrusion_throughall_32x32.png b/src/FeaturesPlugin/icons/extrusion_throughall_32x32.png
new file mode 100644 (file)
index 0000000..6ecb152
Binary files /dev/null and b/src/FeaturesPlugin/icons/extrusion_throughall_32x32.png differ
diff --git a/src/FeaturesPlugin/icons/revol_throughall_32x32.png b/src/FeaturesPlugin/icons/revol_throughall_32x32.png
new file mode 100644 (file)
index 0000000..3c75206
Binary files /dev/null and b/src/FeaturesPlugin/icons/revol_throughall_32x32.png differ
index 6211dbc25a09b5c6472494c8c89f30dfa49f49cb..ce17e7cd1aab1a4ecbdfa1914a1c1a844c49d7d1 100644 (file)
@@ -10,7 +10,8 @@
   <shape_selector id="path_object"
                   label="Path object:"
                   tooltip="Select an edge or wire for path"
-                  shape_types="edge wire">
+                  shape_types="edge wire"
+                  concealment="true">
     <validator id="FeaturesPlugin_ValidatorPipePath"/>
   </shape_selector>
   <toolbox id="creation_method">
@@ -19,7 +20,8 @@
       <shape_selector id="binormal"
                       label="Bi-Normal:"
                       tooltip="Select an edge for Bi-Normal"
-                      shape_types="edge">
+                      shape_types="edge"
+                      concealment="true">
         <validator id="GeomValidators_ShapeType" parameters="line"/>
       </shape_selector>
     </box>
@@ -27,7 +29,8 @@
       <multi_selector id="locations_objects"
                       label="Locations:"
                       tooltip="Select one or more vertices to specify the locations"
-                      shape_types="vertex">
+                      shape_types="vertex"
+                      concealment="true">
         <validator id="FeaturesPlugin_ValidatorPipeLocations"/>
       </multi_selector>
     </box>
index 65c1a1e45998eb49143b4a11e0321efc1f02a32c..3197488a7e3870b1b58ad4d5ed13060f249a736d 100644 (file)
     </group>
     <group id="Measurement">
       <feature id="Measurement" title="Measurement" tooltip="Calculate properties of objects"
-               icon="icons/Features/measurement.png" helpfile="measurementFeature.html">
+               icon="icons/Features/measurement.png" helpfile="measurementFeature.html" abort_confirmation="false">
         <source path="measurement_widget.xml"/>
       </feature>
     </group>
index a8edd4a49206d282d77dc588b79e750d28886f82..c3b19383ebd73881dece0904956dd2bf9836b6dc 100644 (file)
@@ -83,6 +83,8 @@
           </doublevalue>
         </groupbox>
       </box>
+      <box id="ThroughAll" title="Through all" icon="icons/Features/revol_throughall_32x32.png">
+      </box>
     </toolbox>
   </groupbox>
   <multi_selector id="main_objects"
index 7981db76c305aa9751236ff148d9d11e0d4c5e66..4f571406e089f1fac9229e8c0348802124fa2443 100644 (file)
@@ -83,6 +83,8 @@
           </doublevalue>
         </groupbox>
       </box>
+      <box id="ThroughAll" title="Through all" icon="icons/Features/revol_throughall_32x32.png">
+      </box>
     </toolbox>
   </groupbox>
   <multi_selector id="main_objects"
index bb093cb0caa3ef22c9bda6e267a71cff6f3cf772..f3ef3d9aec84dd4165ebc4a831a03ad335df8df4 100644 (file)
@@ -144,9 +144,7 @@ double GeomAPI_Angle2d::angleRadian()
   ThreePoints2d* anAngle = MY_ANGLE;
   gp_Dir2d aDir1(anAngle->myFirst.XY() - anAngle->myCenter.XY());
   gp_Dir2d aDir2(anAngle->mySecond.XY() - anAngle->myCenter.XY());
-  double aRes = aDir1.Angle(aDir2);
-  if (aRes < 0.0) aRes += 2 * PI;
-  return aRes;
+  return aDir1.Angle(aDir2);
 }
 
 bool GeomAPI_Angle2d::isReversed(int theIndex)
index 830fbb1b1ceac2fa867ea85ac0b3011820cc7814..c4504272b3ccbea972eb5606d69f5288aab6da0a 100644 (file)
@@ -25,6 +25,7 @@
 #include<GeomAPI_Lin.h>
 #include<GeomAPI_Ax2.h>
 #include<GeomAPI_Ellipse.h>
+#include<GeomAPI_Vertex.h>
 
 #include <BRepAdaptor_Curve.hxx>
 
@@ -69,6 +70,18 @@ GeomAPI_Edge::GeomAPI_Edge(const std::shared_ptr<GeomAPI_Shape>& theShape)
   }
 }
 
+void GeomAPI_Edge::vertices(std::shared_ptr<GeomAPI_Vertex>& theStartVertex,
+                            std::shared_ptr<GeomAPI_Vertex>& theEndVertex) const
+{
+  const TopoDS_Edge& anEdge = impl<TopoDS_Edge>();
+  TopoDS_Vertex aStart, aEnd;
+  TopExp::Vertices(anEdge, aStart, aEnd);
+  theStartVertex.reset(new GeomAPI_Vertex);
+  theStartVertex->setImpl(new TopoDS_Vertex(aStart));
+  theEndVertex.reset(new GeomAPI_Vertex);
+  theEndVertex->setImpl(new TopoDS_Vertex(aEnd));
+}
+
 static Handle(Geom_Curve) baseCurve(const TopoDS_Edge& theEdge)
 {
   double aFirst, aLast;
index 9d3a4f47b9ae1fe26df16c724cd795a5386c2d27..fdf82ed6fb57954343676c3969fa3805791f44a1 100644 (file)
@@ -27,6 +27,7 @@ class GeomAPI_Pnt;
 class GeomAPI_Circ;
 class GeomAPI_Lin;
 class GeomAPI_Ellipse;
+class GeomAPI_Vertex;
 
 /**\class GeomAPI_Edge
 * \ingroup DataModel
@@ -44,6 +45,11 @@ public:
   GEOMAPI_EXPORT
    GeomAPI_Edge(const std::shared_ptr<GeomAPI_Shape>& theShape);
 
+  /// Return vertices of the edge;
+  GEOMAPI_EXPORT
+  void vertices(std::shared_ptr<GeomAPI_Vertex>& theStartVertex,
+                std::shared_ptr<GeomAPI_Vertex>& theEndVertex) const;
+
   /// Returns \c true if edges have same underlying curve
   GEOMAPI_EXPORT
   virtual bool isSameGeometry(const std::shared_ptr<GeomAPI_Shape> theShape) const;
index 683413c63e9a2aa92cdc35af97daa64a06464f29..5025a6aaa75846722e73d765f7f7d2f8f6ea9f6c 100644 (file)
@@ -75,3 +75,23 @@ bool GeomAPI_Vertex::isEqual(const std::shared_ptr<GeomAPI_Shape> theVert) const
 
   return aPoint1.IsEqual(aPoint2, Precision::Confusion()) == Standard_True;
 }
+
+
+
+bool GeomAPI_Vertex::GeometricComparator::operator()(const GeomVertexPtr& theVertex1,
+                                                     const GeomVertexPtr& theVertex2) const
+{
+  const TopoDS_Vertex& aVertex1 = theVertex1->impl<TopoDS_Vertex>();
+  const TopoDS_Vertex& aVertex2 = theVertex2->impl<TopoDS_Vertex>();
+
+  gp_Pnt aPnt1 = BRep_Tool::Pnt(aVertex1);
+  gp_Pnt aPnt2 = BRep_Tool::Pnt(aVertex2);
+
+  bool isLess = aPnt1.X() + myTolerance < aPnt2.X();
+  if (!isLess && aPnt1.X() <= aPnt2.X() + myTolerance) {
+    isLess = aPnt1.Y() + myTolerance < aPnt2.Y();
+    if (!isLess && aPnt1.Y() <= aPnt2.Y() + myTolerance)
+      isLess = aPnt1.Z() + myTolerance < aPnt2.Z();
+  }
+  return isLess;
+}
index 13668b6af2c4c1034c719c06d6ba5b1b99ad28d3..5c564f842fb7f5ffefa6f49184571d6d93e21072 100644 (file)
@@ -49,6 +49,24 @@ public:
   /// Returns true if the current edge is geometrically equal to the given edge.
   GEOMAPI_EXPORT
   virtual bool isEqual(const std::shared_ptr<GeomAPI_Shape> theVert) const;
+
+public:
+  /// \brief Compare vertices geometrically
+  class GeometricComparator
+  {
+  public:
+    GEOMAPI_EXPORT
+    GeometricComparator(const double theTolerance = 1.e-7) : myTolerance(theTolerance)
+    {}
+
+    /// Return \c true if the first vertex is less than the second
+    GEOMAPI_EXPORT
+    bool operator ()(const std::shared_ptr<GeomAPI_Vertex>& theVertex1,
+                     const std::shared_ptr<GeomAPI_Vertex>& theVertex2) const;
+  private:
+    double myTolerance;
+  };
+
 };
 
 //! Pointer on the object
index 235851975d320db4ffd4596b5215e1af2ee011b9..5861ac8d81332276b0175babe5bcc5af6ad7910a 100644 (file)
@@ -33,6 +33,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_Prism.h
     GeomAlgoAPI_Revolution.h
     GeomAlgoAPI_Boolean.h
+    GeomAlgoAPI_ThroughAll.h
     GeomAlgoAPI_Rotation.h
     GeomAlgoAPI_Translation.h
     GeomAlgoAPI_MakeShape.h
@@ -81,6 +82,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_Offset.h
     GeomAlgoAPI_SolidClassifier.h
     GeomAlgoAPI_MapShapesAndAncestors.h
+    GeomAlgoAPI_Projection.h
     GeomAlgoAPI_Chamfer.h
 )
 
@@ -94,6 +96,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_Prism.cpp
     GeomAlgoAPI_Revolution.cpp
     GeomAlgoAPI_Boolean.cpp
+    GeomAlgoAPI_ThroughAll.cpp
     GeomAlgoAPI_Rotation.cpp
     GeomAlgoAPI_Translation.cpp
     GeomAlgoAPI_MakeShape.cpp
index 32224162bc0d10a1d38f0f3571be27ded0212f2e..1b07fabae681eb16649c8339cbc421c83683972a 100644 (file)
@@ -51,7 +51,7 @@ public:
 
   /// Redefinition of the generic method for the Fuse problem: OCCT 30481
   GEOMALGOAPI_EXPORT virtual void modified(const GeomShapePtr theOldShape,
-    ListOfShape& theNewShapes);
+                                           ListOfShape& theNewShapes);
 
 private:
   /// Builds resulting shape.
index d1d3abe8b5317f5b03ee1e892e3e19c53f65b07f..77aeaad15ea46a7d73a3b2580c5785babdd27aaa 100644 (file)
 #include <GeomAPI_Wire.h>
 
 #include <Bnd_Box.hxx>
+
+#include <BRep_Tool.hxx>
 #include <BRep_Builder.hxx>
-#include <BRepAdaptor_Curve.hxx>
 #include <BRepAlgo.hxx>
 #include <BRepAlgo_FaceRestrictor.hxx>
+#include <BRepAdaptor_Curve.hxx>
 #include <BRepBndLib.hxx>
 #include <BRepBuilderAPI_FindPlane.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
 #include <BRepCheck_Analyzer.hxx>
 #include <BRepExtrema_DistShapeShape.hxx>
 #include <BRepExtrema_ExtCF.hxx>
 #include <BRepTools_WireExplorer.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
 #include <BRepClass_FaceClassifier.hxx>
+#include <BRepLib_CheckCurveOnSurface.hxx>
+
+#include <BOPAlgo_Builder.hxx>
+
 #include <Geom2d_Curve.hxx>
 #include <Geom2d_Curve.hxx>
-#include <BRepLib_CheckCurveOnSurface.hxx>
-#include <BRep_Tool.hxx>
-#include  <Geom_CylindricalSurface.hxx>
+
+#include <Geom_CylindricalSurface.hxx>
 #include <Geom_Line.hxx>
 #include <Geom_Plane.hxx>
+#include <Geom_RectangularTrimmedSurface.hxx>
+
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomAPI_ShapeIterator.h>
+
 #include <GeomLib_IsPlanarSurface.hxx>
 #include <GeomLib_Tool.hxx>
 #include <GeomAPI_IntCS.hxx>
+
 #include <gp_Pln.hxx>
 #include <GProp_GProps.hxx>
+
 #include <IntAna_IntConicQuad.hxx>
 #include <IntAna_Quadric.hxx>
-#include <NCollection_Vector.hxx>
+
 #include <ShapeAnalysis.hxx>
 #include <ShapeAnalysis_Surface.hxx>
-#include <TopoDS_Builder.hxx>
+
+#include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Shell.hxx>
 #include <TopoDS_Vertex.hxx>
-#include <TopoDS.hxx>
+#include <TopoDS_Builder.hxx>
+
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
-#include <TopTools_ListIteratorOfListOfShape.hxx>
 
+#include <TopTools_ListIteratorOfListOfShape.hxx>
 
-#include <BOPAlgo_Builder.hxx>
-#include <BRepBuilderAPI_MakeVertex.hxx>
-#include <TopoDS_Edge.hxx>
+#include <NCollection_Vector.hxx>
 
 //==================================================================================================
 static GProp_GProps props(const TopoDS_Shape& theShape)
@@ -1076,6 +1087,7 @@ static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire)
   return aFixedWire;
 }
 
+//==================================================================================================
 std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_ShapeTools::wireToEdge(
       const std::shared_ptr<GeomAPI_Wire>& theWire)
 {
@@ -1094,6 +1106,7 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_ShapeTools::wireToEdge(
   return anEdge;
 }
 
+//==================================================================================================
 ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& theShape)
 {
   ListOfShape aSubShapes;
@@ -1114,4 +1127,127 @@ ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& the
   }
 
   return aSubShapes;
-}
\ No newline at end of file
+}
+
+//==================================================================================================
+static void getMinMaxPointsOnLine(const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
+                                  const gp_Dir theDir,
+                                  double& theMin, double& theMax)
+{
+  theMin = RealLast();
+  theMax = RealFirst();
+  // Project bounding points on theDir
+  for (std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator
+         aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) {
+    const gp_Pnt& aPnt = (*aPointsIt)->impl<gp_Pnt>();
+    gp_Dir aPntDir (aPnt.XYZ());
+    Standard_Real proj = (theDir*aPntDir) * aPnt.XYZ().Modulus();
+    if (proj < theMin) theMin = proj;
+    if (proj > theMax) theMax = proj;
+  }
+}
+
+//==================================================================================================
+void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects,
+                                               const ListOfShape& theBaseShapes,
+                                               const std::shared_ptr<GeomAPI_Dir> theDir,
+                                               double& theToSize, double& theFromSize)
+{
+  // Bounding box of objects
+  std::list<std::shared_ptr<GeomAPI_Pnt> > aBndObjs =
+      GeomAlgoAPI_ShapeTools::getBoundingBox(theObjects);
+  if (aBndObjs.size() != 8) {
+    return;
+  }
+
+  // Prism direction
+  if (theDir.get()) {
+    // One direction for all prisms
+    gp_Dir aDir = theDir->impl<gp_Dir>();
+
+    // Bounding box of the base
+    std::list<std::shared_ptr<GeomAPI_Pnt> > aBndBases =
+        GeomAlgoAPI_ShapeTools::getBoundingBox(theBaseShapes);
+    if (aBndBases.size() != 8) {
+      return;
+    }
+
+    // Objects bounds
+    Standard_Real lowBnd, upperBnd;
+    getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd);
+
+    // Base bounds
+    Standard_Real lowBase, upperBase;
+    getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase);
+
+    // ----------.-----.---------.--------------.-----------> theDir
+    //       lowBnd   lowBase   upperBase    upperBnd
+
+    theToSize = upperBnd - lowBase;
+    theFromSize = upperBase - lowBnd;
+  } else {
+    // Direction is a normal to each base shape (different normals to bases)
+    // So we calculate own sizes for each base shape
+    theToSize = 0.0;
+    theFromSize = 0.0;
+
+    for (ListOfShape::const_iterator anIt = theBaseShapes.begin();
+         anIt != theBaseShapes.end(); ++anIt) {
+      const GeomShapePtr& aBaseShape_i = (*anIt);
+      ListOfShape aBaseShapes_i;
+      aBaseShapes_i.push_back(aBaseShape_i);
+
+      // Bounding box of the base
+      std::list<std::shared_ptr<GeomAPI_Pnt> > aBndBases =
+          GeomAlgoAPI_ShapeTools::getBoundingBox(aBaseShapes_i);
+      if (aBndBases.size() != 8) {
+        return;
+      }
+
+      // Direction (normal to aBaseShapes_i)
+      // Code like in GeomAlgoAPI_Prism
+      gp_Dir aDir;
+      const TopoDS_Shape& aBaseShape = aBaseShape_i->impl<TopoDS_Shape>();
+      BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
+      if (aFindPlane.Found() == Standard_True) {
+        Handle(Geom_Plane) aPlane;
+        if (aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
+          TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
+          const TopoDS_Shape& aFace = anExp.Current();
+          Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
+          if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
+            Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
+              Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
+            aSurface = aTrimSurface->BasisSurface();
+          }
+          if(aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
+            return;
+          }
+          aPlane = Handle(Geom_Plane)::DownCast(aSurface);
+        } else {
+          aPlane = aFindPlane.Plane();
+        }
+        aDir = aPlane->Axis().Direction();
+      } else {
+        return;
+      }
+
+      // Objects bounds
+      Standard_Real lowBnd, upperBnd;
+      getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd);
+
+      // Base bounds
+      Standard_Real lowBase, upperBase;
+      getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase);
+
+      // ----------.-----.---------.--------------.-----------> theDir
+      //       lowBnd   lowBase   upperBase    upperBnd
+
+      double aToSize_i = upperBnd - lowBase;
+      double aFromSize_i = upperBase - lowBnd;
+
+      if (aToSize_i > theToSize) theToSize = aToSize_i;
+      if (aFromSize_i > theFromSize) theFromSize = aFromSize_i;
+    }
+  }
+}
index da415d359c49cbfbe56e0b1e082e0016dceae297..49b3432445b394744ae06d5faa901f6dde0dc01f 100644 (file)
@@ -193,6 +193,17 @@ public:
   /// \param[in] theShape shape that should be exploded
   /// \return list of sub-shapes (vertices, edges, faces, solids)
   GEOMALGOAPI_EXPORT static ListOfShape getLowLevelSubShapes(const GeomShapePtr& theShape);
+
+  /// \brief Calculate prism sizes to ensure that it passes through all objects
+  /// \param[in] theObjects objects to be joined/cutted by the prism
+  /// \param[in] theBaseShapes bases of the prism
+  /// \param[in] theDir direction of the prism
+  /// \param[out] theToSize upper offset of the prism
+  /// \param[out] theFromSize lower offset of the prism
+  GEOMALGOAPI_EXPORT static void computeThroughAll(const ListOfShape& theObjects,
+                                                   const ListOfShape& theBaseShapes,
+                                                   const std::shared_ptr<GeomAPI_Dir> theDir,
+                                                   double& theToSize, double& theFromSize);
 };
 
 #endif
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.cpp
new file mode 100644 (file)
index 0000000..f64ef60
--- /dev/null
@@ -0,0 +1,88 @@
+// 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 "GeomAlgoAPI_ThroughAll.h"
+
+#include <GeomAlgoAPI_Boolean.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <BRep_Builder.hxx>
+#include <BOPAlgo_BOP.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopExp_Explorer.hxx>
+
+//=================================================================================================
+GeomAlgoAPI_ThroughAll::GeomAlgoAPI_ThroughAll(std::shared_ptr<GeomAlgoAPI_Prism> thePrismAlgo,
+                                               const ListOfShape& theObjects)
+: GeomAlgoAPI_Boolean(thePrismAlgo->shape(), theObjects, GeomAlgoAPI_Tools::BOOL_CUT)
+{
+  removeEnds(thePrismAlgo);
+}
+
+//=================================================================================================
+void GeomAlgoAPI_ThroughAll::removeEnds(std::shared_ptr<GeomAlgoAPI_Prism> thePrismAlgo)
+{
+  GeomShapePtr aCuttedTool = shape(); // result of BOP Cut (thePrismAlgo->shape() by theObjects)
+
+  // Simplify the result
+  ListOfShape aPieces = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aCuttedTool);
+
+  // Get end shapes of Prism
+  const ListOfShape& fromShapes = thePrismAlgo->fromShapes();
+  const ListOfShape& toShapes = thePrismAlgo->toShapes();
+  ListOfShape endShapes (fromShapes);
+  endShapes.insert(endShapes.end(), toShapes.begin(), toShapes.end());
+
+  // Throw away end pieces of cutted tools (containing endShapes)
+  TopTools_ListOfShape listTools;
+  for (ListOfShape::const_iterator
+         anIt = aPieces.begin(); anIt != aPieces.end(); anIt++) {
+    TopoDS_Shape aPiece = (*anIt)->impl<TopoDS_Shape>();
+    bool endPiece = false;
+
+    for (ListOfShape::const_iterator aBaseIt = endShapes.begin();
+         aBaseIt != endShapes.end() && !endPiece; aBaseIt++) {
+      // Check, if the piece contains aBase (one of endShapes)
+      TopoDS_Shape aBase = (*aBaseIt)->impl<TopoDS_Shape>();
+      TopExp_Explorer anExp (aPiece, aBase.ShapeType());
+      for (; anExp.More() && !endPiece; anExp.Next()) {
+        if (anExp.Current().IsSame(aBase))
+          endPiece = true;
+      }
+    }
+
+    if (!endPiece) {
+      listTools.Append(aPiece);
+    }
+  }
+
+  BRep_Builder aBuilder;
+  TopoDS_Compound aCompound;
+  aBuilder.MakeCompound(aCompound);
+  for (TopTools_ListOfShape::Iterator anIt(listTools); anIt.More(); anIt.Next()) {
+    aBuilder.Add(aCompound, anIt.Value());
+  }
+
+  std::shared_ptr<GeomAPI_Shape> aShape (new GeomAPI_Shape());
+  aShape->setImpl(new TopoDS_Shape(aCompound));
+  this->setShape(aShape);
+  this->setDone(true);
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h b/src/GeomAlgoAPI/GeomAlgoAPI_ThroughAll.h
new file mode 100644 (file)
index 0000000..bd54dd7
--- /dev/null
@@ -0,0 +1,46 @@
+// 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 GeomAlgoAPI_ThroughAll_H_
+#define GeomAlgoAPI_ThroughAll_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_Boolean.h>
+#include <GeomAlgoAPI_Prism.h>
+//#include <GeomAlgoAPI_Tools.h>
+
+#include <GeomAPI_Shape.h>
+
+/// \class GeomAlgoAPI_ThroughAll
+/// \ingroup DataAlgo
+/// \brief Cuts a prism by all given objects, throw away end pieces
+class GeomAlgoAPI_ThroughAll : public GeomAlgoAPI_Boolean
+{
+public:
+
+  /// Constructor.
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_ThroughAll (std::shared_ptr<GeomAlgoAPI_Prism> thePrismAlgo,
+                                             const ListOfShape& theObjects);
+
+private:
+  /// Builds resulting shape.
+  void removeEnds (std::shared_ptr<GeomAlgoAPI_Prism> thePrismAlgo);
+};
+
+#endif
index c33177b73d961182d402d189ed6032270f9c3203..cfed1f1992a766cb871a625e2ffa467da73ddaed 100644 (file)
@@ -20,6 +20,7 @@
 #include "GeomAlgoAPI_UnifySameDomain.h"
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_DFLoader.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 
 #include <ShapeUpgrade_UnifySameDomain.hxx>
@@ -113,6 +114,10 @@ void GeomAlgoAPI_UnifySameDomain::build(const GeomShapePtr& theShape,
   if (aResult.IsNull()) {
     return;
   }
+  // take off the compound if it consists of single sub-shape
+  if (aResult.ShapeType() == TopAbs_COMPOUND) {
+    aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+  }
 
   if (theIsToSimplifyShell && aResult.ShapeType() == TopAbs_SHELL) {
     int aNb = 0;
index d03030e359c845a8f83594f45ff13137bde423ec..23c7ce1c4141c879640569ab080848dd5b811f93 100644 (file)
@@ -79,5 +79,6 @@ void GeomData_Dir::reinit()
   if (!myIsInitialized) {
     // create attribute: not initialized by value yet, just zero
     myCoords = TDataStd_RealArray::Set(myLab, 0, 2);
+    myIsInitialized = true;
   }
 }
index fa7830d936d05df07be7ede37672a10b26c245c1..ecc087c26d2dfbc9722f0fbc67ecb5d0e8fd2b28 100644 (file)
@@ -41,6 +41,7 @@ SET(PROJECT_LIBRARIES
 
 INCLUDE_DIRECTORIES(
   ../GeomAPI        # only for SWIG
+  ../Events         # only for SWIG
   ../ModelAPI
 )
 
index df13808e459934ca4cd9946a2f4a2d5442492a43..b23de60169fc52bbaff275f51837ed215f67d7c8 100644 (file)
@@ -22,6 +22,7 @@
 
   #include <GeomAPI_swig.h>
   #include <ModelAPI_swig.h>
+  #include <Events_MessageGroup.h>
 
   #include "GeomDataAPI.h"
   #include "GeomDataAPI_Point.h"
index 18e5c437c1cd10d24fbde0d7dc9328af5d1a9b8c..71d098704cce957b0b4e13484b02570a7d7a8380 100644 (file)
@@ -37,6 +37,7 @@ SET(PROJECT_HEADERS
     GeomValidators_ValueOrder.h
     GeomValidators_Intersected.h
     GeomValidators_NotSelfIntersected.h
+    GeomValidators_GlobalSelection.h
 )
 
 SET(PROJECT_SOURCES
@@ -56,6 +57,7 @@ SET(PROJECT_SOURCES
     GeomValidators_ValueOrder.cpp
     GeomValidators_Intersected.cpp
     GeomValidators_NotSelfIntersected.cpp
+    GeomValidators_GlobalSelection.cpp
 )
 
 SET(PROJECT_LIBRARIES
index b00864d4d7851f00d74851041d68dbb79b0162a9..098f706fc4963f9253979f7a5a3faac12fbbd5c1 100644 (file)
@@ -65,7 +65,7 @@ bool GeomValidators_BodyShapes::isValid(const AttributePtr& theAttribute,
           break;
       }
       if (aIt == aResList.cend()) {
-        theError = "Error: Feature doesn't creates body.";
+        theError = "Error: Feature doesn't create body.";
         return false;
       }
     }
diff --git a/src/GeomValidators/GeomValidators_GlobalSelection.cpp b/src/GeomValidators/GeomValidators_GlobalSelection.cpp
new file mode 100644 (file)
index 0000000..35d6008
--- /dev/null
@@ -0,0 +1,69 @@
+// 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 "GeomValidators_GlobalSelection.h"
+
+#include <Events_InfoMessage.h>
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Object.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_ResultBody.h>
+
+bool GeomValidators_GlobalSelection::isValid(const AttributePtr& theAttribute,
+                                             const std::list<std::string>& theArguments,
+                                             Events_InfoMessage& theError) const
+{
+  std::string anAttributeType = theAttribute->attributeType();
+  if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
+    AttributeSelectionPtr anAttrSelection =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+    ResultPtr aContext = anAttrSelection->context();
+    if (!aContext.get()) {
+      theError = "Error: Context is empty.";
+      return false;
+    }
+
+    GeomShapePtr aShape = anAttrSelection->value();
+    if (aShape && !aShape->isEqual(aContext->shape())) {
+      theError = "Error: Local selection not allowed.";
+      return false;
+    }
+  } else if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
+    AttributeSelectionListPtr anAttrSelectionList =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+
+    // All objects should not be result constructions.
+    for(int anIndex = 0, aSize = anAttrSelectionList->size(); anIndex < aSize; ++anIndex) {
+      AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
+      if(!isValid(anAttrSelection, theArguments, theError)) {
+        return false;
+      }
+    }
+  } else {
+// LCOV_EXCL_START
+    theError = "Error: Attribute \"%1\" does not supported by this validator.";
+    theError.arg(anAttributeType);
+    return false;
+// LCOV_EXCL_STOP
+  }
+
+  return true;
+}
diff --git a/src/GeomValidators/GeomValidators_GlobalSelection.h b/src/GeomValidators/GeomValidators_GlobalSelection.h
new file mode 100644 (file)
index 0000000..3837478
--- /dev/null
@@ -0,0 +1,44 @@
+// 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 GeomValidators_GlobalSelection_H
+#define GeomValidators_GlobalSelection_H
+
+#include <GeomValidators.h>
+
+#include <ModelAPI_AttributeValidator.h>
+#include <ModelAPI_Attribute.h>
+
+/**
+ *  Check the Selection/SelectionList attribute for result selected.
+ */
+class GeomValidators_GlobalSelection : public ModelAPI_AttributeValidator
+{
+public:
+  /// \return True if the attribute is valid.
+  ///         It checks whether the selected object is a full result.
+  /// \param[in] theAttribute an attribute to check
+  /// \param[in] theArguments a filter parameters
+  /// \param[out] theError error message.
+  GEOMVALIDATORS_EXPORT virtual bool isValid(const AttributePtr& theAttribute,
+                                             const std::list<std::string>& theArguments,
+                                             Events_InfoMessage& theError) const;
+};
+
+#endif
index a30aa6a156fe4558f4f32f1f2c85e8e46e5eb380..77a27ea8ad6ec5698656dc03bcd61a888f2534ef 100644 (file)
@@ -25,6 +25,7 @@
 #include <GeomValidators_DifferentShapes.h>
 #include <GeomValidators_Face.h>
 #include <GeomValidators_Finite.h>
+#include <GeomValidators_GlobalSelection.h>
 #include <GeomValidators_ShapeType.h>
 #include <GeomValidators_ZeroOffset.h>
 #include <GeomValidators_FeatureKind.h>
@@ -60,6 +61,7 @@ GeomValidators_Plugin::GeomValidators_Plugin()
   aFactory->registerValidator("GeomValidators_Intersected", new GeomValidators_Intersected);
   aFactory->registerValidator("GeomValidators_NotSelfIntersected",
                               new GeomValidators_NotSelfIntersected);
+  aFactory->registerValidator("GeomValidators_GlobalSelection", new GeomValidators_GlobalSelection);
 
   // Do not register this plugin because it doesn't create features
   //ModelAPI_Session::get()->registerPlugin(this);
index 411a1a21ef59acb0b5a9dd70aa43e1778fda1887..3a52d2d515d992becc252e778487441bd5346a41 100644 (file)
@@ -52,6 +52,7 @@ bool GeomValidators_ZeroOffset::isValid(const std::shared_ptr<ModelAPI_Feature>&
   if(theFeature->string(*anIt)) {
     aSelectedMethod = theFeature->string(*anIt)->value();
   }
+  if (aSelectedMethod == "ThroughAll") return true;
   anIt++;
   std::string aCreationMethod = *anIt;
   anIt++;
index 554b8c03a56b0d03c8040699d627ca1f5043565b..eaac6b906a332e4eddcde3e7621f0c4de4a8d630 100644 (file)
@@ -53,6 +53,7 @@ SET(PROJECT_HEADERS
     Model_ResultField.h
     Model_ResultGroup.h
     Model_ResultParameter.h
+    Model_Tools.h
     Model_Update.h
     Model_Validator.h
 )
@@ -90,6 +91,7 @@ SET(PROJECT_SOURCES
     Model_ResultField.cpp
     Model_ResultGroup.cpp
     Model_ResultParameter.cpp
+    Model_Tools.cpp
     Model_Update.cpp
     Model_Validator.cpp
 )
@@ -115,6 +117,7 @@ SET(PROJECT_INCLUDES
   ../GeomAlgoAPI
   ../GeomAPI
   ../ModelGeomAlgo
+  ../ConstructionPlugin
   ${OpenCASCADE_INCLUDE_DIR}
 )
 
index 6cfb6a3a38db0fce52b852cab4547a685ca39aaf..c2772757f8dd2bcc3f2c55e942c561c504ad7b83 100644 (file)
@@ -22,6 +22,9 @@
 
 #include <ModelAPI_Events.h>
 
+#include <BinDrivers_DocumentRetrievalDriver.hxx>
+#include <BinDrivers_DocumentStorageDriver.hxx>
+
 IMPLEMENT_STANDARD_RTTIEXT(Model_Application, TDocStd_Application)
 
 static Handle_Model_Application TheApplication = new Model_Application;
@@ -168,6 +171,13 @@ Model_Application::Model_Application()
   // store handle to the application to avoid nullification
   static Handle(Model_Application) TheKeepHandle;
   TheKeepHandle = this;
+  // additional file format supported
+  static TCollection_ExtendedString THE_DOC_FORMAT("BinShaperPart");
+  static TCollection_ExtendedString THE_FILE_EXT("shaperpart");
+  Handle(PCDM_RetrievalDriver) aReader = new BinDrivers_DocumentRetrievalDriver;
+  Handle(PCDM_StorageDriver) aWriter = new BinDrivers_DocumentStorageDriver;
+  TheKeepHandle->DefineFormat(THE_DOC_FORMAT, "Shaper Part document", THE_FILE_EXT,
+                              aReader, aWriter);
 }
 
 //=======================================================================
index 3ee99ee6af12816746d0d9833473e54c1333b34b..82ea6415e2003115384dea46c61c212013771160 100644 (file)
@@ -43,36 +43,42 @@ int Model_AttributeIntArray::size()
   return (myArray.IsNull() || !myArray->IsValid()) ? 0 : myArray->Length();
 }
 
-void Model_AttributeIntArray::setSize(const int theSize)
+void Model_AttributeIntArray::setSize(const int theSize, bool sendUpdated)
 {
   if (myArray.IsNull() || !myArray->IsValid()) { // create array if it is not done yet
     if (theSize != 0) { // if size is zero, nothing to do (null array means there is no array)
       myArray = TDataStd_IntegerArray::Set(myLab, 0, theSize - 1);
-      owner()->data()->sendAttributeUpdated(this);
+      if (sendUpdated)
+        owner()->data()->sendAttributeUpdated(this);
     }
   } else { // reset the old array
     if (theSize) {
       if (theSize != myArray->Length()) { // old data is not kept, a new array is created
         Handle(TColStd_HArray1OfInteger) aNewArray = new TColStd_HArray1OfInteger(0, theSize - 1);
         myArray->ChangeArray(aNewArray);
-        owner()->data()->sendAttributeUpdated(this);
+        if (sendUpdated)
+          owner()->data()->sendAttributeUpdated(this);
       }
     } else { // size is zero => array must be erased
       if (!myArray.IsNull()) {
         myArray.Nullify();
         myLab.ForgetAttribute(TDataStd_IntegerArray::GetID());
-        owner()->data()->sendAttributeUpdated(this);
+        if (sendUpdated)
+          owner()->data()->sendAttributeUpdated(this);
       }
     }
   }
 }
 
 void Model_AttributeIntArray::setValue(const int theIndex,
-                                       const int theValue)
+                                       const int theValue,
+                                       bool sendUpdated)
 {
   if (myArray->Value(theIndex) != theValue) {
+    setInitialized();
     myArray->SetValue(theIndex, theValue);
-    owner()->data()->sendAttributeUpdated(this);
+    if (sendUpdated)
+      owner()->data()->sendAttributeUpdated(this);
   }
 }
 
index 1243a14ceb9a6fda73f7baa576cfc2be2ed4a5c6..98040141e382df0fe83675cf12c6d6b661240e06 100644 (file)
@@ -47,11 +47,13 @@ class Model_AttributeIntArray : public ModelAPI_AttributeIntArray
   MODEL_EXPORT virtual int size();
 
   /// Sets the new size of the array. The previous data is erased.
-  MODEL_EXPORT virtual void setSize(const int theSize);
+  MODEL_EXPORT virtual void setSize(const int theSize,
+                                    bool sendUpdated = true);
 
   /// Defines the value of the array by index [0; size-1]
   MODEL_EXPORT virtual void setValue(const int theIndex,
-                                     const int theValue);
+                                     const int theValue,
+                                     bool sendUpdated = true);
 
   /// Returns the value by the index
   MODEL_EXPORT virtual int value(const int theIndex);
index 2a2f5fa6791fee09f7b3762587f1663bb988d611..0b2d2869a3ed7f120f5f1449c405a21d598d94d9 100644 (file)
@@ -125,6 +125,7 @@ void Model_AttributeReference::reinit()
   myIsInitialized = myLab.FindAttribute(TDF_Reference::GetID(), myRef) == Standard_True;
   if (!myIsInitialized) {
     myRef = TDF_Reference::Set(myLab, myLab);  // not initialized references to itself
+    myIsInitialized = true;
   } else {
     if (owner()) {
       std::shared_ptr<Model_Document> aDoc =
index 479df0e05a5df87db9023ba1aa40413c32035d3f..8ff6d81f8a87b93a8b4a402de30c454f7893cd8b 100644 (file)
@@ -302,7 +302,7 @@ GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::Cen
 
 std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
 {
-  if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
+  if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
     return std::shared_ptr<GeomAPI_Shape>();
   CenterType aType = NOT_CENTER;
   std::shared_ptr<GeomAPI_Shape> aResult = internalValue(aType);
@@ -421,32 +421,29 @@ bool Model_AttributeSelection::isInvalid()
 
 bool Model_AttributeSelection::isInitialized()
 {
-  if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized
-    std::shared_ptr<GeomAPI_Shape> aResult;
-    if (myRef.isInitialized()) {
-      TDF_Label aSelLab = selectionLabel();
-      // it is just reference to shape, not sub-shape
-      if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
-        ResultPtr aContext = context();
-        return aContext.get() != NULL;
-      }
-      Handle(TNaming_NamedShape) aSelection;
-      if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
-        return !aSelection->Get().IsNull();
-      } else { // for simple construction element: just shape of this construction element
-        if (myRef.value().get())
-          return true;
-        // check that this is on open of document, so, results are not initialized yet
-        TDF_Label aRefLab = myRef.myRef->Get();
-        if (aRefLab.IsNull() || !owner().get())
-          return false;
-        std::shared_ptr<Model_Document> aMyDoc =
-          std::dynamic_pointer_cast<Model_Document>(owner()->document());
-        if (!aMyDoc.get())
-          return false;
-        // check at least the feature exists
-        return aMyDoc->featureByLab(aRefLab).get() != NULL;
-      }
+  if (myRef.isInitialized()) {
+    TDF_Label aSelLab = selectionLabel();
+    // it is just reference to shape, not sub-shape
+    if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
+      ResultPtr aContext = context();
+      return aContext.get() != NULL;
+    }
+    Handle(TNaming_NamedShape) aSelection;
+    if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
+      return !aSelection->Get().IsNull();
+    } else { // for simple construction element: just shape of this construction element
+      if (myRef.value().get())
+        return true;
+      // check that this is on open of document, so, results are not initialized yet
+      TDF_Label aRefLab = myRef.myRef->Get();
+      if (aRefLab.IsNull() || !owner().get())
+        return false;
+      std::shared_ptr<Model_Document> aMyDoc =
+        std::dynamic_pointer_cast<Model_Document>(owner()->document());
+      if (!aMyDoc.get())
+        return false;
+      // check at least the feature exists
+      return aMyDoc->featureByLab(aRefLab).get() != NULL;
     }
   }
   return false;
@@ -476,7 +473,7 @@ void Model_AttributeSelection::setID(const std::string theID)
 
 ResultPtr Model_AttributeSelection::context()
 {
-  if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
+  if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
     return ResultPtr();
 
   if (myTmpContext.get() || myTmpSubShape.get()) {
@@ -2034,3 +2031,9 @@ TDF_Label Model_AttributeSelection::baseDocumentLab()
   static TDF_Label anEmpty;
   return anEmpty;
 }
+
+void Model_AttributeSelection::reset()
+{
+  ModelAPI_AttributeSelection::reset();
+  myRef.reset();
+}
index bd26925b3fd229cac2ab96282b2d645a01fa4407..50a7ddbb91645726c340b095ce6db0ac97e3acd8 100644 (file)
@@ -143,6 +143,9 @@ public:
   /// Makes the current local selection becomes all sub-shapes with same base geometry.
   MODEL_EXPORT virtual void combineGeometrical();
 
+  /// Resets attribute to deafult state
+  MODEL_EXPORT virtual void reset();
+
 protected:
   /// Objects are created for features automatically
   MODEL_EXPORT Model_AttributeSelection(TDF_Label& theLabel);
index 10d11678d642420f5bde838baabe2072dce78114..e5641930e1b1253ab05e0a83f5afbd1ab8c34137 100644 (file)
@@ -35,6 +35,9 @@
 #include <Model_AttributeTables.h>
 #include <Model_Events.h>
 #include <Model_Expression.h>
+#include <Model_Tools.h>
+#include <Model_Validator.h>
+
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Result.h>
 #include <ModelAPI_ResultParameter.h>
@@ -43,7 +46,6 @@
 #include <ModelAPI_Session.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_Tools.h>
-#include <Model_Validator.h>
 
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 
 #include <TDataStd_Name.hxx>
 #include <TDataStd_AsciiString.hxx>
-#include <TDataStd_IntegerArray.hxx>
 #include <TDataStd_UAttribute.hxx>
-#include <TDF_AttributeIterator.hxx>
-#include <TDF_ChildIterator.hxx>
-#include <TDF_RelocationTable.hxx>
 #include <TDF_ChildIDIterator.hxx>
-#include <TColStd_HArray1OfByte.hxx>
 
 #include <string>
 
@@ -434,7 +431,8 @@ void Model_Data::sendAttributeUpdated(ModelAPI_Attribute* theAttr)
     }
   } else {
     // trim: need to redisplay or set color in the python script
-    if (myObject && (theAttr->attributeType() == "Point2D" || theAttr->id() == "Color")) {
+    if (myObject && (theAttr->attributeType() == "Point2D" || theAttr->id() == "Color" ||
+      theAttr->id() == "Transparency" || theAttr->id() == "Deflection")) {
       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
       ModelAPI_EventCreator::get()->sendUpdated(myObject, anEvent);
     }
@@ -797,37 +795,10 @@ void Model_Data::referencesToObjects(
   }
 }
 
-/// makes copy of all attributes on the given label and all sub-labels
-static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
-  TDF_AttributeIterator anAttrIter(theSource);
-  for(; anAttrIter.More(); anAttrIter.Next()) {
-    Handle(TDF_Attribute) aTargetAttr;
-    if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
-      // create a new attribute if not yet exists in the destination
-           aTargetAttr = anAttrIter.Value()->NewEmpty();
-      theDestination.AddAttribute(aTargetAttr);
-    }
-    // no special relocation, empty map, but self-relocation is on: copy references w/o changes
-    Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(Standard_True);
-    anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
-    // an exception: if a source reference refers itself, a copy must also refer itself
-    if (aTargetAttr->ID() == TDF_Reference::GetID()) {
-      Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
-      if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label()))
-        aTargetRef->Set(aTargetRef->Label());
-    }
-  }
-  // copy the sub-labels content
-  TDF_ChildIterator aSubLabsIter(theSource);
-  for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
-    copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()));
-  }
-}
-
 void Model_Data::copyTo(std::shared_ptr<ModelAPI_Data> theTarget)
 {
   TDF_Label aTargetRoot = std::dynamic_pointer_cast<Model_Data>(theTarget)->label();
-  copyAttrs(myLab, aTargetRoot);
+  Model_Tools::copyAttrs(myLab, aTargetRoot);
   // reinitialize Model_Attributes by TDF_Attributes set
   std::shared_ptr<Model_Data> aTData = std::dynamic_pointer_cast<Model_Data>(theTarget);
   aTData->myAttrs.clear();
index 9f26d8de1050bd4a25b85f481e00f243534c7906..7f9fa9b01584f120771ad4405ceaa1dfe24022bd 100644 (file)
@@ -96,6 +96,7 @@ class Model_Data : public ModelAPI_Data
   friend class Model_SelectionNaming;
   friend class Model_ResultConstruction;
   friend class Model_ResultBody;
+  friend class Model_Tools;
 
  public:
   /// The simplest constructor. "setLabel" must be called just after to initialize correctly.
index be2877848b1a34b891a39b3dae19561fb94e780a..79162a77945b2302e00d7ddc8818358b7cd60457 100644 (file)
@@ -23,6 +23,7 @@
 #include <Model_Application.h>
 #include <Model_Session.h>
 #include <Model_Events.h>
+#include <Model_Tools.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <TNaming_Iterator.hxx>
 #include <TNaming_NamedShape.hxx>
 #include <TNaming_Tool.hxx>
-#include<TNaming_OldShapeIterator.hxx>
+#include <TNaming_OldShapeIterator.hxx>
 #include <TopTools_DataMapOfShapeShape.hxx>
 #include <TopTools_ListOfShape.hxx>
 
 #include <TopExp_Explorer.hxx>
 #include <TopoDS_Shape.hxx>
 
+#include <OSD_Directory.hxx>
 #include <OSD_File.hxx>
 #include <OSD_Path.hxx>
+#include <OSD_Protection.hxx>
 #include <CDF_Session.hxx>
 #include <CDF_Directory.hxx>
+#include <UTL.hxx>
 
 #include <climits>
 #ifndef WIN32
@@ -221,24 +225,20 @@ static void updateShapesFromRoot(const TDF_Label theThisAccess, const TDF_Label
 }
 // LCOV_EXCL_STOP
 
-bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis)
+static bool loadDocument(Handle(Model_Application) theApp,
+                         Handle(TDocStd_Document)& theDoc,
+                         const TCollection_ExtendedString& theFilename)
 {
-  Handle(Model_Application) anApp = Model_Application::getApplication();
-  if (isRoot()) {
-    anApp->setLoadPath(theDirName);
-  }
-  TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName));
-  PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
-  Handle(TDocStd_Document) aLoaded;
+  PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus)-1;
   try {
-    aStatus = anApp->Open(aPath, aLoaded);
+    aStatus = theApp->Open(theFilename, theDoc);
   } catch (Standard_Failure const& anException) {
     Events_InfoMessage("Model_Document",
         "Exception in opening of document: %1").arg(anException.GetMessageString()).send();
     return false;
   }
-  bool isError = aStatus != PCDM_RS_OK;
-  if (isError) {
+  bool isOk = aStatus == PCDM_RS_OK;
+  if (!isOk) {
     // LCOV_EXCL_START
     switch (aStatus) {
       case PCDM_RS_UnknownDocument:
@@ -296,9 +296,22 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum
     }
     // LCOV_EXCL_STOP
   }
+  return isOk;
+}
+
+bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis)
+{
+  Handle(Model_Application) anApp = Model_Application::getApplication();
+  if (isRoot()) {
+    anApp->setLoadPath(theDirName);
+  }
+  TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName));
+  Handle(TDocStd_Document) aLoaded;
+  bool isOk = loadDocument(anApp, aLoaded, aPath);
+
   std::shared_ptr<Model_Session> aSession =
     std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
-  if (!isError) {
+  if (isOk) {
     myDoc = aLoaded;
     myDoc->SetUndoLimit(UNDO_LIMIT);
 
@@ -333,7 +346,124 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum
   } else { // open failed, but new document was created to work with it: inform the model
     aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false);
   }
-  return !isError;
+  return isOk;
+}
+
+bool Model_Document::importPart(const char* theFileName,
+                                std::list<std::shared_ptr<ModelAPI_Feature> >& theImported,
+                                bool theCheckOnly)
+{
+  Handle(Model_Application) anApp = Model_Application::getApplication();
+  TCollection_ExtendedString aFormat;
+  if (!anApp->Format(theFileName, aFormat))
+    return false;
+
+  Handle(TDocStd_Document) aTempDoc;
+  bool isOk = loadDocument(anApp, aTempDoc, theFileName);
+
+  if (isOk && theCheckOnly) {
+    // verify all features are applicable for the current document type (e.g. PartSet)
+    std::shared_ptr<Model_Session> aSession =
+        std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get());
+    for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More() && isOk; anIt.Next()) {
+      TDF_Label aCurrentLab = anIt.Value();
+      Handle(TDataStd_Comment) aFeatureID;
+      TDF_Label aNewFeatuerLab;
+      if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) {
+        TCollection_AsciiString anID(aFeatureID->Get());
+        std::string aFeatureKind(anID.ToCString());
+        if (aSession->myPlugins.find(aFeatureKind) != aSession->myPlugins.end()) {
+          std::string& aDocKind = aSession->myPlugins[aFeatureKind].second;
+          isOk = aDocKind.empty() || aDocKind == kind();
+        }
+      }
+    }
+  }
+
+  if (isOk && !theCheckOnly) {
+    // copy features from the temporary document to the current
+    Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable();
+    TDF_LabelList anAllNewFeatures;
+    // Perform the copying twice for correct references:
+    // 1. copy labels hierarchy and fill the relocation table
+    TDF_Label aMain = myDoc->Main();
+    for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) {
+      TDF_Label aCurrentLab = anIt.Value();
+      Handle(TDataStd_Comment) aFeatureID;
+      TDF_Label aNewFeatuerLab;
+      if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) {
+        TCollection_AsciiString anID(aFeatureID->Get());
+        FeaturePtr aNewFeature = addFeature(anID.ToCString());
+        std::shared_ptr<Model_Data> aData =
+            std::dynamic_pointer_cast<Model_Data>(aNewFeature->data());
+        aNewFeatuerLab = aData->label().Father();
+        Model_Tools::copyLabels(aCurrentLab, aNewFeatuerLab, aRelocTable);
+        theImported.push_back(aNewFeature);
+      }
+      anAllNewFeatures.Append(aNewFeatuerLab);
+    }
+    // 2. copy attributes
+    std::set<TCollection_AsciiString> aCoordinateLabels;
+    Model_Tools::labelsOfCoordinates(aCoordinateLabels, aRelocTable);
+    TDF_ListIteratorOfLabelList aNewIt(anAllNewFeatures);
+    for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) {
+      TDF_Label aCurrentLab = anIt.Value();
+      TDF_Label aFeatureLab = aNewIt.Value();
+      if (aFeatureLab.IsNull())
+        anAllNewFeatures.Remove(aNewIt);
+      else {
+        Model_Tools::copyAttrsAndKeepRefsToCoordinates(
+            aCurrentLab, aFeatureLab, aCoordinateLabels, aRelocTable);
+        aNewIt.Next();
+      }
+    }
+
+    myObjs->synchronizeFeatures(anAllNewFeatures, true, false, false, true);
+  }
+
+  if (anApp->CanClose(aTempDoc) == CDM_CCS_OK)
+    anApp->Close(aTempDoc);
+  return isOk;
+}
+
+static bool saveDocument(Handle(Model_Application) theApp,
+                         Handle(TDocStd_Document) theDoc,
+                         const TCollection_ExtendedString& theFilename)
+{
+  PCDM_StoreStatus aStatus;
+  try {
+    // create the directory to save the document
+    OSD_Path aPathToFile = UTL::Path(theFilename);
+    aPathToFile.SetName("");
+    aPathToFile.SetExtension("");
+    OSD_Directory aBaseDir(aPathToFile);
+    if (aPathToFile.TrekLength() != 0 && !aBaseDir.Exists())
+      aBaseDir.Build(OSD_Protection());
+    // save the document
+    aStatus = theApp->SaveAs(theDoc, theFilename);
+  }
+  catch (Standard_Failure const& anException) {
+    Events_InfoMessage("Model_Document",
+      "Exception in saving of document: %1").arg(anException.GetMessageString()).send();
+    return false;
+  }
+  bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
+  if (!isDone) {
+    switch (aStatus) {
+    case PCDM_SS_DriverFailure:
+      Events_InfoMessage("Model_Document",
+        "Can not save document: save driver-library failure").send();
+      break;
+    case PCDM_SS_WriteFailure:
+      Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send();
+      break;
+    case PCDM_SS_Failure:
+    default:
+      Events_InfoMessage("Model_Document", "Can not save document").send();
+      break;
+    }
+  }
+  return isDone;
 }
 
 bool Model_Document::save(
@@ -374,34 +504,7 @@ bool Model_Document::save(
   }
   // filename in the dir is id of document inside of the given directory
   TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName));
-  PCDM_StoreStatus aStatus;
-  try {
-    aStatus = anApp->SaveAs(myDoc, aPath);
-  } catch (Standard_Failure const& anException) {
-    Events_InfoMessage("Model_Document",
-        "Exception in saving of document: %1").arg(anException.GetMessageString()).send();
-    if (aWasCurrent.get()) { // return the current feature to the initial position
-      setCurrentFeature(aWasCurrent, false);
-      aSession->setCheckTransactions(true);
-    }
-    return false;
-  }
-  bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
-  if (!isDone) {
-    switch (aStatus) {
-      case PCDM_SS_DriverFailure:
-        Events_InfoMessage("Model_Document",
-                           "Can not save document: save driver-library failure").send();
-        break;
-      case PCDM_SS_WriteFailure:
-        Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send();
-        break;
-      case PCDM_SS_Failure:
-      default:
-        Events_InfoMessage("Model_Document", "Can not save document").send();
-        break;
-    }
-  }
+  bool isDone = saveDocument(anApp, myDoc, aPath);
 
   if (aWasCurrent.get()) { // return the current feature to the initial position
     setCurrentFeature(aWasCurrent, false);
@@ -444,6 +547,44 @@ bool Model_Document::save(
   return isDone;
 }
 
+bool Model_Document::save(const char* theFilename,
+                          const std::list<FeaturePtr>& theExportFeatures) const
+{
+  Handle(Model_Application) anApp = Model_Application::getApplication();
+  TCollection_ExtendedString aFormat;
+  if (!anApp->Format(theFilename, aFormat))
+    return false;
+
+  Handle(TDocStd_Document) aTempDoc = new TDocStd_Document(aFormat);
+  TDF_Label aMain = aTempDoc->Main();
+
+  Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable();
+  std::list<FeaturePtr>::const_iterator anIt = theExportFeatures.begin();
+  // Perform the copying twice for correct references:
+  // 1. copy labels hierarchy and fill the relocation table
+  for (; anIt != theExportFeatures.end(); ++anIt) {
+    TDF_Label aFeatureLab = aMain.NewChild();
+    std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>((*anIt)->data());
+    Model_Tools::copyLabels(aData->label().Father(), aFeatureLab, aRelocTable);
+  }
+  // 2. copy attributes
+  std::set<TCollection_AsciiString> aCoordinateLabels;
+  Model_Tools::labelsOfCoordinates(aCoordinateLabels, aRelocTable);
+  TDF_ChildIterator aChildIt(aMain);
+  for (anIt = theExportFeatures.begin(); anIt != theExportFeatures.end(); ++anIt) {
+    TDF_Label aFeatureLab = aChildIt.Value();
+    std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>((*anIt)->data());
+    Model_Tools::copyAttrsAndKeepRefsToCoordinates(
+        aData->label().Father(), aFeatureLab, aCoordinateLabels, aRelocTable);
+    aChildIt.Next();
+  }
+
+  bool isDone = saveDocument(anApp, aTempDoc, theFilename);
+  if (aTempDoc->CanClose() == CDM_CCS_OK)
+    aTempDoc->Close();
+  return isDone;
+}
+
 void Model_Document::close(const bool theForever)
 {
   std::shared_ptr<ModelAPI_Session> aPM = Model_Session::get();
@@ -1098,7 +1239,7 @@ static bool isSub(const CompositeFeaturePtr theMain, const FeaturePtr theSub) {
   return isSub(theMain, aParent);
 }
 
-void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
+void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis, const bool theSplit)
 {
   bool aCurrentUp = theMoved == currentFeature(false);
   if (aCurrentUp) {
@@ -1123,12 +1264,21 @@ void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
   }
 
   myObjs->moveFeature(theMoved, anAfterThisSub);
+
+  if (theSplit) { // split the group into sub-features
+    theMoved->customAction("split");
+  }
+
   if (aCurrentUp) { // make the moved feature enabled or disabled due to the real status
     setCurrentFeature(currentFeature(false), false);
   } else if (theAfterThis == currentFeature(false) || anAfterThisSub == currentFeature(false)) {
     // 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");
+  }
 }
 
 void Model_Document::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
index 72a570738b5080a167838dc2fa0830d3f43eeebf..277c822ba629730adc39a796a6a78192f72afcc2 100644 (file)
@@ -56,6 +56,17 @@ class Model_Document : public ModelAPI_Document
   MODEL_EXPORT virtual bool load(
     const char* theDirName, const char* theFileName, DocumentPtr theThis);
 
+  //! Loads the OCAF document from the file into the current document.
+  //! All the features are added after the active feature.
+  //! \param theFileName name of the file to import
+  //! \param theImported list of features imported from the file
+  //! \param theCheckOnly verify the document does not contain unappropriate features
+  //!                     (useful for import to PartSet), but do not import it
+  //! \returns true if file was loaded successfully
+  MODEL_EXPORT virtual bool importPart(const char* theFileName,
+                                   std::list<std::shared_ptr<ModelAPI_Feature> >& theImported,
+                                   bool theCheckOnly = false);
+
   //! Saves the OCAF document to the file.
   //! \param theDirName directory where the document will be saved
   //! \param theFileName a name of the document file to store
@@ -64,6 +75,12 @@ class Model_Document : public ModelAPI_Document
   MODEL_EXPORT virtual bool save(
     const char* theDirName, const char* theFileName, std::list<std::string>& theResults);
 
+  //! Export the list of features to the file
+  //! \param theFilename path to save the file
+  //! \param theExportFeatures list of features to export
+  MODEL_EXPORT virtual bool save(const char* theFilename,
+    const std::list<std::shared_ptr<ModelAPI_Feature> >& theExportFeatures) const;
+
   //! Removes document data
   //! \param theForever if it is false, document is just hidden
   //!                   (to keep possibility make it back on Undo/Redo)
@@ -110,7 +127,8 @@ class Model_Document : public ModelAPI_Document
   MODEL_EXPORT virtual void removeFeature(FeaturePtr theFeature);
 
   //! Moves the feature to make it after the given one in the history.
-  MODEL_EXPORT virtual void moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis);
+  MODEL_EXPORT virtual void moveFeature(
+    FeaturePtr theMoved, FeaturePtr theAfterThis, const bool theSplit = false);
 
   //! Returns the first found object in the group by the object name
   //! \param theGroupID group that contains an object
diff --git a/src/Model/Model_Tools.cpp b/src/Model/Model_Tools.cpp
new file mode 100644 (file)
index 0000000..4883180
--- /dev/null
@@ -0,0 +1,181 @@
+// 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 <Model_Tools.h>
+#include <Model_Data.h>
+
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_Result.h>
+#include <ModelAPI_Session.h>
+
+#include <ConstructionPlugin_Axis.h>
+#include <ConstructionPlugin_Plane.h>
+#include <ConstructionPlugin_Point.h>
+
+#include <Standard_GUID.hxx>
+
+#include <TDataStd_Comment.hxx>
+#include <TDataStd_AsciiString.hxx>
+
+#include <TDF_AttributeIterator.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TDF_Reference.hxx>
+#include <TDF_RelocationTable.hxx>
+#include <TDF_Tool.hxx>
+
+void Model_Tools::copyLabels(TDF_Label theSource, TDF_Label theDestination,
+                             Handle(TDF_RelocationTable) theRelocTable)
+{
+  theRelocTable->SetRelocation(theSource, theDestination);
+  // copy the sub-labels hierarchy
+  TDF_ChildIterator aSubLabsIter(theSource);
+  for (; aSubLabsIter.More(); aSubLabsIter.Next()) {
+    copyLabels(aSubLabsIter.Value(),
+               theDestination.FindChild(aSubLabsIter.Value().Tag()),
+               theRelocTable);
+  }
+}
+
+void Model_Tools::copyAttrs(TDF_Label theSource, TDF_Label theDestination,
+                            Handle(TDF_RelocationTable) theRelocTable)
+{
+  TDF_AttributeIterator anAttrIter(theSource);
+  for(; anAttrIter.More(); anAttrIter.Next()) {
+    Handle(TDF_Attribute) aTargetAttr;
+    if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
+      // create a new attribute if not yet exists in the destination
+           aTargetAttr = anAttrIter.Value()->NewEmpty();
+      theDestination.AddAttribute(aTargetAttr);
+    }
+    // no special relocation, empty map, but self-relocation is on: copy references w/o changes
+    Handle(TDF_RelocationTable) aRelocTable =
+        theRelocTable.IsNull() ? new TDF_RelocationTable(Standard_True) : theRelocTable;
+    anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
+    // an exception: if a source reference refers itself, a copy must also refer itself
+    if (aTargetAttr->ID() == TDF_Reference::GetID()) {
+      Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
+      if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label()))
+        aTargetRef->Set(aTargetRef->Label());
+    }
+  }
+  // copy the sub-labels content
+  TDF_ChildIterator aSubLabsIter(theSource);
+  for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
+    copyAttrs(aSubLabsIter.Value(),
+              theDestination.FindChild(aSubLabsIter.Value().Tag()),
+              theRelocTable);
+  }
+}
+
+static TCollection_AsciiString labelToString(TDF_Label theLabel)
+{
+  TCollection_AsciiString aLabString;
+  TDF_Tool::Entry(theLabel, aLabString);
+  return aLabString;
+}
+
+static void makeExternalReference(TDF_Label theDestination, TDF_Label theReferred)
+{
+  Handle(TDF_Attribute) aReference, aComment, aString;
+  theDestination.FindAttribute(TDF_Reference::GetID(), aReference);
+  // create new attributes if not yet exists in the destination
+  if (!theDestination.FindAttribute(TDataStd_Comment::GetID(), aComment)) {
+    aComment = new TDataStd_Comment;
+    theDestination.AddAttribute(aComment);
+  }
+  if (!theDestination.FindAttribute(TDataStd_AsciiString::GetID(), aString)) {
+    aString = new TDataStd_AsciiString;
+    theDestination.AddAttribute(aString);
+  }
+  // reference to itself
+  Handle(TDF_Reference)::DownCast(aReference)->Set(theDestination, theDestination);
+  // ID of the document
+  std::ostringstream aDocIdStr;
+  aDocIdStr << ModelAPI_Session::get()->moduleDocument()->id();
+  Handle(TDataStd_Comment)::DownCast(aComment)->Set(aDocIdStr.str().c_str());
+  // value of referred label
+  Handle(TDataStd_AsciiString)::DownCast(aString)->Set(labelToString(theReferred));
+}
+
+void Model_Tools::copyAttrsAndKeepRefsToCoordinates(
+    TDF_Label theSource,
+    TDF_Label theDestination,
+    const std::set<TCollection_AsciiString>& theCoordinateLabels,
+    Handle(TDF_RelocationTable) theRelocTable)
+{
+  TDF_AttributeIterator anAttrIter(theSource);
+  for(; anAttrIter.More(); anAttrIter.Next()) {
+    Handle(TDF_Attribute) aTargetAttr;
+    if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
+      // create a new attribute if not yet exists in the destination
+           aTargetAttr = anAttrIter.Value()->NewEmpty();
+      theDestination.AddAttribute(aTargetAttr);
+    }
+    anAttrIter.Value()->Paste(aTargetAttr, theRelocTable);
+    if (aTargetAttr->ID() == TDF_Reference::GetID()) {
+      Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
+      if (aTargetRef->Get().IsNull()) {
+        // may be refer to a cartesian coordinate entity
+        Handle(TDF_Reference) aSourceRef = Handle(TDF_Reference)::DownCast(anAttrIter.Value());
+        if (!aSourceRef.IsNull() && !aSourceRef->Get().IsNull()) {
+          std::set<TCollection_AsciiString>::const_iterator aFound =
+              theCoordinateLabels.find(labelToString(aSourceRef->Get()));
+          if (aFound != theCoordinateLabels.end())
+            makeExternalReference(theDestination, aSourceRef->Get());
+        }
+      }
+      else if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label())) {
+        // a source reference refers itself, a copy must also refer itself
+        aTargetRef->Set(aTargetRef->Label());
+      }
+    }
+  }
+  // copy the sub-labels content
+  TDF_ChildIterator aSubLabsIter(theSource);
+  for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
+    copyAttrsAndKeepRefsToCoordinates(
+        aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()),
+        theCoordinateLabels, theRelocTable);
+  }
+}
+
+void Model_Tools::labelsOfCoordinates(std::set<TCollection_AsciiString>& theCoordinateLabels,
+                                      Handle(TDF_RelocationTable) theRelocTable)
+{
+  DocumentPtr aPartSet = ModelAPI_Session::get()->moduleDocument();
+  std::list<FeaturePtr> aFeatures = aPartSet->allFeatures();
+  for (std::list<FeaturePtr>::iterator aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
+    FeaturePtr aCurFeat = *aFIt;
+    if (!aCurFeat->isInHistory() &&
+        (aCurFeat->getKind() == ConstructionPlugin_Point::ID() ||
+         aCurFeat->getKind() == ConstructionPlugin_Axis::ID() ||
+         aCurFeat->getKind() == ConstructionPlugin_Plane::ID())) {
+      ResultPtr aResult = aCurFeat->lastResult();
+      if (aResult) {
+        std::shared_ptr<Model_Data> aResData =
+            std::dynamic_pointer_cast<Model_Data>(aResult->data());
+        TDF_Label aLab = aResData->label().Father();
+        theCoordinateLabels.insert(labelToString(aLab));
+        // set relocation to empty, references will be set correctly while copying attributes
+        theRelocTable->SetRelocation(aLab, TDF_Label());
+      }
+    }
+  }
+}
diff --git a/src/Model/Model_Tools.h b/src/Model/Model_Tools.h
new file mode 100644 (file)
index 0000000..b7ec96c
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 Model_Tools_H_
+#define Model_Tools_H_
+
+#include <Model.h>
+
+#include <TDF_Label.hxx>
+#include <TDF_RelocationTable.hxx>
+
+#include <memory>
+#include <set>
+
+/// A collection of methods useful for different parts of data model.
+class Model_Tools
+{
+public:
+  /// makes copy of label and all its sub-labels without copying the attributes;
+  /// and feel the relocation table
+  static void copyLabels(TDF_Label theSource, TDF_Label theDestination,
+                         Handle(TDF_RelocationTable) theRelocTable);
+
+  /// makes copy of all attributes on the given label and all sub-labels
+  static void copyAttrs(TDF_Label theSource, TDF_Label theDestination,
+                        Handle(TDF_RelocationTable) theRelocTable = Handle(TDF_RelocationTable)());
+
+  /// makes copy of all attributes on the given label and all sub-labels,
+  /// but keep references to the Origin, coordinate axes and coordinate planes
+  static void copyAttrsAndKeepRefsToCoordinates(TDF_Label theSource, TDF_Label theDestination,
+      const std::set<TCollection_AsciiString>& theCoordinateLabels,
+      Handle(TDF_RelocationTable) theRelocTable);
+
+  /// collect labels of coordinate planes, axes, and origin
+  static void labelsOfCoordinates(
+      std::set<TCollection_AsciiString>& theCoordinateLabels,
+      Handle(TDF_RelocationTable) theRelocTable);
+};
+
+#endif
index 1ef43263f40abdae8a3f11daf77b0c21f49d7d9c..a1894001e694def50b1455874b06ddf7c73ec1db 100644 (file)
@@ -118,7 +118,7 @@ SET(PROJECT_LIBRARIES
     Config
     GeomAPI
 )
-SET(CMAKE_SWIG_FLAGS -threads -w325,321,362,383,302,403,473)
+SET(CMAKE_SWIG_FLAGS -threads -w325,321,362,383,302,403,451,473)
 ADD_DEFINITIONS(-DMODELAPI_EXPORTS)
 
 ADD_LIBRARY(ModelAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
index dc76645c858400c27b191d35e251c9fc336ff224..913b41b8bebc172ab07dbef5f135e83ab0ed2b4d 100644 (file)
@@ -36,6 +36,7 @@
 
 // import other modules
 %import "GeomAPI.i"
+%import "Events.i"
 
 // to avoid error on this
 #define MODELAPI_EXPORT
@@ -96,6 +97,7 @@
 %shared_ptr(ModelAPI_ResultField)
 %shared_ptr(ModelAPI_ResultParameter)
 %shared_ptr(ModelAPI_ResultCompSolid)
+%shared_ptr(ModelAPI_ObjectUpdatedMessage)
 
 %typecheck(SWIG_TYPECHECK_POINTER) const ModelAPI_AttributeTables::Value {
   $1 = (PyFloat_Check($input) || PyLong_Check($input) || PyUnicode_Check($input) || PyBool_Check($input)) ? 1 : 0;
 
 // all supported interfaces
 %include "ModelAPI_Entity.h"
+%include "ModelAPI_Events.h"
 %include "ModelAPI_Document.h"
 %include "ModelAPI_Session.h"
 %include "ModelAPI_Plugin.h"
 // std::set -> []
 %template(AttributeSet) std::set<std::shared_ptr<ModelAPI_Attribute> >;
 %template(FeatureSet) std::set<std::shared_ptr<ModelAPI_Feature> >;
+%template(ObjectSet) std::set<std::shared_ptr<ModelAPI_Object> >;
 
 // std::dynamic_pointer_cast
 template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
@@ -192,6 +196,8 @@ template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr
 %template(modelAPI_ResultGroup) shared_ptr_cast<ModelAPI_ResultGroup, ModelAPI_Result>;
 %template(modelAPI_ResultField) shared_ptr_cast<ModelAPI_ResultField, ModelAPI_Result>;
 
+%template(messageToUpdatedMessage) shared_ptr_cast<ModelAPI_ObjectUpdatedMessage, Events_Message>;
+
 // Attribute casts
 %template(modelAPI_AttributeDocRef)        shared_ptr_cast<ModelAPI_AttributeDocRef, ModelAPI_Attribute>;
 %template(modelAPI_AttributeDouble)        shared_ptr_cast<ModelAPI_AttributeDouble, ModelAPI_Attribute>;
index d0fd38c50a84dfc32a45b10039d34d1e3b4984d3..e77841875dce26527cf8dc59cff944b3b14f2675 100644 (file)
@@ -40,11 +40,13 @@ class ModelAPI_AttributeIntArray : public ModelAPI_Attribute
   MODELAPI_EXPORT virtual int size() = 0;
 
   /// Sets the new size of the array. The previous data is erased.
-  MODELAPI_EXPORT virtual void setSize(const int theSize) = 0;
+  MODELAPI_EXPORT virtual void setSize(const int theSize,
+                                       bool sendUpdated = true) = 0;
 
   /// Defines the value of the array by index [0; size-1]
   MODELAPI_EXPORT virtual void setValue(const int theIndex,
-                                         const int theValue) = 0;
+                                        const int theValue,
+                                        bool sendUpdated = true) = 0;
 
   /// Returns the value by the index
   MODELAPI_EXPORT virtual int value(const int theIndex) = 0;
index 9cc95bad2be1874f0205d34a714ba8fb5cea26ce..602c4e8033280f0b9eeba6ca31d78b677220f75e 100644 (file)
@@ -81,7 +81,8 @@ public:
 
   //! Moves the feature to make it after the given one in the history.
   virtual void moveFeature(std::shared_ptr<ModelAPI_Feature> theMoved,
-                           std::shared_ptr<ModelAPI_Feature> theAfterThis) = 0;
+                           std::shared_ptr<ModelAPI_Feature> theAfterThis,
+                           const bool theSplit = false) = 0;
 
   ///! Returns the id of the document
   virtual const int id() const = 0;
@@ -259,6 +260,23 @@ public:
   MODELAPI_EXPORT virtual std::shared_ptr<ModelAPI_Feature> nextFeature(
     std::shared_ptr<ModelAPI_Feature> theCurrent, const bool theReverse = false) const = 0;
 
+  /// Loads the OCAF document from the file into the current document.
+  /// All the features are added after the active feature.
+  /// \param theFileName name of the file to import
+  /// \param theImported list of features imported from the file
+  /// \param theCheckOnly verify the document does not contain unappropriate features
+  ///                     (useful for import to PartSet), but do not import it
+  /// \returns true if file was loaded successfully
+  MODELAPI_EXPORT virtual bool importPart(const char* theFileName,
+                                      std::list<std::shared_ptr<ModelAPI_Feature> >& theImported,
+                                      bool theCheckOnly = false) = 0;
+
+  /// Export the list of features to the file
+  /// \param theFilename path to save the file
+  /// \param theExportFeatures list of features to export
+  MODELAPI_EXPORT virtual bool save(const char* theFilename,
+    const std::list<std::shared_ptr<ModelAPI_Feature> >& theExportFeatures) const = 0;
+
 protected:
   //! Only for SWIG wrapping it is here
   MODELAPI_EXPORT ModelAPI_Document();
index 042c06a41d040c82902eb7c1d3bfda56037e454f..0b250ebd53e24493c8f0b4b93e42841d71b53aa4 100644 (file)
@@ -101,6 +101,15 @@ static const char * EVENT_STABILITY_CHANGED = "StabilityChanged";
 /// Event ID that the sketch is prepared and all grouped messages for the solver may be flushed
 static const char * EVENT_SKETCH_PREPARED = "SketchPrepared";
 
+/// Event ID that provides a request for list of non-fixed objects necessary for DoF = 0
+static const char * EVENT_GET_DOF_OBJECTS = "GetDoFObjects";
+
+/// Event ID that provides a request for list of non-fixed objects necessary for DoF = 0
+static const char * EVENT_DOF_OBJECTS = "DoFObjects";
+
+/// Event ID that requests updates visual attributes for presentations
+static const char * EVENT_VISUAL_ATTRIBUTES = "UpdateVisualAttributes";
+
 /// Message that feature was changed (used for Object Browser update): moved, updated and deleted
 class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup
 {
index c6b8a6f7257df6ba4933747cb038402399502a87..413f52c4ce616edd2c2e4cb49f84f0621dde2737 100644 (file)
@@ -29,6 +29,7 @@
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_AttributeDocRef.h>
 #include <ModelAPI_Validator.h>
+#include <ModelAPI_AttributeIntArray.h>
 #include <list>
 #include <map>
 #include <iostream>
@@ -784,4 +785,84 @@ void removeResults(const std::list<ResultPtr>& theResults)
   }
 }
 
+// used by GUI only
+// LCOV_EXCL_START
+double getDeflection(const std::shared_ptr<ModelAPI_Result>& theResult)
+{
+  double aDeflection = -1;
+  // get deflection from the attribute of the result
+  if (theResult.get() != NULL &&
+    theResult->data()->attribute(ModelAPI_Result::DEFLECTION_ID()).get() != NULL) {
+    AttributeDoublePtr aDoubleAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID());
+    if (aDoubleAttr.get() && aDoubleAttr->isInitialized()) {
+      double aValue = aDoubleAttr->value();
+      if (aValue > 0) /// zero value should not be used as a deflection(previous studies)
+        aDeflection = aDoubleAttr->value();
+    }
+  }
+  return aDeflection;
+}
+
+
+void getColor(const std::shared_ptr<ModelAPI_Result>& theResult, std::vector<int>& theColor)
+{
+  theColor.clear();
+  // get color from the attribute of the result
+  if (theResult.get() != NULL &&
+    theResult->data()->attribute(ModelAPI_Result::COLOR_ID()).get() != NULL) {
+    AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
+    if (aColorAttr.get() && aColorAttr->size()) {
+      theColor.push_back(aColorAttr->value(0));
+      theColor.push_back(aColorAttr->value(1));
+      theColor.push_back(aColorAttr->value(2));
+    }
+  }
+}
+
+double getTransparency(const std::shared_ptr<ModelAPI_Result>& theResult)
+{
+  double aTransparency = -1;
+  // get transparency from the attribute of the result
+  if (theResult.get() != NULL &&
+    theResult->data()->attribute(ModelAPI_Result::TRANSPARENCY_ID()).get() != NULL) {
+    AttributeDoublePtr aDoubleAttr = theResult->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
+    if (aDoubleAttr.get() && aDoubleAttr->isInitialized()) {
+      aTransparency = aDoubleAttr->value();
+    }
+  }
+  return aTransparency;
+}
+// LCOV_EXCL_STOP
+
+void copyVisualizationAttrs(
+  std::shared_ptr<ModelAPI_Result> theSource, std::shared_ptr<ModelAPI_Result> theDest)
+{
+  // color
+  AttributeIntArrayPtr aSourceColor = theSource->data()->intArray(ModelAPI_Result::COLOR_ID());
+  if (aSourceColor.get() && aSourceColor->isInitialized() && aSourceColor->size()) {
+    AttributeIntArrayPtr aDestColor = theDest->data()->intArray(ModelAPI_Result::COLOR_ID());
+    if (aDestColor.get()) {
+      aDestColor->setSize(aSourceColor->size());
+      for(int a = 0; a < aSourceColor->size(); a++)
+        aDestColor->setValue(a, aSourceColor->value(a));
+    }
+  }
+  // deflection
+  AttributeDoublePtr aSourceDefl = theSource->data()->real(ModelAPI_Result::DEFLECTION_ID());
+  if (aSourceDefl.get() && aSourceDefl->isInitialized()) {
+    AttributeDoublePtr aDestDefl = theDest->data()->real(ModelAPI_Result::DEFLECTION_ID());
+    if (aDestDefl.get()) {
+      aDestDefl->setValue(aSourceDefl->value());
+    }
+  }
+  // transparency
+  AttributeDoublePtr aSourceTransp = theSource->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
+  if (aSourceTransp.get() && aSourceTransp->isInitialized()) {
+    AttributeDoublePtr aDestTransp = theDest->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
+    if (aDestTransp.get()) {
+      aDestTransp->setValue(aSourceTransp->value());
+    }
+  }
+}
+
 } // namespace ModelAPI_Tools
index 6b4d31f8401cdd34a2c1e8403833400ab37e7f09..b0af5520bae730e1b3a1252f24df5a358bb42e70 100644 (file)
@@ -209,6 +209,33 @@ MODELAPI_EXPORT std::set<std::shared_ptr<ModelAPI_Feature> >
 /*! Creates a remove result features with the given results
 */
 MODELAPI_EXPORT void removeResults(const std::list<std::shared_ptr<ModelAPI_Result> >& theResults);
+
+/*! Returns current deflection in the given result
+* \param theResult a result object
+* \return a deflection value or -1 if it was not defined
+*/
+MODELAPI_EXPORT double getDeflection(const std::shared_ptr<ModelAPI_Result>& theResult);
+
+/*! Returns current color of the current result
+* \param[in] theResult a result object
+* \param[out] theColor a color values if it is defined
+*/
+MODELAPI_EXPORT void getColor(const std::shared_ptr<ModelAPI_Result>& theResult,
+  std::vector<int>& theColor);
+
+/*! Returns current transparency in the given result
+* \param theResult a result object
+* \return a transparency value or -1 if it was not defined
+*/
+MODELAPI_EXPORT double getTransparency(const std::shared_ptr<ModelAPI_Result>& theResult);
+
+/*! Copies all visualization attributes from one result to another.
+* \param theSource a result that contains the copied attributes
+* \param theDest a destination result that takes the visualization attributes
+*/
+MODELAPI_EXPORT void copyVisualizationAttrs(std::shared_ptr<ModelAPI_Result> theSource,
+                                            std::shared_ptr<ModelAPI_Result> theDest);
+
 }
 
 #endif
index 2187c2ae41cf1ca29cbb66a396da298566eec586..de4312c62408c486f42c0d6e4831818e82c0cfd0 100644 (file)
@@ -24,6 +24,7 @@
 
   #include "ModelAPI.h"
   #include "ModelAPI_Entity.h"
+  #include "ModelAPI_Events.h"
   #include "ModelAPI_Document.h"
   #include "ModelAPI_Session.h"
   #include "ModelAPI_Object.h"
index fc73000c04b2fb1753ed3a6e2dc68ef128244d02..2cf757443be12442821253fe138cfb1d0e9b11a4 100644 (file)
@@ -368,6 +368,8 @@ std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) {
     double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
     dumpArray(aResult, aValues, 3);
   } else if (aType == GeomDataAPI_Dir::typeId()) {
+    if (theAttr->id() == "DistanceDirection")
+      return "__notcase__";
     AttributeDirPtr anAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theAttr);
     double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
     dumpArray(aResult, aValues, 3);
index fe127695dd545764b0db4fc78ec1d351b1d8b041..b2f9cc08f83f0f00de4622a48963ecc44d5857a5 100644 (file)
@@ -55,7 +55,6 @@ SET(PROJECT_HEADERS
   ModuleBase_ListView.h
   ModuleBase_ModelWidget.h
   ModuleBase_Operation.h
-  ModuleBase_OperationAction.h
   ModuleBase_OperationDescription.h
   ModuleBase_OperationFeature.h
   ModuleBase_PageBase.h
@@ -108,6 +107,7 @@ SET(PROJECT_HEADERS
   ModuleBase_WidgetSelectionFilter.h
   ModuleBase_IStepPrs.h
   ModuleBase_SelectionFilterType.h
+  ModuleBase_WidgetUndoLabel.h
 )
 
 SET(PROJECT_MOC_HEADERS
@@ -124,7 +124,6 @@ SET(PROJECT_MOC_HEADERS
   ModuleBase_ModelDialogWidget.h
   ModuleBase_ModelWidget.h
   ModuleBase_Operation.h
-  ModuleBase_OperationAction.h
   ModuleBase_OperationFeature.h
   ModuleBase_PagedContainer.h
   ModuleBase_PageGroupBox.h
@@ -158,6 +157,7 @@ SET(PROJECT_MOC_HEADERS
   ModuleBase_WidgetRadiobox.h
   ModuleBase_WidgetPointInput.h
   ModuleBase_WidgetSelectionFilter.h
+  ModuleBase_WidgetUndoLabel.h
 )
 
 SET(PROJECT_SOURCES
@@ -180,7 +180,6 @@ SET(PROJECT_SOURCES
   ModuleBase_ListView.cpp
   ModuleBase_ModelWidget.cpp
   ModuleBase_Operation.cpp
-  ModuleBase_OperationAction.cpp
   ModuleBase_OperationDescription.cpp
   ModuleBase_OperationFeature.cpp
   ModuleBase_PageBase.cpp
@@ -228,10 +227,11 @@ SET(PROJECT_SOURCES
   ModuleBase_WidgetPointInput.cpp
   ModuleBase_WidgetSelectionFilter.cpp
   ModuleBase_IStepPrs.cpp
+  ModuleBase_WidgetUndoLabel.cpp
 )
 
 SET(TEXT_RESOURCES
-#    ModuleBase_msg_fr.ts
+    ModuleBase_msg_fr.ts
 )
 
 SET(PROJECT_LIBRARIES
@@ -258,10 +258,12 @@ IF (${UPDATE_TRANSLATION})
     QT5_CREATE_TRANSLATION(QM_RESOURCES
                            ${PROJECT_FILES}
                            ${TEXT_RESOURCES}
-                           OPTIONS -extensions cpp -no-recursive
+                           OPTIONS -extensions cpp -no-recursive -locations none
                           )
 ELSE(${UPDATE_TRANSLATION})
-    QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    IF(${MAKE_TRANSLATION})
+        QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    ENDIF(${MAKE_TRANSLATION})
 ENDIF(${UPDATE_TRANSLATION})
 
 SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES} ${QM_RESOURCES})
index 1c887faa49d28a30870458d79fff76f5d171c3bf..3404b55f282490d7571eca20368005f00d16a52f 100644 (file)
@@ -29,6 +29,9 @@
 #include <QRadioButton>
 #include <QToolButton>
 
+const QString AStyle = "QToolButton:checked {border: 1px solid black; background-color:#C0DCF3}";
+
+
 ModuleBase_ChoiceCtrl::ModuleBase_ChoiceCtrl(QWidget* theParent,
                                              const QStringList& theChoiceList,
                                              const QStringList& theIconsList,
@@ -68,6 +71,7 @@ ModuleBase_ChoiceCtrl::ModuleBase_ChoiceCtrl(QWidget* theParent,
           QPixmap aIcon = ModuleBase_IconFactory::loadPixmap(theIconsList.at(aId));
           aBtn->setIcon(aIcon);
           aBtn->setIconSize(aIcon.size());
+          aBtn->setStyleSheet(AStyle);
 
           aBtnLayout->addWidget(aBtn);
           myButtons->addButton(aBtn, aId++);
index 03abb8233950ce89c26d887b94dd8c5206dc5b36..f3314ca2a27a1c186a11c2d01a1f636ce6a3da29 100644 (file)
@@ -159,9 +159,9 @@ void ModuleBase_IModule::launchOperation(const QString& theCmdId,
   }
 }
 
-Handle(AIS_InteractiveObject) ModuleBase_IModule::createPresentation(const ObjectPtr& theResult)
+AISObjectPtr ModuleBase_IModule::createPresentation(const ObjectPtr& theResult)
 {
-  return Handle(AIS_InteractiveObject)();
+  return AISObjectPtr();
 }
 
 bool ModuleBase_IModule::canBeShaded(Handle(AIS_InteractiveObject) theAIS) const
@@ -186,13 +186,6 @@ ModuleBase_Operation* ModuleBase_IModule::getNewOperation(const std::string& the
   return new ModuleBase_OperationFeature(theFeatureId.c_str(), this);
 }
 
-bool ModuleBase_IModule::customizeObject(ObjectPtr theObject,
-                              const ModuleBase_IModule::ModuleBase_CustomizeFlag& theFlag,
-                              const bool theUpdateViewer)
-{
-  return false;
-}
-
 ModuleBase_Operation* ModuleBase_IModule::createOperation(const std::string& theFeatureId)
 {
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
index b748d6a148c2721b89fd659551cc38cf50f11c82..963070788e390a26d96e8c9f394b29aa97597dc2 100644 (file)
@@ -169,10 +169,11 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
 
   /// Have an opportunity to create widgets for the current operation
   /// instead of standard creation in workshop
-  /// \param theOperation a started operation
+  /// \param theFeature a feature of the started operation
+  /// \param theXmlRepr an XML representation of the operation
   /// \param theWidgets a list of created widgets
   /// \return boolean result, false by default
-  virtual bool createWidgets(ModuleBase_Operation* theOperation,
+  virtual bool createWidgets(const FeaturePtr& theFeature, const QString& theXmlRepr,
                              QList<ModuleBase_ModelWidget*>& theWidgets) const { return false; }
 
   //! Returns True if there are available Undos and there is not an active operation
@@ -277,14 +278,14 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
                                    const bool theUpdateViewer) {}
 
   /// Modifies the given presentation in the custom way.
-  virtual bool customisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
-                                     AISObjectPtr thePrs,
-                                     GeomCustomPrsPtr theCustomPrs) { return false; };
+  //virtual bool customisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
+  //                                   AISObjectPtr thePrs,
+  //                                   GeomCustomPrsPtr theCustomPrs) { return false; };
 
-  /// Modifies the given presentation in the custom way after usual customize is performed.
-  virtual bool afterCustomisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
-                                     AISObjectPtr thePrs,
-                                     GeomCustomPrsPtr theCustomPrs) { return false; };
+  ///// Modifies the given presentation in the custom way after usual customize is performed.
+  //virtual bool afterCustomisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
+  //                                   AISObjectPtr thePrs,
+  //                                   GeomCustomPrsPtr theCustomPrs) { return false; };
 
   /// Update the object presentable properties such as color, lines width and other
   /// If the object is result with the color attribute value set, it is used,
@@ -294,8 +295,10 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
   /// should be updated(e.g. only highlighted elements)
   /// \param theUpdateViewer the parameter whether the viewer should be update immediately
   /// \returns true if the object is modified
-  virtual bool customizeObject(ObjectPtr theObject, const ModuleBase_CustomizeFlag& theFlag,
-                               const bool theUpdateViewer);
+  virtual bool customizeFeature(ObjectPtr theObject, const ModuleBase_CustomizeFlag& theFlag,
+    const bool theUpdateViewer) {
+    return false;
+  }
 
   /// Disable displaying of custom mode
   /// \param theMode a mode to disable
@@ -312,10 +315,17 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
   /// \param theCmdId the operation name
   virtual ModuleBase_Operation* createOperation(const std::string& theCmdId);
 
-  /// Create specific for the module presentation
+  /// Create specific for the module presentation. The presentation has to be
+  /// customized accordingly to the object.
   /// \param theResult an object for presentation
   /// \return created presentation or NULL(default value)
-  virtual Handle(AIS_InteractiveObject) createPresentation(const ObjectPtr& theResult);
+  virtual AISObjectPtr createPresentation(const ObjectPtr& theResult);
+
+  /// Customize presentation according to objects attributes
+  /// \param theObject an object for presentation
+  /// \param thePrs a presentation object
+  virtual void customizePresentation(const ObjectPtr& theObject, const AISObjectPtr& thePrs) const
+  {}
 
   //! Returns data object by AIS
   virtual ObjectPtr findPresentedObject(const AISObjectPtr& theAIS) const = 0;
index df66658a7e0b9f5c5a0eafbeb45e87acaf630745..cd8b25c401d5ac5bf1537b5e3b4aed2fe1632f59 100644 (file)
@@ -78,3 +78,14 @@ ModuleBase_ModelWidget* ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget
   }
   return aFirstWidget;
 }
+
+bool ModuleBase_IPropertyPanel::isModified() const
+{
+  bool isModified = false;
+  QList<ModuleBase_ModelWidget*> aWidgets = modelWidgets();
+  foreach(ModuleBase_ModelWidget* aWgt, aWidgets) {
+    bool aRes = aWgt->isModified();
+    isModified |= aRes;
+  }
+  return isModified;
+}
index a4f954ea03ad8688b67556100c6d32cce1cff50c..16fdecf13b7a38ca9054e2e1e0c986bbf6f28346 100644 (file)
@@ -88,6 +88,9 @@ public:
   /// The method is called on accepting of operation
   virtual void onAcceptData() = 0;
 
+  /// Returns True if data of its feature was modified during operation
+  virtual bool isModified() const;
+
   /// Returns the first widget, where canAcceptFocus returns true
   /// \return a widget or null
   static ModuleBase_ModelWidget* findFirstAcceptingValueWidget(
index 56ca626301444da926d7014608a8bb3b5c1d50f6..466b06641d828f285841f64c3e189555e2c5d9cd 100644 (file)
@@ -152,6 +152,15 @@ Q_OBJECT
   //! \param theAIS the object which has to be activated
   virtual void applyCurrentSelectionModes(const AISObjectPtr& theAIS) = 0;
 
+  //! Undo last command
+  virtual void undo() = 0;
+
+  //! Set enabled state of cancel button in property panel
+  virtual void setCancelEnabled(bool toEnable) = 0;
+
+  //! Returns current state of cancel button
+  virtual bool isCancelEnabled() const = 0;
+
 signals:
   /// Signal selection changed.
   void selectionChanged();
index d9fe13d2c18339a17daaafebe041484adacb8e43..5fd8909eefb4374cf7f6a24549fe17f26668cc24 100644 (file)
@@ -77,6 +77,19 @@ void ModuleBase_ListView::getSelectedIndices(std::set<int>& theIndices)
   }
 }
 
+//********************************************************************
+void  ModuleBase_ListView::selectIndices(const std::set<int>& theIndices)
+{
+  myListControl->clearSelection();
+  for (int i = 0; i < myListControl->count(); i++) {
+    QListWidgetItem* anItem = myListControl->item(i);
+    int aId = anItem->data(ATTRIBUTE_SELECTION_INDEX_ROLE).toInt();
+    if (theIndices.find(aId) != theIndices.end()) {
+      anItem->setSelected(true);
+    }
+  }
+}
+
 //********************************************************************
 void ModuleBase_ListView::removeSelectedItems()
 {
index aa973845e1c4ce44c5058e03ed309a308182eead..aa0620e9045471dbac2eb42f2e0d66d69f2daded 100644 (file)
@@ -118,6 +118,10 @@ public:
   /// \param theIndices an output container for indices
   void getSelectedIndices(std::set<int>& theIndices);
 
+  /// Selects items with indices
+  /// \param theIndices indices
+  void selectIndices(const std::set<int>& theIndices);
+
   /// Removes selected items from the list widget
   void removeSelectedItems();
 
index 89546edfd4bacde2ac2f40b91a4258dbcef1a299..de9582a5f86b32eb7c960bfb775d0ba447c2aa7c 100644 (file)
 
 //**************************************************************
 ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
-                                               const Config_WidgetAPI* theData)
-    : QWidget(theParent),
-      myIsEditing(false),
-      myState(Stored),
-      myIsValueStateBlocked(false),
-      myFlushUpdateBlocked(false),
-      myWidgetValidator(0)
+  const Config_WidgetAPI* theData)
+  : QWidget(theParent),
+  myIsEditing(false),
+  myState(Stored),
+  myIsValueStateBlocked(false),
+  myFlushUpdateBlocked(false),
+  myWidgetValidator(0)
 {
 #ifdef DEBUG_WIDGET_INSTANCE
   qDebug("ModuleBase_ModelWidget::ModuleBase_ModelWidget");
@@ -68,6 +68,8 @@ ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
 
   myIsModifiedInEdit = theData->getProperty(ATTR_MODIFIED_IN_EDIT);
 
+  myUpdateVisualAttributes = theData->getBooleanAttribute(ATTR_VISUAL_CHANGED, false);
+
   myDefaultValue = theData->getProperty(ATTR_DEFAULT);
   myUseReset = theData->getBooleanAttribute(ATTR_USE_RESET, true);
   myIsComputedDefault = theData->getProperty(ATTR_DEFAULT) == DOUBLE_WDG_DEFAULT_COMPUTED;
@@ -423,6 +425,12 @@ bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
 //**************************************************************
 bool ModuleBase_ModelWidget::restoreValue()
 {
+  if (!isEnabled()) {
+    // This code works in inspection panel
+    ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
+    if (!aValidators->isCase(myFeature, attributeID()))
+      return false; // if it is not an active case for the widget
+  }
   emit beforeValuesRestored();
   bool isDone = restoreValueCustom();
   emit afterValuesRestored();
@@ -437,6 +445,10 @@ void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)
 #ifdef DEBUG_WIDGET_INSTANCE
     qDebug("ModuleBase_ModelWidget::updateObject");
 #endif
+    if (myFeature.get() && myUpdateVisualAttributes) {
+      static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
+      ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
+    }
     ModuleBase_Tools::flushUpdated(theObject);
     emit objectUpdated();
   }
index fdd467481bf79cf5439a99b6b28834b411f507f2..4060181c0d412c27e0e812e9dc8393c2b1168ec4 100644 (file)
@@ -303,6 +303,20 @@ Q_OBJECT
   /// By default this slot does nothing
   virtual void onFeatureAccepted() {}
 
+  /// Returns True in case if the widget contains useful information for inspection tool
+  virtual bool isInformative() const { return true; }
+
+  /// If widgets has several panels then this method has to show a page which contains information
+  /// for current feature. By default does nothing
+  virtual void showInformativePage() {}
+
+  /// Returns True if data of its attribute was modified
+  virtual bool isModified() const { return false; }
+
+  virtual void setReadOnly(bool isReadOnly) { setEnabled(!isReadOnly); }
+
+  virtual bool isReadOnly() const { return !isEnabled(); }
+
 signals:
   /// The signal about widget values are to be changed
   void beforeValuesChanged();
@@ -445,6 +459,8 @@ private:
   bool myIsValueStateBlocked;
   /// do not flush updated signal
   bool myFlushUpdateBlocked;
+
+  bool myUpdateVisualAttributes;
 };
 
 #endif
index b4f4a38b05296e9a20a94d30cabc41198ee4a188..81da1e47d898882b53af79b8c3b81823a346074e 100644 (file)
@@ -40,6 +40,8 @@
 #include <GeomAPI_Pnt2d.h>
 
 #include <Events_Loop.h>
+#include <Config_WidgetAPI.h>
+#include <Config_Keywords.h>
 
 #include <QTimer>
 
@@ -50,7 +52,8 @@
 ModuleBase_Operation::ModuleBase_Operation(const QString& theId, QObject* theParent)
     : QObject(theParent),
       myIsModified(false),
-      myPropertyPanel(NULL)
+      myPropertyPanel(NULL),
+  myHideFacesVisibilityState(false)
 {
   myDescription = new ModuleBase_OperationDescription(theId);
 }
@@ -176,3 +179,17 @@ bool ModuleBase_Operation::isGranted(QString theId) const
 {
   return myGrantedIds.contains(theId);
 }
+
+bool  ModuleBase_Operation::isModified() const
+{
+  if (myDescription->hasXmlRepresentation()) {
+    Config_WidgetAPI aWidgetApi(myDescription->xmlRepresentation().toStdString());
+    if (!aWidgetApi.getBooleanAttribute(ABORT_CONFIRMATION, true))
+      return false;
+  }
+  //if (myPropertyPanel)
+  //  return myPropertyPanel->isModified();
+  //return false;
+  // Most of operation causes creation of a feature
+  return true;
+}
index 845f6368608e555ef9890aa7b0fcba0ed7fda172..6ce75a83968fd4db49f5d5756f891aa7f9198dae 100644 (file)
@@ -80,10 +80,7 @@ Q_OBJECT
   virtual bool isGranted(QString theId) const;
 
   /// Returns True if data of its feature was modified during operation
-  virtual bool isModified() const { return myIsModified; }
-
-  /// Change the modified state of the operation
-  void setIsModified(const bool theIsModified) { myIsModified = theIsModified;  }
+  virtual bool isModified() const;
 
   /// Returns operations Id from it's description
   QString id() const;
@@ -105,6 +102,10 @@ Q_OBJECT
     myHelpFileName = theName;
   }
 
+  void setHideFacesVisible(bool isVisible) { myHideFacesVisibilityState = isVisible; }
+
+  bool isHideFacesVisible() const { return myHideFacesVisibilityState; }
+
 signals:
   /// The operation is started
   void beforeStarted();
@@ -209,6 +210,9 @@ private:
   ModuleBase_IPropertyPanel* myPropertyPanel;
 
   QString myHelpFileName;
+
+  /// Visibility state of HideFaces panel before the operation launch
+  bool myHideFacesVisibilityState;
 };
 
 #endif
diff --git a/src/ModuleBase/ModuleBase_OperationAction.cpp b/src/ModuleBase/ModuleBase_OperationAction.cpp
deleted file mode 100644 (file)
index c55c693..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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 "ModuleBase_OperationAction.h"
-
-ModuleBase_OperationAction::ModuleBase_OperationAction(const QString& theId, QObject* theParent)
- : ModuleBase_Operation(theId, theParent)
-{
-}
-
-ModuleBase_OperationAction::~ModuleBase_OperationAction()
-{
-}
-
-bool ModuleBase_OperationAction::commit()
-{
-  // the action is supposed to perform a single modification,
-  // so the operation returns modified state
-  setIsModified(true);
-
-  return ModuleBase_Operation::commit();
-}
diff --git a/src/ModuleBase/ModuleBase_OperationAction.h b/src/ModuleBase/ModuleBase_OperationAction.h
deleted file mode 100644 (file)
index 35b9acf..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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 ModuleBase_OperationAction_H
-#define ModuleBase_OperationAction_H
-
-#include <ModuleBase.h>
-
-#include <ModuleBase_Operation.h>
-
-/*!
- * \class ModuleBase_OperationAction
- * \ingroup GUI
- * \brief Base class for action operations
- *
- *  This is an action-like operation, which modifies the structure of data through
- *  starting/comitting transactions in the document. This operations are single stepped,
- *  and have no filled property panel, like Delete/Detach.
- */
-
-class MODULEBASE_EXPORT ModuleBase_OperationAction : public ModuleBase_Operation
-{
-Q_OBJECT
-
- public:
-  /// Constructor
-  /// \param theId the operation identifier
-  /// \param theParent the QObject parent
-  ModuleBase_OperationAction(const QString& theId = "", QObject* theParent = 0);
-  /// Destructor
-  virtual ~ModuleBase_OperationAction();
-
- public slots:
-  /// Commits the operation. Change is modified state to true value.
-  /// \return the result of commit
-  virtual bool commit();
-};
-
-#endif
index aa2d464fcb4fda8c66cf1f089b413a279ec4cdc2..98cbc74403f48ac321af785e2d41a49786e1d947 100644 (file)
@@ -175,22 +175,6 @@ FeaturePtr ModuleBase_OperationFeature::createFeature(const bool theFlushMessage
     std::shared_ptr<ModelAPI_Document> aDoc = ModelAPI_Session::get()->activeDocument();
     myFeature = aDoc->addFeature(getDescription()->operationId().toStdString());
   }
-  if (myFeature) {  // TODO: generate an error if feature was not created
-    setIsModified(true);
-    // Model update should call "execute" of a feature.
-    //myFeature->execute();
-    // Init default values
-    /*QList<ModuleBase_ModelWidget*> aWidgets = getDescription()->modelWidgets();
-     QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
-     for (; anIt != aLast; anIt++) {
-     (*anIt)->storeValue(aFeature);
-     }*/
-  }
-
-  //if (theFlushMessage) {
-  //  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
-  //  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
-  //}
   return myFeature;
 }
 
@@ -249,7 +233,6 @@ bool ModuleBase_OperationFeature::start()
 #ifdef DEBUG_OPERATION_START
   qDebug("ModuleBase_OperationFeature::start -- begin");
 #endif
-  setIsModified(false);
   QString anId = getDescription()->operationId();
   if (myIsEditing) {
     anId = anId.append(EditSuffix());
index e2d35c87b2a8111facc8ebd31d15db737b151aee..9bf101d3ffffb9612aa9310509d56485afcf38c0 100644 (file)
@@ -145,7 +145,7 @@ void ModuleBase_ResultPrs::setEdgesDefaultColor()
 
 
 //********************************************************************
-bool ModuleBase_ResultPrs::setSubShapeHidden(const NCollection_List<TopoDS_Shape>& theShapes)
+void ModuleBase_ResultPrs::setSubShapeHidden(const TopoDS_ListOfShape& theShapes)
 {
   bool isModified = false;
 
@@ -153,48 +153,16 @@ bool ModuleBase_ResultPrs::setSubShapeHidden(const NCollection_List<TopoDS_Shape
   BRep_Builder aBBuilder;
   aBBuilder.MakeCompound (aCompound);
 
-  TopoDS_Compound aShownComp;
-  if (myIsSubstituted)
-    aShownComp = TopoDS::Compound(Shape());
+  myHiddenSubShapes = theShapes;
+  collectSubShapes(aBBuilder, aCompound, myOriginalShape, myHiddenSubShapes);
+  myVisibleCompound = aCompound;
 
-  // restore hidden shapes if there are not the shapes in parameter container
-  NCollection_List<TopoDS_Shape> aVisibleSubShapes;
-  NCollection_List<TopoDS_Shape>::Iterator aHiddenIt(myHiddenSubShapes);
-  for (; aHiddenIt.More(); aHiddenIt.Next()) {
-    if (!theShapes.Contains(aHiddenIt.Value())) {
-      aVisibleSubShapes.Append(aHiddenIt.Value());
-    }
-    else {
-      aBBuilder.Add(aCompound, aHiddenIt.Value());
-      if (!aShownComp.IsNull())
-        aBBuilder.Remove(aShownComp, aHiddenIt.Value());
-    }
-  }
-  isModified = !aVisibleSubShapes.IsEmpty();
-  NCollection_List<TopoDS_Shape>::Iterator aVisibleIt(aVisibleSubShapes);
-  for (; aVisibleIt.More(); aVisibleIt.Next()) {
-    if (myHiddenSubShapes.Contains(aVisibleIt.Value())) {
-      myHiddenSubShapes.Remove(aVisibleIt.Value());
-      if (!aShownComp.IsNull())
-        aBBuilder.Add(aShownComp, aVisibleIt.Value());
-    }
-  }
-  // append hidden shapes into internal container if there are not these shapes
-  NCollection_List<TopoDS_Shape>::Iterator aShapeIt(theShapes);
-  for (; aShapeIt.More(); aShapeIt.Next()) {
-    if (aShapeIt.Value().ShapeType() != TopAbs_FACE) // only face shape can be hidden
-      continue;
-
-    if (!myHiddenSubShapes.Contains(aShapeIt.Value())) {
-      myHiddenSubShapes.Append(aShapeIt.Value());
-      aBBuilder.Add (aCompound, aShapeIt.Value());
-      if (!aShownComp.IsNull())
-        aBBuilder.Remove(aShownComp, aShapeIt.Value());
-      isModified = true;
-    }
+  aBBuilder.MakeCompound (aCompound);
+  TopoDS_ListOfShape::Iterator aIt(myHiddenSubShapes);
+  for (; aIt.More(); aIt.Next()) {
+    aBBuilder.Add(aCompound, aIt.Value());
   }
   myHiddenCompound = aCompound;
-  return isModified;
 }
 
 //********************************************************************
@@ -204,9 +172,8 @@ bool ModuleBase_ResultPrs::isSubShapeHidden(const TopoDS_Shape& theShape)
     return false;
 
   // orientation of parameter shape(come from selection) may be wrong, check isEqual() to be sure
-  for (NCollection_List<TopoDS_Shape>::Iterator aShapeIt(myHiddenSubShapes); aShapeIt.More();
-    aShapeIt.Next())
-  {
+  TopoDS_ListOfShape::Iterator aShapeIt(myHiddenSubShapes);
+  for (; aShapeIt.More(); aShapeIt.Next()) {
     if (theShape.IsSame(aShapeIt.Value()))
       return true;
   }
@@ -216,14 +183,15 @@ bool ModuleBase_ResultPrs::isSubShapeHidden(const TopoDS_Shape& theShape)
 
 //********************************************************************
 bool ModuleBase_ResultPrs::hasSubShapeVisible(
-  const NCollection_List<TopoDS_Shape>& theShapesToSkip)
+  const TopoDS_ListOfShape& theShapesToSkip)
 {
   TopoDS_Compound aCompound;
   BRep_Builder aBuilder;
   aBuilder.MakeCompound (aCompound);
-  NCollection_List<TopoDS_Shape> aShapesToSkip;
-  aShapesToSkip.Append(myHiddenSubShapes);
-  for (NCollection_List<TopoDS_Shape>::Iterator anIt(theShapesToSkip); anIt.More(); anIt.Next())
+  TopoDS_ListOfShape aShapesToSkip;
+  TopoDS_ListOfShape aHiddenCopy(myHiddenSubShapes);
+  aShapesToSkip.Append(aHiddenCopy);
+  for (TopoDS_ListOfShape::Iterator anIt(theShapesToSkip); anIt.More(); anIt.Next())
     aShapesToSkip.Append(anIt.Value());
 
   collectSubShapes(aBuilder, aCompound, myOriginalShape, aShapesToSkip);
@@ -258,17 +226,8 @@ void ModuleBase_ResultPrs::Compute(
       }
     }
     else { // convert shape into SHELL
-      TopoDS_Compound aCompound;
-      if (!myIsSubstituted) {
-        BRep_Builder aBuilder;
-        aBuilder.MakeCompound(aCompound);
-        collectSubShapes(aBuilder, aCompound, myOriginalShape, myHiddenSubShapes);
-      }
-      else {
-        aCompound = TopoDS::Compound(Shape());
-      }
-      bool isEmptyShape = BOPTools_AlgoTools3D::IsEmptyShape(aCompound);
-      Set(aCompound);
+      bool isEmptyShape = BOPTools_AlgoTools3D::IsEmptyShape(myVisibleCompound);
+      Set(myVisibleCompound);
       myIsSubstituted = true;
       if (isEmptyShape)
         aReadyToDisplay = false;
@@ -301,7 +260,7 @@ void ModuleBase_ResultPrs::Compute(
 //********************************************************************
 void ModuleBase_ResultPrs::collectSubShapes(BRep_Builder& theBuilder,
   TopoDS_Shape& theCompound, const TopoDS_Shape& theShape,
-  const NCollection_List<TopoDS_Shape>& theHiddenSubShapes)
+  const TopoDS_ListOfShape& theHiddenSubShapes)
 {
   switch (theShape.ShapeType()) {
     case TopAbs_COMPSOLID:
index 1868ad8dbb4c2ada4fe36872510f02f161f053f5..84500eba65dfff600d2f6cbad61b76defbefa624 100644 (file)
@@ -91,17 +91,21 @@ public:
   /// Visual state of the face is controlled by the second parameter
   /// \param theShapes a container of shape objects
   /// \returns true if the presentation is changed, or false (if for example it was hidden)
-  Standard_EXPORT bool setSubShapeHidden(const NCollection_List<TopoDS_Shape>& theShapes);
+  Standard_EXPORT void setSubShapeHidden(const TopoDS_ListOfShape& theShapes);
 
   /// Returns true if parameter shape has been hidden
   /// \param theShape sub-shape of the presentation shape
   /// \return boolean value
   Standard_EXPORT bool isSubShapeHidden(const TopoDS_Shape& theShape);
 
+  /// Returns hidden sub shapes list
+  Standard_EXPORT const TopoDS_ListOfShape& hiddenSubShapes() const
+  { return myHiddenSubShapes; }
+
   /// Returns true if there are no hidden sub shapes or original shape has at least one not hidden
   /// \param theShapesToSkip container of shape to be hidden in the presentation (faces)
   /// \return boolean value
-  Standard_EXPORT bool hasSubShapeVisible(const NCollection_List<TopoDS_Shape>& theShapesToSkip);
+  Standard_EXPORT bool hasSubShapeVisible(const TopoDS_ListOfShape& theShapesToSkip);
 
   /// Set transparency of hidden sub shapes: if value is 1, shapes are entirely hidden
   /// \param theTransparency transparency value
@@ -144,7 +148,7 @@ private:
   /// \param theShape the processed shape
   /// \param theHiddenSubShapes container of shapes to be skipped (faces)
   void collectSubShapes(BRep_Builder& theBuilder, TopoDS_Shape& theCompound,
-    const TopoDS_Shape& theShape, const NCollection_List<TopoDS_Shape>& theHiddenSubShapes);
+    const TopoDS_Shape& theShape, const TopoDS_ListOfShape& theHiddenSubShapes);
 
   void setEdgesDefaultColor();
 
@@ -158,7 +162,8 @@ private:
   bool myIsSubstituted;
 
   /// Container of original Shape sub shape to be hidden and not selectable
-  NCollection_List<TopoDS_Shape> myHiddenSubShapes;
+  TopoDS_ListOfShape myHiddenSubShapes;
+  TopoDS_Compound myVisibleCompound; /// compound of hidden sub shapes
   TopoDS_Compound myHiddenCompound; /// compound of hidden sub shapes
   double myTransparency; ///< transparency of hidden shapes, where 0 - there is no transparency
   Handle(AIS_ColoredDrawer) myHiddenSubShapesDrawer; ///< drawer for hidden sub shapes
index 8618e3b3488e2487506a0938af04b54bc3338fd8..ab6296671ade2a08b59f768d71b71c3bf510a9e1 100644 (file)
@@ -28,6 +28,9 @@
 
 #include <ModuleBase_PagedContainer.h>
 
+const QString AStyle = "QToolButton:checked {border: 1px solid black; background-color:#C0DCF3}";
+
+
 ModuleBase_ToolBox::ModuleBase_ToolBox(QWidget* theParent, const bool theUseFrameStyleBox)
 : QFrame(theParent)
 {
@@ -71,6 +74,7 @@ void ModuleBase_ToolBox::addItem(QWidget* thePage, const QString& theName, const
   QToolButton* aButton = new QToolButton(myButtonsFrame);
   aButton->setFocusPolicy(Qt::StrongFocus);
   aButton->setCheckable(true);
+  aButton->setStyleSheet(AStyle);
   if (theIcon.isNull())
     aButton->setText(theName);
   else {
index 5055c0275ee8744e3b81c49f44a2f45524461a5c..bae232f486e72a37e9ea4b87b7f53d1e63f12935 100644 (file)
@@ -257,7 +257,7 @@ void setSpinValue(QDoubleSpinBox* theSpin, double theValue)
 
 void setSpinValue(ModuleBase_ParamSpinBox* theSpin, double theValue)
 {
-  if (fabs(theSpin->value() - theValue) < tolerance)
+  if (!theSpin->text().isEmpty() && fabs(theSpin->value() - theValue) < tolerance)
     return;
   bool isBlocked = theSpin->blockSignals(true);
   theSpin->setValue(theValue);
@@ -763,6 +763,7 @@ void flushUpdated(ObjectPtr theObject)
   // (for the sketch result) to start processing of the sketch in the solver.
   // TODO: these flushes should be moved in a separate method provided by Model
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES));
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
 
index 4b0e41daa5be7e11d1c94dbcd10b85f36eee2b1b..c07a5f4b1d3cae63aeb73ab3a83149f2f7e8b95c 100644 (file)
@@ -195,18 +195,6 @@ bool ModuleBase_WidgetDoubleValue::restoreValueCustom()
   std::string aTextRepr = aRef->text();
   if (!aTextRepr.empty()) {
     QString aText = QString::fromStdString(aTextRepr);
-    //if (aText.endsWith('=')) {
-    //  if (!myParameter.get()) {
-    //    QString aName = aText.left(aText.indexOf('=')).trimmed();
-    //    myParameter = ModuleBase_Tools::findParameter(aName);
-    //  }
-    //  /// If myParameter is empty then it was not created because of an error
-    //  if (!myParameter.get())
-    //    return false;
-
-    //  AttributeStringPtr aExprAttr = myParameter->string("expression");
-    //  aText += aExprAttr->value().c_str();
-    //}
     ModuleBase_Tools::setSpinText(mySpinBox, aText);
   }
   else {
@@ -242,3 +230,18 @@ bool ModuleBase_WidgetDoubleValue::processEnter()
   }
   return isModified;
 }
+
+bool ModuleBase_WidgetDoubleValue::isModified() const
+{
+  QString aText = mySpinBox->text();
+  if (aText.isEmpty())
+    return false;
+
+  if (myHasDefault) {
+    bool aOk = false;
+    double aVal = aText.toDouble(&aOk);
+    if (!aOk || aVal == myDefaultVal)
+      return false;
+  }
+  return true;
+}
\ No newline at end of file
index 4854ffe7a89934b68c714eb7b2f5c9bbacd3eb71..db658ac8b2f2a2fc577335e80f0331b7d5c47bb5 100644 (file)
@@ -58,6 +58,9 @@ Q_OBJECT
   /// \return a control list
   virtual QList<QWidget*> getControls() const;
 
+  /// Returns True if data of its feature was modified during operation
+  virtual bool isModified() const;
+
  public slots:
  // Delayed value chnged: when user starts typing something,
  // it gives him a 0,5 second to finish typing, when sends valueChnaged() signal
index 0cc45bf0947f676388cd9fb748f86c0286a6169e..7f51a61a7cebe597e8b0cb4c1b41f1636c814238 100644 (file)
@@ -40,6 +40,7 @@
 #include <ModuleBase_WidgetMultiSelector.h>
 #include <ModuleBase_WidgetConcealedObjects.h>
 #include <ModuleBase_WidgetLabel.h>
+#include <ModuleBase_WidgetUndoLabel.h>
 #include <ModuleBase_WidgetToolbox.h>
 #include <ModuleBase_WidgetRadiobox.h>
 #include <ModuleBase_PageBase.h>
@@ -303,6 +304,8 @@ ModuleBase_ModelWidget* ModuleBase_WidgetFactory::createWidgetByType(const std::
     result = new ModuleBase_WidgetLabel(theParent, myWidgetApi);
   } else if (theType == WDG_DOUBLEVALUE) {
     result = new ModuleBase_WidgetDoubleValue(theParent, myWidgetApi);
+  } else if (theType == WDG_UNDOLABEL) {
+    result = new ModuleBase_WidgetUndoLabel(theParent, myWorkshop, myWidgetApi);
   } else if (theType == WDG_DOUBLEVALUELABEL) {
     result = new ModuleBase_WidgetLabelValue(theParent, myWidgetApi);
   } else if (theType == WDG_INTEGERVALUE) {
index 0e131bb1dc8dda8766947714177e795ea9a01e38..25bee53c85eab9488cf97a00f375db621d342d29 100644 (file)
@@ -230,3 +230,18 @@ bool ModuleBase_WidgetIntValue::processEnter()
   }
   return isModified;
 }
+
+bool ModuleBase_WidgetIntValue::isModified() const
+{
+  QString aText = mySpinBox->text();
+  if (aText.isEmpty())
+    return false;
+
+  if (myHasDefault) {
+    bool aOk = false;
+    int aVal = aText.toInt(&aOk);
+    if (!aOk || aVal == myDefVal)
+      return false;
+  }
+  return true;
+}
\ No newline at end of file
index 7fb7d13f487663b4c6f369ca6c3bd024e4ff33d6..955e3aa973fd7fabc19bf3b0e5569783e0e3fdef 100644 (file)
@@ -58,6 +58,9 @@ Q_OBJECT
   /// \return a control list
   virtual QList<QWidget*> getControls() const;
 
+  /// Returns True if data of its feature was modified during operation
+  virtual bool isModified() const;
+
 protected:
   /// Returns true if the event is processed.
   virtual bool processEnter();
index b717bf1039c7c0dadc958836b56836424e9db179..135d006a3805539ed3403468de543f91c4ddd9b6 100644 (file)
@@ -37,6 +37,8 @@ ModuleBase_WidgetLabel::ModuleBase_WidgetLabel(QWidget* theParent,
 : ModuleBase_ModelWidget(theParent, theData)
 {
   QString aText = translate(theData->getProperty("title"));
+  bool aIsHtml = theData->getBooleanAttribute(ATTR_HTML_STYLE, false);
+
   QString aLabelIcon = QString::fromStdString(theData->getProperty("icon"));
   myLabel = new QLabel(aText, theParent);
   if (!aLabelIcon.isEmpty()) {
@@ -48,13 +50,15 @@ ModuleBase_WidgetLabel::ModuleBase_WidgetLabel(QWidget* theParent,
   myLabel->setWordWrap(true);
   myLabel->setIndent(5);
   myLabel->setContentsMargins(0,0,0,4);
+  if (aIsHtml)
+    myLabel->setTextFormat(Qt::RichText);
 
   QVBoxLayout* aLayout = new QVBoxLayout(this);
   ModuleBase_Tools::zeroMargins(aLayout);
   aLayout->addWidget(myLabel);
   setLayout(aLayout);
 
-  std::string aStyleSheet = theData->getProperty(ATTR_STYLE_SHEET).c_str();
+  std::string aStyleSheet = theData->getProperty(ATTR_STYLE_SHEET);
   if (!aStyleSheet.empty())
     myLabel->setStyleSheet(QString("QLabel {%1}").arg(aStyleSheet.c_str()));
 }
index e915477ed7948f52023ec495ecf4cefc000e2f11..f5429cc3f24228d888ce7c8a5dd15178b2295f12 100644 (file)
@@ -160,3 +160,8 @@ bool ModuleBase_WidgetLineEdit::processEnter()
   }
   return isModified;
 }
+
+bool ModuleBase_WidgetLineEdit::isModified() const
+{
+  return !myLineEdit->text().isEmpty();
+}
\ No newline at end of file
index 05d6b1ed577d76469d61f67f42e0d4b29e27776c..c1622c4aa53ddbdadbfc900aef0755541d53ec10 100644 (file)
@@ -51,6 +51,9 @@ class MODULEBASE_EXPORT ModuleBase_WidgetLineEdit : public ModuleBase_ModelWidge
   /// Redefinition of virtual method
   virtual QList<QWidget*> getControls() const;
 
+  /// Returns True if data of its feature was modified during operation
+  virtual bool isModified() const;
+
 protected:
   /// Returns true if the event is processed.
   virtual bool processEnter();
index 337aa8acf4a4e246ccb969bfc5470dd4057de76f..33f14a17ec64014ab79ecf2543b408320d7690da 100644 (file)
@@ -114,7 +114,7 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
                                                                const Config_WidgetAPI* theData)
 : ModuleBase_WidgetSelector(theParent, theWorkshop, theData),
   myIsSetSelectionBlocked(false), myCurrentHistoryIndex(-1),
-  myIsFirst(true), myFiltersWgt(0)
+  myIsFirst(true), myFiltersWgt(0), myShowOnlyBtn(0)
 {
   std::string aPropertyTypes = theData->getProperty("shape_types");
   QString aTypesStr = aPropertyTypes.c_str();
@@ -125,8 +125,8 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
   if (!aAllowedList.isEmpty())
     myAllowedObjects = aAllowedList.split(' ', QString::SkipEmptyParts);
 
-  QVBoxLayout* aMainLay = new QVBoxLayout(this);
-  ModuleBase_Tools::adjustMargins(aMainLay);
+  myMainLayout = new QVBoxLayout(this);
+  ModuleBase_Tools::adjustMargins(myMainLayout);
 
   QStringList aIconsList = getIconsList(myShapeTypes);
   myTypeCtrl = new ModuleBase_ChoiceCtrl(this, myShapeTypes, aIconsList);
@@ -135,7 +135,7 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
     myTypeCtrl->setValue(0);
     myDefMode = myShapeTypes.first().toStdString();
   }
-  aMainLay->addWidget(myTypeCtrl);
+  myMainLayout->addWidget(myTypeCtrl);
 
   // There is no sense to parameterize list of types while we can not parameterize selection mode
   // if the xml definition contains one type, the controls to select a type should not be shown
@@ -148,7 +148,7 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
     QWidget* aLabelWgt = new QWidget(this);
     QHBoxLayout* aLabelLayout = new QHBoxLayout(aLabelWgt);
     aLabelLayout->setContentsMargins(0, 0, 0, 0);
-    aMainLay->addWidget(aLabelWgt);
+    myMainLayout->addWidget(aLabelWgt);
 
     QLabel* aListLabel = new QLabel(aLabelText, this);
     aLabelLayout->addWidget(aListLabel);
@@ -172,32 +172,32 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
   connect(myListView, SIGNAL(deleteActionClicked()), SLOT(onDeleteItem()));
   connect(myListView, SIGNAL(listActivated()), SLOT(onListActivated()));
 
-  aMainLay->addWidget(myListView->getControl());
+  myMainLayout->addWidget(myListView->getControl());
   connect(myTypeCtrl, SIGNAL(valueChanged(int)), this, SLOT(onSelectionTypeChanged()));
 
-  std::string aUseFilters = theData->getProperty("use_filters");
-  if (aUseFilters.length() > 0) {
+  myUseFilters = theData->getProperty("use_filters");
+  if (myUseFilters.length() > 0) {
     QWidget* aFltrWgt = new QWidget(this);
     QHBoxLayout* aFltrLayout = new QHBoxLayout(aFltrWgt);
 
-    myFiltersWgt = new ModuleBase_FilterStarter(aUseFilters.c_str(), aFltrWgt, theWorkshop);
+    myFiltersWgt = new ModuleBase_FilterStarter(myUseFilters, aFltrWgt, theWorkshop);
     aFltrLayout->addWidget(myFiltersWgt);
 
     aFltrLayout->addStretch();
 
-    QPushButton* aShowBtn = new QPushButton(tr("Show only"), aFltrWgt);
-    aShowBtn->setCheckable(true);
-    aShowBtn->setChecked(false);
-    connect(aShowBtn, SIGNAL(toggled(bool)), SLOT(onShowOnly(bool)));
-    aFltrLayout->addWidget(aShowBtn);
+    myShowOnlyBtn = new QPushButton(tr("Show only"), aFltrWgt);
+    myShowOnlyBtn->setCheckable(true);
+    myShowOnlyBtn->setChecked(false);
+    connect(myShowOnlyBtn, SIGNAL(toggled(bool)), SLOT(onShowOnly(bool)));
+    aFltrLayout->addWidget(myShowOnlyBtn);
 
-    aMainLay->addWidget(aFltrWgt);
+    myMainLayout->addWidget(aFltrWgt);
   }
 
   bool aSameTop = theData->getBooleanAttribute("same_topology", false);
   if (aSameTop) {
     myGeomCheck = new QCheckBox(tr("Add elements that share the same topology"), this);
-    aMainLay->addWidget(myGeomCheck);
+    myMainLayout->addWidget(myGeomCheck);
     connect(myGeomCheck, SIGNAL(toggled(bool)), SLOT(onSameTopology(bool)));
   }
   else
@@ -411,7 +411,7 @@ bool ModuleBase_WidgetMultiSelector::setSelection(QList<ModuleBase_ViewerPrsPtr>
     theValues.append(anInvalidValues);
 
   if (isDone) // may be the feature's result is not displayed, but attributes should be
-    myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
+    myWorkshop->module()->customizeFeature(myFeature, ModuleBase_IModule::CustomizeArguments,
                              true);/// hope that something is redisplayed by object updated
 
   return isDone;
@@ -555,7 +555,7 @@ bool ModuleBase_WidgetMultiSelector::processDelete()
     myWorkshop->setSelected(getAttributeSelection());
 
     // may be the feature's result is not displayed, but attributes should be
-    myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
+    myWorkshop->module()->customizeFeature(myFeature, ModuleBase_IModule::CustomizeArguments,
                               true); /// hope that something is redisplayed by object updated
   }
 
@@ -618,7 +618,7 @@ void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
   restoreValue();
   myWorkshop->setSelected(getAttributeSelection());
   // may be the feature's result is not displayed, but attributes should be
-  myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
+  myWorkshop->module()->customizeFeature(myFeature, ModuleBase_IModule::CustomizeArguments,
                             true); /// hope that something is redisplayed by object updated
   // clear history should follow after set selected to do not increase history by setSelected
   clearSelectedHistory();
@@ -855,8 +855,8 @@ void ModuleBase_WidgetMultiSelector::onDeleteItem()
 //********************************************************************
 void ModuleBase_WidgetMultiSelector::onListSelection()
 {
-  myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects,
-                                        true);
+  myWorkshop->module()->customizeFeature(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects,
+                                         true);
 }
 
 //********************************************************************
@@ -1179,4 +1179,40 @@ void ModuleBase_WidgetMultiSelector::onShowOnly(bool theChecked)
     myVisibleObjects.clear();
   } else
     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+  myWorkshop->viewer()->update();
+}
+
+bool ModuleBase_WidgetMultiSelector::isModified() const
+{
+  return myListView->getControl()->count() > 0;
+}
+
+
+void ModuleBase_WidgetMultiSelector::setReadOnly(bool isReadOnly)
+{
+  ModuleBase_WidgetSelector::setReadOnly(isReadOnly);
+  if (myShowOnlyBtn)
+    myShowOnlyBtn->hide();
+  if (myFiltersWgt) {
+    myFiltersWgt->hide();
+
+    AttributeSelectionListPtr aAttrList = feature()->selectionList(attributeID());
+    if (aAttrList.get()) {
+      FiltersFeaturePtr aFilters = aAttrList->filters();
+      if (aFilters.get()) {
+        ModuleBase_WidgetSelectionFilter::SelectorFeature = feature();
+        ModuleBase_WidgetSelectionFilter::AttributeId = attributeID();
+
+        std::string aXmlCfg, aDescription;
+        myWorkshop->module()->getXMLRepresentation(myUseFilters, aXmlCfg, aDescription);
+
+        ModuleBase_WidgetSelectionFilter* aWgt =
+          new ModuleBase_WidgetSelectionFilter(this, myWorkshop,
+            new Config_WidgetAPI(aDescription), true);
+        aWgt->setFeature(aFilters);
+        aWgt->restoreValue();
+        myMainLayout->addWidget(aWgt);
+      }
+    }
+  }
 }
index f34e18ef568e40ffacf0ad776ebf6a952e3d7111..d54f557d57b4939180f51b2f1c0a186c332124ef 100644 (file)
@@ -37,7 +37,8 @@
 
 class QWidget;
 class QCheckBox;
-//class QComboBox;
+class QPushButton;
+class QVBoxLayout;
 class ModuleBase_ListView;
 class ModuleBase_IWorkshop;
 class ModuleBase_ChoiceCtrl;
@@ -115,6 +116,11 @@ class MODULEBASE_EXPORT ModuleBase_WidgetMultiSelector : public ModuleBase_Widge
   /// The slot is called when user press Ok or OkPlus buttons in the parent property panel
   virtual void onFeatureAccepted();
 
+  /// Returns True if data of its feature was modified during operation
+  virtual bool isModified() const;
+
+  virtual void setReadOnly(bool isReadOnly);
+
 public slots:
   /// Slot is called on selection type changed
   void onSelectionTypeChanged();
@@ -253,12 +259,15 @@ protected:
   bool myIsFirst;
   std::string myDefMode;
 
+  QVBoxLayout* myMainLayout;
   QCheckBox* myGeomCheck;
   ModuleBase_FilterStarter* myFiltersWgt;
+  QPushButton* myShowOnlyBtn;
 
   QObjectPtrList myVisibleObjects;
   QStringList myAllowedObjects;
   QStringList myTmpAllowed;
+  std::string myUseFilters;
 };
 
 #endif /* MODULEBASE_WIDGETFILESELECTOR_H_ */
index 963861a31497f2ef726b5a7687481994844ee032..500bd5b68ff21f3737233b55515e9469d0c6038f 100644 (file)
@@ -55,8 +55,8 @@
 #include <QCheckBox>
 #include <QDir>
 
-static FeaturePtr SelectorFeature;
-static std::string AttributeId;
+FeaturePtr ModuleBase_WidgetSelectionFilter::SelectorFeature;
+std::string ModuleBase_WidgetSelectionFilter::AttributeId;
 
 
 GeomAPI_Shape::ShapeType selectionType(const QString& theType)
@@ -118,14 +118,16 @@ void ModuleBase_FilterStarter::onFiltersLaunch()
   }
   if (!aSelector)
     return;
-  SelectorFeature = aSelector->feature();
-  AttributeId = aSelector->attributeID();
+  ModuleBase_WidgetSelectionFilter::SelectorFeature = aSelector->feature();
+  ModuleBase_WidgetSelectionFilter::AttributeId = aSelector->attributeID();
 
   // Launch Filters operation
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
     (myWorkshop->module()->createOperation(myFeatureName));
 
-  AttributeSelectionListPtr aAttrList = SelectorFeature->selectionList(AttributeId);
+  AttributeSelectionListPtr aAttrList =
+    ModuleBase_WidgetSelectionFilter::SelectorFeature->selectionList(
+      ModuleBase_WidgetSelectionFilter::AttributeId);
   FiltersFeaturePtr aFilters = aAttrList->filters();
   if (aFilters.get())
     aFOperation->setFeature(aFilters);
@@ -225,16 +227,18 @@ void ModuleBase_FilterItem::onDelete()
 //*****************************************************************************
 //*****************************************************************************
 ModuleBase_WidgetSelectionFilter::ModuleBase_WidgetSelectionFilter(QWidget* theParent,
-  ModuleBase_IWorkshop* theWorkshop, const Config_WidgetAPI* theData)
+  ModuleBase_IWorkshop* theWorkshop, const Config_WidgetAPI* theData, bool theReadOnly)
   : ModuleBase_ModelWidget(theParent, theData),
   myWorkshop(theWorkshop),
-  mySelectorFeature(SelectorFeature),
-  mySelectorAttribute(AttributeId)
+  mySelectorFeature(ModuleBase_WidgetSelectionFilter::SelectorFeature),
+  mySelectorAttribute(ModuleBase_WidgetSelectionFilter::AttributeId)
 {
   // Clear Old selection
-  AttributeSelectionListPtr aAttrList = mySelectorFeature->selectionList(mySelectorAttribute);
-  mySelectionType = selectionType(aAttrList->selectionType().c_str());
-  aAttrList->clear();
+    AttributeSelectionListPtr aAttrList = mySelectorFeature->selectionList(mySelectorAttribute);
+    mySelectionType = selectionType(aAttrList->selectionType().c_str());
+  if (!theReadOnly) {
+    aAttrList->clear();
+  }
 
   // Define widgets
   QVBoxLayout* aMainLayout = new QVBoxLayout(this);
@@ -300,6 +304,12 @@ ModuleBase_WidgetSelectionFilter::ModuleBase_WidgetSelectionFilter(QWidget* theP
   aMainLayout->addStretch(1);
 
   updateSelectBtn();
+  if (theReadOnly) {
+    myFiltersCombo->hide();
+    mySelectBtn->hide();
+    aLblWgt->hide();
+    myShowBtn->hide();
+  }
 }
 
 ModuleBase_WidgetSelectionFilter::~ModuleBase_WidgetSelectionFilter()
@@ -645,28 +655,28 @@ bool ModuleBase_WidgetSelectionFilter::restoreValueCustom()
 {
   ModelAPI_FiltersFactory* aFactory = ModelAPI_Session::get()->filters();
   FiltersFeaturePtr aFiltersFeature = std::dynamic_pointer_cast<ModelAPI_FiltersFeature>(myFeature);
+
+  // Init filters member of the parent attribute
+  AttributeSelectionListPtr aAttrList = mySelectorFeature->selectionList(mySelectorAttribute);
+  if (aAttrList->filters() != aFiltersFeature) {
+    aAttrList->setFilters(aFiltersFeature);
+  }
+
   std::list<std::string> aFilters = aFiltersFeature->filters();
   std::list<std::string>::const_iterator aIt;
   for (aIt = aFilters.cbegin(); aIt != aFilters.cend(); aIt++) {
     std::string aStr = (*aIt);
-    onAddFilter(aStr);
+    ModuleBase_FilterItem* aItem = onAddFilter(aStr);
     FilterPtr aFilterObj = aFactory->filter(aStr);
     int aId = myFiltersCombo->findText(aFilterObj->name().c_str());
     if (aId != -1)
       myFiltersCombo->removeItem(aId);
-  }
-  // Init filters member of the parent attribute
-  AttributeSelectionListPtr aAttrList = mySelectorFeature->selectionList(mySelectorAttribute);
-  if (aAttrList->filters() != aFiltersFeature) {
-    aAttrList->setFilters(aFiltersFeature);
-  }
 
-  QList<QWidget*> aWidgets;
-  QList<ModuleBase_FilterItem*> aItems = myFiltersLayout->findChildren<ModuleBase_FilterItem*>();
-  foreach(ModuleBase_FilterItem* aItem, aItems) {
-    QList<ModuleBase_ModelWidget*> aSubList = aItem->widgets();
-    foreach(ModuleBase_ModelWidget* aWgt, aSubList) {
-      aWgt->restoreValue();
+    if (aItem) {
+      QList<ModuleBase_ModelWidget*> aSubList = aItem->widgets();
+      foreach(ModuleBase_ModelWidget* aWgt, aSubList) {
+        aWgt->restoreValue();
+      }
     }
   }
   return true;
index 30eb1b342c6040ffb2571c3343816f1802c1d5b6..4862581b89559f93174489232afa4137d16117e0 100644 (file)
@@ -139,13 +139,16 @@ class ModuleBase_WidgetSelectionFilter : public ModuleBase_ModelWidget
 {
   Q_OBJECT
 public:
+  static FeaturePtr SelectorFeature;
+  static std::string AttributeId;
+
 
   /// Constructor
   /// \param theParent the parent object
   /// \param theData the widget configuration. The attribute of the model widget is obtained from
   /// a low-level API for reading xml definitions of widgets
   ModuleBase_WidgetSelectionFilter(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
-    const Config_WidgetAPI* theData);
+    const Config_WidgetAPI* theData, bool theReadOnly = false);
 
   /// Destructor
   ~ModuleBase_WidgetSelectionFilter();
index c8d37d5d3ad3678481d40d680f07996d394746e6..127c7621e4f846c5ca09a4a4b6ff784c702d133e 100644 (file)
@@ -238,3 +238,9 @@ void ModuleBase_WidgetShapeSelector::updateSelectionName()
     }
   }
 }
+
+//********************************************************************
+bool ModuleBase_WidgetShapeSelector::isModified() const
+{
+  return !myTextLine->text().isEmpty();
+}
\ No newline at end of file
index 61b51810d7195af48e38ede379e287e989658e27..916259660ec8d89f567c95dcc3cc55d064363cbc 100644 (file)
@@ -94,6 +94,9 @@ Q_OBJECT
   /// \return a control list
   virtual QList<QWidget*> getControls() const;
 
+  /// Returns True if data of its feature was modified during operation
+  virtual bool isModified() const;
+
  protected:
   /// Saves the internal parameters to the given feature
   /// \return True in success
diff --git a/src/ModuleBase/ModuleBase_WidgetUndoLabel.cpp b/src/ModuleBase/ModuleBase_WidgetUndoLabel.cpp
new file mode 100644 (file)
index 0000000..3f5a35b
--- /dev/null
@@ -0,0 +1,54 @@
+// 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 "ModuleBase_WidgetUndoLabel.h"
+#include "ModuleBase_IWorkshop.h"
+
+#include <QPushButton>
+#include <QLayout>
+#include <QString>
+#include <QLabel>
+
+ModuleBase_WidgetUndoLabel::ModuleBase_WidgetUndoLabel(QWidget* theParent,
+  ModuleBase_IWorkshop* theWorkshop,
+  const Config_WidgetAPI* theData)
+  : ModuleBase_WidgetLabel(theParent, theData),
+  myWorkshop(theWorkshop)
+{
+  myUndoBtn = new QPushButton(tr("Undo"), this);
+  myUndoBtn->hide();
+  layout()->addWidget(myUndoBtn);
+  connect(myUndoBtn, SIGNAL(clicked(bool)), SLOT(onUndo()));
+}
+
+
+bool ModuleBase_WidgetUndoLabel::restoreValueCustom()
+{
+  bool aRes = ModuleBase_WidgetLabel::restoreValueCustom();
+  bool aError = myLabel->text().length() > 0;
+  myUndoBtn->setVisible(aError);
+  myWorkshop->setCancelEnabled(!aError);
+  return aRes;
+}
+
+
+void ModuleBase_WidgetUndoLabel::onUndo()
+{
+  myWorkshop->undo();
+}
\ No newline at end of file
diff --git a/src/ModuleBase/ModuleBase_WidgetUndoLabel.h b/src/ModuleBase/ModuleBase_WidgetUndoLabel.h
new file mode 100644 (file)
index 0000000..efa46ee
--- /dev/null
@@ -0,0 +1,55 @@
+// 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 ModuleBase_WidgetUndoLabel_H
+#define ModuleBase_WidgetUndoLabel_H
+
+#include "ModuleBase.h"
+#include "ModuleBase_WidgetLabel.h"
+
+class QPushButton;
+class ModuleBase_IWorkshop;
+
+/**
+* \ingroup GUI
+* Implementation of model widget for a label control
+*/
+class MODULEBASE_EXPORT ModuleBase_WidgetUndoLabel : public ModuleBase_WidgetLabel
+{
+  Q_OBJECT
+public:
+  /// Constructor
+  /// \param theParent the parent object
+  /// \param theData the widget configuation. The attribute of the model widget is obtained from
+  ModuleBase_WidgetUndoLabel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+    const Config_WidgetAPI* theData);
+
+  virtual ~ModuleBase_WidgetUndoLabel() {}
+
+  virtual bool restoreValueCustom();
+
+private slots:
+  void onUndo();
+
+private:
+  ModuleBase_IWorkshop* myWorkshop;
+  QPushButton* myUndoBtn;
+};
+
+#endif
\ No newline at end of file
index bd9cdbd76b9a019995b20b451caf0bcbdcfa4767..1536c3066d273a678bbfeaf32187cff23e7a088b 100644 (file)
@@ -32,7 +32,6 @@
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_AttributeValidator.h>
 #include <ModelAPI_Events.h>
-#include <ModelAPI_ResultBody.h>
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_AttributeSelection.h>
 
@@ -97,6 +96,31 @@ void ModuleBase_WidgetValidated::restoreAttributeValue(const AttributePtr& theAt
   myAttributeStore->restoreAttributeValue(theAttribute, myWorkshop);
 }
 
+
+//********************************************************************
+void ModuleBase_WidgetValidated::collectSubBodies(const ResultBodyPtr& theBody,
+                                                  AIS_NListOfEntityOwner& theList)
+{
+  AISObjectPtr aIOPtr;
+  TopoDS_Shape aTDShape;
+  int aNb = theBody->numberOfSubs();
+  for (int i = 0; i < aNb; i++) {
+    ResultBodyPtr aSub = theBody->subResult(i);
+    if (aSub->numberOfSubs() > 0)
+      collectSubBodies(aSub, theList);
+    else {
+      aTDShape = aSub->shape()->impl<TopoDS_Shape>();
+      aIOPtr = myWorkshop->findPresentation(aSub);
+      if (aIOPtr.get()) {
+        Handle(AIS_InteractiveObject) anIO = aIOPtr->impl<Handle(AIS_InteractiveObject)>();
+        theList.Append(new StdSelect_BRepOwner(aTDShape, anIO));
+      }
+      else
+        theList.Append(new StdSelect_BRepOwner(aTDShape));
+    }
+  }
+}
+
 //********************************************************************
 bool ModuleBase_WidgetValidated::isValidInFilters(const ModuleBase_ViewerPrsPtr& thePrs)
 {
@@ -141,32 +165,34 @@ bool ModuleBase_WidgetValidated::isValidInFilters(const ModuleBase_ViewerPrsPtr&
             Handle(AIS_InteractiveObject) anIO = myWorkshop->selection()->getIO(thePrs);
             aOwnersList.Append(new StdSelect_BRepOwner(aTDShape, anIO));
           }
-          else
-            aValid = false;
-          //aSelectAttr->setValue(ObjectPtr(), GeomShapePtr(), true);
         }
         else {
           ResultPtr aResult = aFeature->firstResult();
           if (aResult.get()) {
-            GeomShapePtr aShapePtr = ModelAPI_Tools::shape(aResult);
-            if (aShapePtr.get()) {
-              const TopoDS_Shape aTDShape = aShapePtr->impl<TopoDS_Shape>();
-              AISObjectPtr aIOPtr = myWorkshop->findPresentation(aResult);
-              if (aIOPtr.get()) {
-                Handle(AIS_InteractiveObject) anIO = aIOPtr->impl<Handle(AIS_InteractiveObject)>();
-                aOwnersList.Append(new StdSelect_BRepOwner(aTDShape, anIO));
-              }
-              else {
-                aOwnersList.Append(new StdSelect_BRepOwner(aTDShape));
+            ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResult);
+            if (aBody.get() && (aBody->numberOfSubs() > 0))
+              collectSubBodies(aBody, aOwnersList);
+            else {
+              GeomShapePtr aShapePtr = ModelAPI_Tools::shape(aResult);
+              if (aShapePtr.get()) {
+                TopoDS_Shape aTDShape = aShapePtr->impl<TopoDS_Shape>();
+                AISObjectPtr aIOPtr = myWorkshop->findPresentation(aResult);
+                if (aIOPtr.get()) {
+                  Handle(AIS_InteractiveObject) anIO =
+                    aIOPtr->impl<Handle(AIS_InteractiveObject)>();
+                  aOwnersList.Append(new StdSelect_BRepOwner(aTDShape, anIO));
+                }
+                else
+                  aOwnersList.Append(new StdSelect_BRepOwner(aTDShape));
               }
             }
           }
-          aValid = (aOwnersList.Size() > 0); // only results with a shape can be filtered
         }
-      } else
-        aValid = false; // only results with a shape can be filtered
+      }
     }
   }
+  aValid = (aOwnersList.Size() > 0); // only results with a shape can be filtered
+
   // checks the owner by the AIS context activated filters
   if (aOwnersList.Size() > 0) {
     // the widget validator filter should be active, but during check by preselection
index 19f7fff888662fd47f219eae5fc5c870503e26a4..ce6752b724950423a3006bf4fa955c058194cd94 100644 (file)
 #include <GeomAPI_AISObject.h>
 #include <ModelAPI_Object.h>
 #include <ModelAPI_Attribute.h>
+#include <ModelAPI_ResultBody.h>
 
 #include <SelectMgr_ListOfFilter.hxx>
 #include <NCollection_DataMap.hxx>
 #include <TopoDS_Shape.hxx>
+#include <AIS_NListOfEntityOwner.hxx>
 
 #include <QList>
 #include <QMap>
@@ -190,6 +192,8 @@ private:
   /// \param theValues a list of presentations.
   void filterCompSolids(QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues);
 
+  void collectSubBodies(const ResultBodyPtr& theBody, AIS_NListOfEntityOwner& theList);
+
 protected:
   /// Reference to workshop
   ModuleBase_IWorkshop* myWorkshop;
diff --git a/src/ModuleBase/ModuleBase_msg_fr.ts b/src/ModuleBase/ModuleBase_msg_fr.ts
new file mode 100644 (file)
index 0000000..b04a995
--- /dev/null
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+    <name>ExpressionEditor</name>
+    <message>
+        <source>Ctrl+Space</source>
+        <comment>Complete</comment>
+        <translation>Ctrl+Espace</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_FilterItem</name>
+    <message>
+        <source>Reverse the filter</source>
+        <translation>Inverser le filtre</translation>
+    </message>
+    <message>
+        <source>Delete the filter</source>
+        <translation>Supprimer le filtre</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_FilterStarter</name>
+    <message>
+        <source>Selection by filters</source>
+        <translation>Sélection par filtres</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_ListView</name>
+    <message>
+        <source>Copy</source>
+        <translation>Copie</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Effacer</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_PreferencesDlg</name>
+    <message>
+        <source>Edit preferences</source>
+        <translation>Modifier les préférences</translation>
+    </message>
+    <message>
+        <source>Default</source>
+        <translation>Défaut</translation>
+    </message>
+    <message>
+        <source>Desktop</source>
+        <translation>Bureau</translation>
+    </message>
+    <message>
+        <source>Module</source>
+        <translation>Module</translation>
+    </message>
+    <message>
+        <source>Viewer</source>
+        <translation>Vue</translation>
+    </message>
+    <message>
+        <source>Horizontal gradient</source>
+        <translation>Dégradé horizontal</translation>
+    </message>
+    <message>
+        <source>Vertical gradient</source>
+        <translation>Gradient vertical</translation>
+    </message>
+    <message>
+        <source>First diagonal gradient</source>
+        <translation>Premier gradient en diagonale</translation>
+    </message>
+    <message>
+        <source>Second diagonal gradient</source>
+        <translation>Deuxième gradient diagonal</translation>
+    </message>
+    <message>
+        <source>First corner gradient</source>
+        <translation>Premier angle de dégradé</translation>
+    </message>
+    <message>
+        <source>Second corner gradient</source>
+        <translation>Deuxième angle du dégradé</translation>
+    </message>
+    <message>
+        <source>Third corner gradient</source>
+        <translation>Troisième angle de dégradé</translation>
+    </message>
+    <message>
+        <source>Fourth corner gradient</source>
+        <translation>Quatrième angle</translation>
+    </message>
+    <message>
+        <source>Background</source>
+        <translation>Arrière-plan</translation>
+    </message>
+    <message>
+        <source>Viewer 3d</source>
+        <translation>Vue 3d</translation>
+    </message>
+    <message>
+        <source>Default selection</source>
+        <translation>Sélection par défaut</translation>
+    </message>
+    <message>
+        <source>Faces</source>
+        <translation>Faces</translation>
+    </message>
+    <message>
+        <source>Edges</source>
+        <translation>Arêtes</translation>
+    </message>
+    <message>
+        <source>Vertices</source>
+        <translation>Sommets</translation>
+    </message>
+    <message>
+        <source>Selection sensitivity</source>
+        <translation>Sensibilité de sélection</translation>
+    </message>
+    <message>
+        <source>Vertex</source>
+        <translation>Sommet</translation>
+    </message>
+    <message>
+        <source>Edge</source>
+        <translation>Bord</translation>
+    </message>
+    <message>
+        <source>Additional highlighting</source>
+        <translation>Mise en évidence supplémentaire</translation>
+    </message>
+    <message>
+        <source>In 3d mode</source>
+        <translation>En mode 3D</translation>
+    </message>
+    <message>
+        <source>In 2d mode</source>
+        <translation>En mode 2D</translation>
+    </message>
+    <message>
+        <source>Color scale</source>
+        <translation>Échelle de couleur</translation>
+    </message>
+    <message>
+        <source>X position</source>
+        <translation>Position X</translation>
+    </message>
+    <message>
+        <source>Y position</source>
+        <translation>Position Y</translation>
+    </message>
+    <message>
+        <source>Width</source>
+        <translation>Largeur</translation>
+    </message>
+    <message>
+        <source>Height</source>
+        <translation>Hauteur</translation>
+    </message>
+    <message>
+        <source>Intervals number</source>
+        <translation>Nombre d&apos;intervalles</translation>
+    </message>
+    <message>
+        <source>Text height</source>
+        <translation>Hauteur du texte</translation>
+    </message>
+    <message>
+        <source>Text color</source>
+        <translation>Couleur du texte</translation>
+    </message>
+    <message>
+        <source>Main menu</source>
+        <translation>Menu principal</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Taille</translation>
+    </message>
+    <message>
+        <source>Number of rows</source>
+        <translation>Nombre de rangées</translation>
+    </message>
+    <message>
+        <source>Show Status Bar</source>
+        <translation>Afficher la barre d&apos;état</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_WidgetFileSelector</name>
+    <message>
+        <source>Select file...</source>
+        <translation>Choisir le dossier...</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_WidgetMultiSelector</name>
+    <message>
+        <source>Type</source>
+        <translation>Type</translation>
+    </message>
+    <message>
+        <source>Show only</source>
+        <translation>Montrer seulement</translation>
+    </message>
+    <message>
+        <source>Add elements that share the same topology</source>
+        <translation>Ajouter des éléments qui partagent la même topologie</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_WidgetPointInput</name>
+    <message>
+        <source>X coordinate</source>
+        <translation>Coordonnée X</translation>
+    </message>
+    <message>
+        <source>Y coordinate</source>
+        <translation>Coordonnée Y</translation>
+    </message>
+    <message>
+        <source>Z coordinate</source>
+        <translation>Coordonnée Z</translation>
+    </message>
+</context>
+<context>
+    <name>ModuleBase_WidgetSelectionFilter</name>
+    <message>
+        <source>Filters</source>
+        <translation>Filtres</translation>
+    </message>
+    <message>
+        <source>Add new filter...</source>
+        <translation>Ajouter un nouveau filtre...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Sélectionner</translation>
+    </message>
+    <message>
+        <source>Number of selected objects:</source>
+        <translation>Nombre d&apos;objets sélectionnés:</translation>
+    </message>
+    <message>
+        <source>Show only</source>
+        <translation>Montrer seulement</translation>
+    </message>
+    <message>
+        <source>Selection is empty</source>
+        <translation>La sélection est vide</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>Selected objects can be used in Part documents which are not loaded: %1.
+</source>
+        <translation>Les objets sélectionnés peuvent être utilisés dans les documents de pièce non chargés : %1.
+</translation>
+    </message>
+    <message>
+        <source>Delete features</source>
+        <translation>Supprimer les fonctionnalités</translation>
+    </message>
+    <message>
+        <source>The following parts will be deleted: %1.
+</source>
+        <translation>Les pièces suivantes seront supprimées : %1.
+
+</translation>
+    </message>
+    <message>
+        <source>Replace</source>
+        <translation>Remplacer</translation>
+    </message>
+</context>
+</TS>
index 17aa1caabf0bbf73ac3c2751b728488e6e023fc1..8887619f9a1c652bf2f72663bf85ff8fc8eb5a0c 100644 (file)
@@ -78,6 +78,7 @@ ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS ${OpenCASCADE_DEFINITIONS})
 SET(TEXT_RESOURCES
        ParametersPlugin_msg_ru.ts
        ParametersPlugin_msg_en.ts
+       ParametersPlugin_msg_fr.ts
 )
 
 # QT4_CREATE_TRANSLATION(QM_RESOURCES
index 9078329662e93044b3d61496b2e572539f63be1d..9938df1e66b911170eae3108086274f1a72ea186 100644 (file)
@@ -39,6 +39,7 @@
 #include <ModuleBase_Tools.h>
 
 #include <Events_Loop.h>
+#include <Config_PropManager.h>
 
 #include <QLayout>
 #include <QPushButton>
@@ -50,6 +51,7 @@
 #include <QEvent>
 #include <QKeyEvent>
 #include <QDialogButtonBox>
+#include <QShortcut>
 
 enum ColumnType {
   Col_Name,
@@ -238,6 +240,13 @@ ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theP
   connect(myAddBtn, SIGNAL(clicked(bool)), SLOT(onAdd()));
   aBtnLayout->addWidget(myAddBtn);
 
+  QString aAddStr(Config_PropManager::string("Shortcuts", "add_parameter_shortcut").c_str());
+  if (aAddStr.isEmpty())
+    aAddStr = "Ctrl+A";
+
+  QShortcut* aAddShc = new QShortcut(QKeySequence(aAddStr), myAddBtn);
+  connect(aAddShc, SIGNAL(activated()), SLOT(onAdd()));
+
   myInsertBtn = new QPushButton(translate("Insert"), this);
   connect(myInsertBtn, SIGNAL(clicked(bool)), SLOT(onInsert()));
   aBtnLayout->addWidget(myInsertBtn);
diff --git a/src/ParametersPlugin/ParametersPlugin_msg_fr.ts b/src/ParametersPlugin/ParametersPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..6bd03a1
--- /dev/null
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Parameter</source>
+      <translation>Paramètre</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>ModuleBase_Dialog</name>
+    <message>
+      <source>Parameters</source>
+      <translation>Paramètres</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Parameter</name>
+    <message>
+      <source>Create a parameter</source>
+      <translation>Créer un paramètre</translation>
+    </message>
+    <message>
+      <source>Parameter</source>
+      <translation>Paramètre</translation>
+    </message>
+    <message>
+      <source>Attribute "variable" is not initialized.</source>
+      <translation>Définir le nom de la variable</translation>
+    </message>
+    <message>
+      <source>Expression error.</source>
+      <translation>Erreur d&apos;expression.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Parameter:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "expression" is not initialized.</source>
+      <translation>Définir l&apos;expression</translation>
+    </message>
+  </context>
+  <context>
+    <name>Parameter:comment</name>
+    <message>
+      <source>Comment</source>
+      <translation>Commentaire</translation>
+    </message>
+  </context>
+  <context>
+    <name>Parameter:expression</name>
+    <message>
+      <source>Please input the expression</source>
+      <translation>S&apos;il vous plaît entrer l&apos;expression</translation>
+    </message>
+  </context>
+  <context>
+    <name>Parameter:expression:Parameters_ExpressionValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Parameter:variable</name>
+    <message>
+      <source>Name</source>
+      <translation>Nom</translation>
+    </message>
+    <message>
+      <source>Please input the parameter name</source>
+      <translation>Veuillez saisir le nom du paramètre</translation>
+    </message>
+  </context>
+  <context>
+    <name>Parameter:variable:Parameters_VariableValidator</name>
+    <message>
+      <source>Attribute "%1" value is empty.</source>
+      <translation>La valeur de l&apos;attribut &quot;%1&quot; est vide.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>ParametersMgr</name>
+    <message>
+      <source>Manage parameters</source>
+      <translation>Gérer les paramètres</translation>
+    </message>
+    <message>
+      <source>Parameters</source>
+      <translation>Paramètres</translation>
+    </message>
+  </context>
+  <context>
+    <name>ParametersMgr</name>
+    <message>
+      <source>Add</source>
+      <translation>Ajouter</translation>
+    </message>
+    <message>
+      <source>Comment</source>
+      <translation>Commentaire</translation>
+    </message>
+    <message>
+      <source>Expression</source>
+      <translation>Expression</translation>
+    </message>
+    <message>
+      <source>Features</source>
+      <translation>Caractéristiques</translation>
+    </message>
+    <message>
+      <source>Insert</source>
+      <translation>Insérer</translation>
+    </message>
+    <message>
+      <source>Name</source>
+      <translation>Nom</translation>
+    </message>
+    <message>
+      <source>Remove</source>
+      <translation>Retirer</translation>
+    </message>
+    <message>
+      <source>Result</source>
+      <translation>Résultat</translation>
+    </message>
+    <message>
+      <source>See preview</source>
+      <translation>Voir l&apos;aperçu</translation>
+    </message>
+    <message>
+      <source>&lt;NoName&gt;</source>
+      <translation>&lt;SansNom&gt;</translation>
+    </message>
+    <message>
+      <source>&lt;NoValue&gt;</source>
+      <translation>&lt;AucuneValeur&gt;</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>ParametersPlugin</name>
+    <message>
+      <source>Warning</source>
+      <translation>Attention</translation>
+    </message>
+    <message>
+      <source>Selected objects can be used in Part documents which are not loaded: %1. Would you like to continue?</source>
+      <translation>Les objets sélectionnés peuvent être utilisés dans les documents de pièce non chargés : %1. Voulez-vous continuer ?</translation>
+    </message>
+  </context>
+
+</TS>
index b818e20c90ed87d840808ff28365721d1242f21d..83789b24f3b56cca7f72f5401121995d3fa231ec 100644 (file)
@@ -118,7 +118,7 @@ SET(PROJECT_RESOURCES
 )
 
 SET(TEXT_RESOURCES
-#    PartSet_msg_fr.ts
+    PartSet_msg_fr.ts
 )
 
 SET(PROJECT_LIBRARIES
@@ -139,14 +139,16 @@ QT_WRAP_MOC(PROJECT_AUTOMOC ${PROJECT_MOC_HEADERS})
 QT_ADD_RESOURCES(PROJECT_COMPILED_RESOURCES ${PROJECT_RESOURCES})
 
 IF (${UPDATE_TRANSLATION})
-    SET(PROJECT_FILES ${PROJECT_SOURCES} ${ROJECT_HEADERS} )
+    SET(PROJECT_FILES ${PROJECT_SOURCES} ${PROJECT_HEADERS} )
     QT5_CREATE_TRANSLATION(QM_RESOURCES
                            ${PROJECT_FILES}
                            ${TEXT_RESOURCES}
-                           OPTIONS -extensions cpp -no-recursive
+                           OPTIONS -extensions cpp -no-recursive -locations none
                           )
 ELSE(${UPDATE_TRANSLATION})
-    QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    IF(${MAKE_TRANSLATION})
+        QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    ENDIF(${MAKE_TRANSLATION})
 ENDIF(${UPDATE_TRANSLATION})
 
 SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES} ${QM_RESOURCES})
index 21465eb1cb133887e2a96caf458beb7fe9b87fd6..e18ca5bb063b58a5716997908d3c8b078328ac4d 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-#include <PartSet_CustomPrs.h>
-#include <PartSet_Module.h>
+#include "PartSet_CustomPrs.h"
+#include "PartSet_Module.h"
 #include "PartSet_OperationPrs.h"
 #include "PartSet_OverconstraintListener.h"
+#include "PartSet_SketcherMgr.h"
 
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_Workshop.h>
@@ -30,6 +31,9 @@
 #include <ModuleBase_IViewer.h>
 #include <ModuleBase_Tools.h>
 
+#include <ModelAPI_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
 #include <Config_PropManager.h>
 #include <Events_Loop.h>
 #include <ModelAPI_Events.h>
@@ -68,12 +72,22 @@ bool PartSet_CustomPrs::activate(const FeaturePtr& theFeature,
 #ifdef DO_NOT_VISUALIZE_CUSTOM_PRESENTATION
   return false;
 #endif
+  bool isModified = false;
 
-  myIsActive[theFlag] = true;
-  myFeature = theFeature;
+  // Do not call customisation for sketcher and all its sub-objects
+  if (theFeature->getKind() == SketchPlugin_Sketch::ID())
+    return isModified;
+
+  FeaturePtr aParent = ModelAPI_Tools::compositeOwner(theFeature);
+  if (aParent.get()) {
+    std::string aType = aParent->getKind();
+    if (aType == SketchPlugin_Sketch::ID())
+      return isModified;
+  }
 
-  bool isModified = false;
   if (theFeature.get()) {
+    myIsActive[theFlag] = true;
+    myFeature = theFeature;
     displayPresentation(theFlag, theUpdateViewer);
     isModified = true;
   }
index abe6aa02599cb656bcd66a7f60d0044856004e3a..67c385b96ac26998277597270b60c0388f5b0c19 100644 (file)
@@ -163,11 +163,9 @@ void PartSet_IconFactory::processEvent(const std::shared_ptr<Events_Message>& th
       Events_Loop::loop()->eventByName(Config_FeatureMessage::GUI_EVENT())) {
     std::shared_ptr<Config_FeatureMessage> aFeatureMsg =
        std::dynamic_pointer_cast<Config_FeatureMessage>(theMessage);
-    if (!aFeatureMsg->isInternal()) {
-      ActionInfo aFeatureInfo;
-      aFeatureInfo.initFrom(aFeatureMsg);
-      // Remember features icons
-      myIcons[QString::fromStdString(aFeatureMsg->id())] = aFeatureInfo.iconFile;
-    }
+    ActionInfo aFeatureInfo;
+    aFeatureInfo.initFrom(aFeatureMsg);
+    // Remember features icons
+    myIcons[QString::fromStdString(aFeatureMsg->id())] = aFeatureInfo.iconFile;
   }
 }
\ No newline at end of file
index 5756d13d6ac0bed9fe297b7adfec9b362aa0ae31..0ea7aa78d4efeafc27614cefd638c72bb8f6cb80 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <ModuleBase_ISelection.h>
 #include <ModuleBase_Operation.h>
-#include <ModuleBase_OperationAction.h>
 #include <ModuleBase_OperationFeature.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_Tools.h>
@@ -313,8 +312,8 @@ void PartSet_MenuMgr::onLineDetach(QAction* theAction)
     XGUI_Workshop* aWorkshop = aConnector->workshop();
     ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
 
-    ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(
-                                   tr("Detach %1").arg(aLine->data()->name().c_str()), myModule);
+    ModuleBase_Operation* anOpAction =
+      new ModuleBase_Operation(tr("Detach %1").arg(aLine->data()->name().c_str()), myModule);
     bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
     XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
     // the active nested sketch operation should be aborted unconditionally
@@ -373,11 +372,11 @@ void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
 
   QAction* anAction = action("AUXILIARY_CMD");
   //SessionPtr aMgr = ModelAPI_Session::get();
-  ModuleBase_OperationAction* anOpAction = 0;
+  ModuleBase_Operation* anOpAction = 0;
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
   XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
   if (isUseTransaction) {
-    anOpAction = new ModuleBase_OperationAction(anAction->text(), myModule);
+    anOpAction = new ModuleBase_Operation(anAction->text(), myModule);
     bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
 
     bool isCommitted;
@@ -386,6 +385,7 @@ void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
 
     anOpMgr->startOperation(anOpAction);
   }
+  static const Events_ID anVisualEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
   if (anObjects.size() > 0) {
     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
     for (; anIt != aLast; anIt++) {
@@ -401,6 +401,7 @@ void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
             aSketchFeature->data()->attribute(anAttribute));
           if (anAuxiliaryAttr)
             anAuxiliaryAttr->setValue(isChecked);
+          ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, anVisualEvent);
         }
       }
     }
@@ -409,6 +410,7 @@ void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
     anOpMgr->commitOperation();
 
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  Events_Loop::loop()->flush(anVisualEvent);
 }
 
 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
index 0ad3ce8f22bf20accb23f184853d37930ddd21ac..5b50689714efd32cde8bd4584cae4d8411858834 100644 (file)
@@ -54,7 +54,6 @@
 #include <SketchPlugin_ConstraintCoincidence.h>
 
 #include <ModuleBase_Operation.h>
-#include <ModuleBase_OperationAction.h>
 #include <ModuleBase_IViewer.h>
 #include <ModuleBase_IViewWindow.h>
 #include <ModuleBase_IPropertyPanel.h>
@@ -67,8 +66,9 @@
 #include <ModuleBase_WidgetFactory.h>
 #include <ModuleBase_OperationDescription.h>
 #include <ModuleBase_ViewerPrs.h>
-#include <ModelAPI_ResultField.h>
+#include <ModuleBase_ResultPrs.h>
 
+#include <ModelAPI_ResultField.h>
 #include <ModelAPI_Object.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_Validator.h>
@@ -80,6 +80,7 @@
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_ResultGroup.h>
 
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Point.h>
@@ -89,7 +90,6 @@
 #include <XGUI_ActiveControlSelector.h>
 #include <XGUI_ActionsMgr.h>
 #include <XGUI_ContextMenuMgr.h>
-#include <XGUI_CustomPrs.h>
 #include <XGUI_DataModel.h>
 #include <XGUI_Displayer.h>
 #include <XGUI_ErrorMgr.h>
@@ -191,6 +191,26 @@ PartSet_Module::PartSet_Module(ModuleBase_IWorkshop* theWshop)
 
   setDefaultConstraintShown();
 
+  //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color",
+  //                                 Config_Prop::Color, "225,225,225");
+
+  Config_PropManager::registerProp("Visualization", "result_body_color", "Result color",
+    Config_Prop::Color, ModelAPI_ResultBody::DEFAULT_COLOR());
+
+  Config_PropManager::registerProp("Visualization", "result_group_color", "Group color",
+    Config_Prop::Color, ModelAPI_ResultGroup::DEFAULT_COLOR());
+
+  Config_PropManager::registerProp("Visualization", "result_construction_color",
+    "Construction color",
+    Config_Prop::Color,
+    ModelAPI_ResultConstruction::DEFAULT_COLOR());
+
+  Config_PropManager::registerProp("Visualization", "result_part_color", "Part color",
+    Config_Prop::Color, ModelAPI_ResultPart::DEFAULT_COLOR());
+
+  Config_PropManager::registerProp("Visualization", "result_field_color", "Field color",
+    Config_Prop::Color, ModelAPI_ResultField::DEFAULT_COLOR());
+
   Config_PropManager::registerProp("Visualization", "operation_parameter_color",
                           "Reference shape wireframe color in operation", Config_Prop::Color,
                           PartSet_CustomPrs::OPERATION_PARAMETER_COLOR());
@@ -228,6 +248,13 @@ PartSet_Module::PartSet_Module(ModuleBase_IWorkshop* theWshop)
   Config_PropManager::registerProp("Visualization", "sketch_dimension_color",
     "Dimension color",
     Config_Prop::Color, SKETCH_DIMENSION_COLOR);
+
+  Config_PropManager::registerProp("Shortcuts", "add_parameter_shortcut",
+    "Add parameter in parameters manager dialog",
+    Config_Prop::Shortcut, "Ctrl+A");
+
+  Config_PropManager::registerProp("Windows", "use_hide_faces_panel",
+    "Use HideFaces panel in operations", Config_Prop::Boolean, "false");
 }
 
 //******************************************************
@@ -430,9 +457,11 @@ void PartSet_Module::updateSketcherOnStart(ModuleBase_Operation* theOperation)
   if (PartSet_SketcherMgr::isSketchOperation(theOperation)) {
     mySketchMgr->startSketch(theOperation);
   }
-  else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
-    mySketchMgr->startNestedSketch(theOperation);
-  }
+  // 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);
+  //}
 }
 
 //******************************************************
@@ -524,7 +553,7 @@ bool PartSet_Module::canRedo() const
 bool PartSet_Module::canApplyAction(const ObjectPtr& theObject, const QString& theActionId) const
 {
   bool aValid = true;
-  if (theActionId == "MOVE_CMD") {
+  if (theActionId == "MOVE_CMD" || theActionId == "MOVE_SPLIT_CMD") {
     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
     if (aFeature) {
       ResultPtr aResult = ModuleBase_Tools::firstResult(aFeature);
@@ -747,16 +776,14 @@ void PartSet_Module::propertyPanelDefined(ModuleBase_Operation* theOperation)
 }
 
 //******************************************************
-bool PartSet_Module::createWidgets(ModuleBase_Operation* theOperation,
+bool PartSet_Module::createWidgets(const FeaturePtr& theFeature, const QString& theXmlRepr,
                                    QList<ModuleBase_ModelWidget*>& theWidgets) const
 {
   bool aProcessed = false;
 
-  ModuleBase_OperationFeature* aFOperation =
-    dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
   XGUI_Workshop* aWorkshop = getWorkshop();
   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
-  if (mySketchMgr->activeSketch().get() && aFOperation && aPropertyPanel) {
+  if (mySketchMgr->activeSketch().get() && aPropertyPanel) {
     ModuleBase_ISelection* aSelection = workshop()->selection();
     // click on a point in sketch leads here with the point is highlighted, not yet selected
     QList<ModuleBase_ViewerPrsPtr> aPreselection = aSelection->getHighlighted();
@@ -765,11 +792,10 @@ bool PartSet_Module::createWidgets(ModuleBase_Operation* theOperation,
       ObjectPtr anObject = aSelectedPrs->object();
 
       FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
-      FeaturePtr anOpFeature = aFOperation->feature();
       GeomShapePtr aShape = aSelectedPrs->shape();
       // click on the digit of dimension constrain comes here
       // with an empty shape, so we need the check
-      if (aFeature == anOpFeature && aShape.get() && !aShape->isNull()) {
+      if (aFeature == theFeature && aShape.get() && !aShape->isNull()) {
         // if feature has only one result and shape of result is equal to selected shape
         // this attribute is not processed. It is a case of Sketch Point.
         if (aFeature->results().size() == 1) {
@@ -781,8 +807,7 @@ bool PartSet_Module::createWidgets(ModuleBase_Operation* theOperation,
         AttributePtr anAttribute = PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape,
                                                                mySketchMgr->activeSketch());
         if (anAttribute.get()) {
-          QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
-          ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), workshop());
+          ModuleBase_WidgetFactory aFactory(theXmlRepr.toStdString(), workshop());
 
           const std::string anAttributeId = anAttribute->id();
           aFactory.createWidget(aPropertyPanel->contentWidget(), anAttributeId);
@@ -966,7 +991,7 @@ bool PartSet_Module::deleteObjects()
 
     // 3. start operation
     QString aDescription = aWorkshop->contextMenuMgr()->action("DELETE_CMD")->text();
-    ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, this);
+    ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, this);
 
     // the active nested sketch operation should be aborted unconditionally
     // the Delete action should be additionally granted for the Sketch operation
@@ -1166,75 +1191,75 @@ void PartSet_Module::deactivateCustomPrs(const ModuleBase_CustomizeFlag& theFlag
 }
 
 //******************************************************
-bool PartSet_Module::customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
-                                           std::shared_ptr<GeomAPI_ICustomPrs> theCustomPrs)
-{
-  bool aCustomized = false;
-
-  XGUI_Workshop* aWorkshop = getWorkshop();
-  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
-  ObjectPtr anObject = aDisplayer->getObject(thePrs);
-  if (!anObject)
-    return aCustomized;
-
-  if (!theResult.get()) {
-    std::vector<int> aColor;
-    XGUI_CustomPrs::getDefaultColor(anObject, true, aColor);
-    if (!aColor.empty()) {
-      aCustomized = thePrs->setColor(aColor[0], aColor[1], aColor[2]);
-    }
-  }
-  // customize dimentional constrains
-  sketchMgr()->customizePresentation(anObject);
-
-  return aCustomized;
-}
-
-//******************************************************
-bool PartSet_Module::afterCustomisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
-                                                AISObjectPtr thePrs,
-                                                GeomCustomPrsPtr theCustomPrs)
-{
-  bool aCustomized = false;
-
-  XGUI_Workshop* aWorkshop = getWorkshop();
-  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
-  ObjectPtr anObject = aDisplayer->getObject(thePrs);
-  if (!anObject)
-    return aCustomized;
-
-  std::vector<int> aColor;
-  bool aUseCustomColor = true;
-  if (aUseCustomColor)
-    myOverconstraintListener->getCustomColor(anObject, aColor);
-  // customize sketch symbol presentation
-  Handle(AIS_InteractiveObject) anAISIO = thePrs->impl<Handle(AIS_InteractiveObject)>();
-  if (!anAISIO.IsNull()) {
-    if (!Handle(SketcherPrs_SymbolPrs)::DownCast(anAISIO).IsNull()) {
-      Handle(SketcherPrs_SymbolPrs) aPrs = Handle(SketcherPrs_SymbolPrs)::DownCast(anAISIO);
-      if (!aPrs.IsNull()) {
-        aPrs->SetCustomColor(aColor);
-        aCustomized = true;
-      }
-    } else if (!Handle(SketcherPrs_Coincident)::DownCast(anAISIO).IsNull()) {
-      Handle(SketcherPrs_Coincident) aPrs = Handle(SketcherPrs_Coincident)::DownCast(anAISIO);
-      if (!aPrs.IsNull()) {
-        aPrs->SetCustomColor(aColor);
-        aCustomized = true;
-      }
-    }
-  }
-  // customize sketch dimension constraint presentation
-  if (!aCustomized) {
-    if (!aColor.empty()) { // otherwise presentation has the default color
-      aCustomized = thePrs->setColor(aColor[0], aColor[1], aColor[2]);
-    }
-  }
-  return aCustomized;
-}
-
-//******************************************************
-bool PartSet_Module::customizeObject(ObjectPtr theObject, const ModuleBase_CustomizeFlag& theFlag,
+//bool PartSet_Module::customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
+//                                           std::shared_ptr<GeomAPI_ICustomPrs> theCustomPrs)
+//{
+//  bool aCustomized = false;
+//
+//  XGUI_Workshop* aWorkshop = getWorkshop();
+//  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+//  ObjectPtr anObject = aDisplayer->getObject(thePrs);
+//  if (!anObject)
+//    return aCustomized;
+//
+//  if (!theResult.get()) {
+//    std::vector<int> aColor;
+//    XGUI_CustomPrs::getDefaultColor(anObject, true, aColor);
+//    if (!aColor.empty()) {
+//      aCustomized = thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+//    }
+//  }
+//  // customize dimentional constrains
+//  sketchMgr()->customisePresentation(anObject);
+//
+//  return aCustomized;
+//}
+//
+////******************************************************
+//bool PartSet_Module::afterCustomisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
+//                                                AISObjectPtr thePrs,
+//                                                GeomCustomPrsPtr theCustomPrs)
+//{
+//  bool aCustomized = false;
+//
+//  XGUI_Workshop* aWorkshop = getWorkshop();
+//  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+//  ObjectPtr anObject = aDisplayer->getObject(thePrs);
+//  if (!anObject)
+//    return aCustomized;
+//
+//  std::vector<int> aColor;
+//  bool aUseCustomColor = true;
+//  if (aUseCustomColor)
+//    myOverconstraintListener->getCustomColor(anObject, aColor);
+//  // customize sketch symbol presentation
+//  Handle(AIS_InteractiveObject) anAISIO = thePrs->impl<Handle(AIS_InteractiveObject)>();
+//  if (!anAISIO.IsNull()) {
+//    if (!Handle(SketcherPrs_SymbolPrs)::DownCast(anAISIO).IsNull()) {
+//      Handle(SketcherPrs_SymbolPrs) aPrs = Handle(SketcherPrs_SymbolPrs)::DownCast(anAISIO);
+//      if (!aPrs.IsNull()) {
+//        aPrs->SetCustomColor(aColor);
+//        aCustomized = true;
+//      }
+//    } else if (!Handle(SketcherPrs_Coincident)::DownCast(anAISIO).IsNull()) {
+//      Handle(SketcherPrs_Coincident) aPrs = Handle(SketcherPrs_Coincident)::DownCast(anAISIO);
+//      if (!aPrs.IsNull()) {
+//        aPrs->SetCustomColor(aColor);
+//        aCustomized = true;
+//      }
+//    }
+//  }
+//  // customize sketch dimension constraint presentation
+//  if (!aCustomized) {
+//    if (!aColor.empty()) { // otherwise presentation has the default color
+//      aCustomized = thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+//    }
+//  }
+//  return aCustomized;
+//}
+
+//******************************************************
+bool PartSet_Module::customizeFeature(ObjectPtr theObject, const ModuleBase_CustomizeFlag& theFlag,
                                      const bool theUpdateViewer)
 {
   bool isRedisplayed = false;
@@ -1279,21 +1304,101 @@ void PartSet_Module::onActiveDocPopup(const QPoint& thePnt)
 }
 
 //******************************************************
-Handle(AIS_InteractiveObject) PartSet_Module::createPresentation(const ObjectPtr& theObject)
+AISObjectPtr PartSet_Module::createPresentation(const ObjectPtr& theObject)
+{
+  Handle(AIS_InteractiveObject) anAISPrs = mySketchMgr->createPresentation(theObject);
+  if (anAISPrs.IsNull()) {
+    ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+    if (aResult.get()) {
+      std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
+      if (aShapePtr.get() != NULL)
+        anAISPrs = new ModuleBase_ResultPrs(aResult);
+    }
+    else {
+      FieldStepPtr aStep =
+        std::dynamic_pointer_cast<ModelAPI_ResultField::ModelAPI_FieldStep>(theObject);
+      if (aStep.get()) {
+        anAISPrs = new PartSet_FieldStepPrs(aStep);
+      }
+    }
+  }
+  AISObjectPtr anAIS;
+  if (!anAISPrs.IsNull()) {
+    Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(anAISPrs);
+    if (!aShapePrs.IsNull())
+      ModuleBase_Tools::setPointBallHighlighting((AIS_Shape*)aShapePrs.get());
+
+    anAIS = AISObjectPtr(new GeomAPI_AISObject());
+    anAIS->setImpl(new Handle(AIS_InteractiveObject)(anAISPrs));
+    customizePresentation(theObject, anAIS);
+  }
+  return anAIS;
+}
+
+//******************************************************
+void getResultColor(const ResultPtr& theResult, std::vector<int>& theColor)
+{
+  ModelAPI_Tools::getColor(theResult, theColor);
+  if (theColor.empty())
+    PartSet_Tools::getDefaultColor(theResult, false, theColor);
+}
+
+//******************************************************
+double getResultDeflection(const ResultPtr& theResult)
 {
-  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-  if (aResult.get())
-    return mySketchMgr->createPresentation(aResult);
+  double aDeflection = ModelAPI_Tools::getDeflection(theResult);
+  if (aDeflection < 0)
+    aDeflection = PartSet_Tools::getDefaultDeflection(theResult);
+  return aDeflection;
+}
+
+//******************************************************
+double getResultTransparency(const ResultPtr& theResult)
+{
+  double aTransparency = ModelAPI_Tools::getTransparency(theResult);
+  if (aTransparency < 0)
+    aTransparency = PartSet_Tools::getDefaultTransparency();
+  return aTransparency;
+}
+
+
+//******************************************************
+void PartSet_Module::customizePresentation(const ObjectPtr& theObject,
+                                           const AISObjectPtr& thePrs) const
+{
+  if (mySketchMgr->isObjectOfSketch(theObject)) {
+    mySketchMgr->customizeSketchPresentation(theObject, thePrs);
+  }
   else {
-    FieldStepPtr aStep =
-      std::dynamic_pointer_cast<ModelAPI_ResultField::ModelAPI_FieldStep>(theObject);
-    if (aStep.get()) {
-      return new PartSet_FieldStepPrs(aStep);
+    ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+    if (aResult.get()) {
+      std::vector<int> aColor;
+      getResultColor(aResult, aColor);
+
+      SessionPtr aMgr = ModelAPI_Session::get();
+      if (aMgr->activeDocument() != aResult->document()) {
+        QColor aQColor(aColor[0], aColor[1], aColor[2]);
+        QColor aNewColor =
+          QColor::fromHsvF(aQColor.hueF(), aQColor.saturationF() / 3., aQColor.valueF());
+        aColor[0] = aNewColor.red();
+        aColor[1] = aNewColor.green();
+        aColor[2] = aNewColor.blue();
+      }
+      thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+
+      thePrs->setDeflection(getResultDeflection(aResult));
+
+      thePrs->setTransparency(getResultTransparency(aResult));
+    }
+    FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+    if (aFeature.get()) {
+      if (aFeature->getKind() == SketchPlugin_Sketch::ID())
+        thePrs->setWidth(2);
     }
   }
-  return Handle(AIS_InteractiveObject)();
 }
 
+
 //******************************************************
 ObjectPtr PartSet_Module::findPresentedObject(const AISObjectPtr& theAIS) const
 {
index bcd16ee1771476c5a5cfd3854f611d087bcfb479..bd91508616f0262bbe80aa3802e9b88f28b29ecf 100644 (file)
@@ -105,10 +105,11 @@ public:
   /// If there is found selected attribute, widgets are created and contains
   /// only a widget for the attribute
   /// It is important for Property Panel filling by sketch point attribute
-  /// \param theOperation a started operation
+  /// \param theFeature a feature of the started operation
+  /// \param theXmlRepr an XML representation of the operation
   /// \param theWidgets a list of created widgets
   /// \return boolean result, false by default
-  virtual bool createWidgets(ModuleBase_Operation* theOperation,
+  virtual bool createWidgets(const FeaturePtr& theFeature, const QString& theXmlRepr,
                              QList<ModuleBase_ModelWidget*>& theWidgets) const;
 
   /// Launching of a edit operation on the feature
@@ -290,14 +291,14 @@ public:
                                    const bool theUpdateViewer);
 
   /// Modifies the given presentation in the custom way.
-  virtual bool customisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
-                                     AISObjectPtr thePrs,
-                                     std::shared_ptr<GeomAPI_ICustomPrs> theCustomPrs);
+  //virtual bool customisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
+  //                                   AISObjectPtr thePrs,
+  //                                   std::shared_ptr<GeomAPI_ICustomPrs> theCustomPrs);
 
-  /// Modifies the given presentation in the custom way after usual customize is performed.
-  virtual bool afterCustomisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
-                                          AISObjectPtr thePrs,
-                                          GeomCustomPrsPtr theCustomPrs);
+  ///// Modifies the given presentation in the custom way after usual customize is performed.
+  //virtual bool afterCustomisePresentation(std::shared_ptr<ModelAPI_Result> theResult,
+  //                                        AISObjectPtr thePrs,
+  //                                        GeomCustomPrsPtr theCustomPrs);
 
   /// Update the object presentable properties such as color, lines width and other
   /// If the object is result with the color attribute value set, it is used,
@@ -307,8 +308,8 @@ public:
   /// should be updated(e.g. only highlighted elements)
   /// \param theUpdateViewer the parameter whether the viewer should be update immediatelly
   /// \returns true if the object is modified
-  virtual bool customizeObject(ObjectPtr theObject, const ModuleBase_CustomizeFlag& theFlag,
-                               const bool theUpdateViewer);
+  virtual bool customizeFeature(ObjectPtr theObject, const ModuleBase_CustomizeFlag& theFlag,
+                                const bool theUpdateViewer);
 
   /// Disable displaying of custom mode
   /// \param theMode a mode to disable
@@ -327,7 +328,12 @@ public:
   /// Create specific for the module presentation
   /// \param theResult an object for presentation
   /// \return created presentation or NULL(default value)
-  virtual Handle(AIS_InteractiveObject) createPresentation(const ObjectPtr& theResult);
+  virtual AISObjectPtr createPresentation(const ObjectPtr& theResult);
+
+  /// Customize presentation according to objects attributes
+  /// \param theObject an object for presentation
+  /// \param thePrs a presentation object
+  virtual void customizePresentation(const ObjectPtr& theObject, const AISObjectPtr& thePrs) const;
 
   //! Returns data object by AIS
   virtual ObjectPtr findPresentedObject(const AISObjectPtr& theAIS) const;
index 59fbfa96edecbb2bb0b055177e1fca6800e81ecd..70c19725c8ff56b0221dc9c9e7d358bd78f668c3 100644 (file)
@@ -25,7 +25,6 @@
 #include <PartSet_SketcherMgr.h>
 #include <PartSet_SketcherReentrantMgr.h>
 
-#include "XGUI_CustomPrs.h"
 #include "XGUI_Displayer.h"
 #include "XGUI_ModuleConnector.h"
 #include "XGUI_OperationMgr.h"
@@ -284,7 +283,7 @@ void PartSet_OverconstraintListener::redisplayObjects(
 {
   static Events_Loop* aLoop = Events_Loop::loop();
 
-  static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_VISUAL_ATTRIBUTES);
   static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
 
   std::set<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();
index 5481f9d947d9e866a2454fce010d6136fb1ee8c6..a02dee98e5036150619507b34b019c66a607e661 100644 (file)
@@ -58,6 +58,14 @@ public:
   /// Redefinition of Events_Listener method
   virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
+
+  bool isConflictingObject(const ObjectPtr& theObject) const
+  {
+    return (myConflictingObjects.find(theObject) != myConflictingObjects.end());
+  }
+
+  bool isFullyConstrained() const { return myIsFullyConstrained; }
+
 protected:
   /// Append objects to the internal container of conflicting object, redisplay necessary objects
   /// \param theObjects a list of new conflicting objects
index e5118c9b99b8443f9182f4f7c6850afab83a7512..e8257714569d0363873ca9a0db1b851984a35787 100644 (file)
 #include <QMessageBox>
 #include <QMainWindow>
 
+#include <set>
+
 //#define DEBUG_DO_NOT_BY_ENTER
 //#define DEBUG_SKETCHER_ENTITIES
 //#define DEBUG_SKETCH_ENTITIES_ON_MOVE
@@ -201,6 +203,8 @@ PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
 
   registerSelectionFilter(SF_SketchCirclePointFilter, new PartSet_CirclePointFilter(anIWorkshop));
   registerSelectionFilter(SF_SketchPlaneFilter, new ModuleBase_ShapeInPlaneFilter());
+
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_DOF_OBJECTS));
 }
 
 PartSet_SketcherMgr::~PartSet_SketcherMgr()
@@ -220,15 +224,17 @@ void PartSet_SketcherMgr::onEnterViewPort()
   return;
   #endif
 
-  if (canChangeCursor(getCurrentOperation())) {
-    QCursor* aCurrentCursor = QApplication::overrideCursor();
-    if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
-      QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
-#ifdef DEBUG_CURSOR
-      qDebug("onEnterViewPort() : Qt::CrossCursor");
-#endif
-    }
-  }
+  // 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));
+  //#ifdef DEBUG_CURSOR
+  //      qDebug("onEnterViewPort() : Qt::CrossCursor");
+  //#endif
+  //    }
+  //  }
 
   if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
     return;
@@ -260,12 +266,12 @@ void PartSet_SketcherMgr::onLeaveViewPort()
   return;
   #endif
 
-  if (canChangeCursor(getCurrentOperation())) {
-    QApplication::restoreOverrideCursor();
-#ifdef DEBUG_CURSOR
-    qDebug("onLeaveViewPort() : None");
-#endif
-  }
+//  if (canChangeCursor(getCurrentOperation())) {
+//    QApplication::restoreOverrideCursor();
+//#ifdef DEBUG_CURSOR
+//    qDebug("onLeaveViewPort() : None");
+//#endif
+//  }
 
   if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
     return;
@@ -407,7 +413,6 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
     }
     // Init flyout point for radius rotation
     FeaturePtr aFeature = myCurrentSelection.begin().key();
-
     get2dPoint(theWnd, theEvent, myCurrentPoint);
     if (isSketcher) {
       if (aCanDrag) {
@@ -437,14 +442,33 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       /// Internal edit should not be stored as editing operation as the result will be a
       /// creation operation, where previous selection should not be used(and will be cleared)
       myIsEditLaunching = !myModule->sketchReentranceMgr()->isInternalEditActive();
-      aFOperation->commit();
+
+      std::shared_ptr<SketchPlugin_Feature> aSPFeature =
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(aFOperation->feature());
+      bool isRelaunchEditing = true;
+      if (aSPFeature->isExternal()) {
+        foreach(FeaturePtr aF, myCurrentSelection.keys()) {
+          FeaturePtr aProducerFeature = PartSet_Tools::findRefsToMeFeature(aF,
+            aSPFeature->getKind());
+          if (aProducerFeature == aSPFeature) {
+            isRelaunchEditing = false;
+            break;
+          }
+        }
+      }
+      else
+        isRelaunchEditing = !myCurrentSelection.contains(aSPFeature);
+
+      if (isRelaunchEditing)
+        aFOperation->commit();
 
       if (aCanDrag) {
         myIsDragging = true;
         myDragDone = false;
       }
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
-      launchEditing();
+      if (isRelaunchEditing)
+        launchEditing();
       myIsEditLaunching = aPrevLaunchingState;
       if (aFeature.get() != NULL) {
         std::shared_ptr<SketchPlugin_Feature> aSPFeature =
@@ -466,8 +490,9 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
+  ModuleBase_IViewer* aViewer = aWorkshop->viewer();
   if (myIsDragging)
-    aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
+    aViewer->enableDrawMode(myPreviousDrawModeEnabled);
 
   bool aWasDragging = myIsDragging;
   myIsDragging = false;
@@ -479,11 +504,10 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse
   if (!myIsMouseOverViewProcessed) {
     return;
   }
-  ModuleBase_IViewer* aViewer = aWorkshop->viewer();
   //if (!aViewer->canDragByMouse())
   //  return;
   ModuleBase_OperationFeature* aOp =
-      dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
+    dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
   if (aOp) {
     bool aStartNoDragOperation = !aViewer->canDragByMouse() && aOp->isEditOperation();
     if (aStartNoDragOperation || myNoDragMoving) {
@@ -883,13 +907,15 @@ void PartSet_SketcherMgr::sketchSelectionModes(const CompositeFeaturePtr& theSke
   theModes.append(TopAbs_EDGE);
 }
 
-Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ResultPtr& theResult)
+Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ObjectPtr& theObj)
 {
   Handle(AIS_InteractiveObject) aPrs;
 
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObj);
   if (aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID()) {
-    aPrs = new PartSet_ResultSketchPrs(theResult);
+    ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObj);
+    if (aResult.get())
+      aPrs = new PartSet_ResultSketchPrs(aResult);
   }
   return aPrs;
 }
@@ -961,6 +987,8 @@ bool PartSet_SketcherMgr::isEntity(const std::string& theId)
          (theId == SketchPlugin_Arc::ID()) ||
          (theId == SketchPlugin_Circle::ID()) ||
          (theId == SketchPlugin_Ellipse::ID()) ||
+         (theId == SketchPlugin_Projection::ID()) ||
+         (theId == SketchPlugin_IntersectionPoint::ID()) ||
          (theId == SketchPlugin_EllipticArc::ID());
 }
 
@@ -991,6 +1019,9 @@ bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)
 
 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
 {
+  static Events_ID EVENT_ATTR = Events_Loop::loop()->eventByName(EVENT_VISUAL_ATTRIBUTES);
+  static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                (getCurrentOperation());
   if (!aFOperation)
@@ -1063,7 +1094,6 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   myModule->overconstraintListener()->setActive(true);
   // Display sketcher objects
   QStringList anInfo;
-  Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
   const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
   aNumberOfSubs = myCurrentSketch->numberOfSubs();
   for (int i = 0; i < aNumberOfSubs; i++) {
@@ -1084,6 +1114,7 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
       aECreator->sendUpdated(aFeature, EVENT_DISP);
     else
       aFeature->setDisplayed(true);
+    aECreator->sendUpdated(aFeature, EVENT_ATTR);
   }
 #ifdef DEBUG_SKETCHER_ENTITIES
   QString anInfoStr = anInfo.join(";\t");
@@ -1100,7 +1131,8 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   workshop()->selectionActivate()->updateSelectionFilters();
   workshop()->selectionActivate()->updateSelectionModes();
 
-  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+  Events_Loop::loop()->flush(EVENT_DISP);
+  Events_Loop::loop()->flush(EVENT_ATTR);
 
   myExternalPointsMgr = new PartSet_ExternalPointsMgr(myModule->workshop(), myCurrentSketch);
 
@@ -1184,18 +1216,18 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   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));
-#ifdef DEBUG_CURSOR
-      qDebug("startNestedSketch() : Qt::CrossCursor");
-#endif
-    }
-  }
-}
+//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));
+//#ifdef DEBUG_CURSOR
+//      qDebug("startNestedSketch() : Qt::CrossCursor");
+//#endif
+//    }
+//  }
+//}
 
 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
 {
@@ -1203,7 +1235,7 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
   operationMgr()->onValidateOperation();
   // when sketch nested operation is stopped the cursor should be restored unconditionally
   //if (canChangeCursor(theOperation)) {
-    QApplication::restoreOverrideCursor();
+    //QApplication::restoreOverrideCursor();
 #ifdef DEBUG_CURSOR
     qDebug("stopNestedSketch() : None");
 #endif
@@ -1542,17 +1574,19 @@ const QMap<PartSet_Tools::ConstraintVisibleState, bool>& PartSet_SketcherMgr::sh
 
 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
 {
-  bool isFoundObject = false;
-
+  if (!myCurrentSketch.get())
+    return false;
   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
   if (anObjectFeature.get()) {
     int aSize = myCurrentSketch->numberOfSubs();
-    for (int i = 0; i < aSize && !isFoundObject; i++) {
-      FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);
-      isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;
+    FeaturePtr aCurrentFeature;
+    for (int i = 0; i < aSize; i++) {
+      aCurrentFeature = myCurrentSketch->subFeature(i);
+      if (myCurrentSketch->subFeature(i) == anObjectFeature)
+        return true;
     }
   }
-  return isFoundObject;
+  return false;
 }
 
 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePlane)
@@ -1775,26 +1809,26 @@ void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
   }
 }
 
-void PartSet_SketcherMgr::customizePresentation(const ObjectPtr& theObject)
-{
-  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                                           (getCurrentOperation());
-  if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
-                      isNestedSketchOperation(aFOperation)))
-    SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
-
-  // update entities selection priorities
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
-  if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
-    // update priority for feature
-    updateSelectionPriority(aFeature, aFeature);
-    // update priority for results of the feature
-    std::list<ResultPtr> aResults = aFeature->results();
-    std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();
-    for (; anIt != aLastIt; anIt++)
-      updateSelectionPriority(*anIt, aFeature);
-  }
-}
+//void PartSet_SketcherMgr::customisePresentation(const ObjectPtr& theObject)
+//{
+//  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+//                                                                           (getCurrentOperation());
+//  if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
+//                      isNestedSketchOperation(aFOperation)))
+//    SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
+//
+//  // update entities selection priorities
+//  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+//  if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
+//    // update priority for feature
+//    updateSelectionPriority(aFeature, aFeature);
+//    // update priority for results of the feature
+//    std::list<ResultPtr> aResults = aFeature->results();
+//    std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();
+//    for (; anIt != aLastIt; anIt++)
+//      updateSelectionPriority(*anIt, aFeature);
+//  }
+//}
 
 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
 {
@@ -1985,6 +2019,8 @@ void PartSet_SketcherMgr::updateBySketchParameters(
       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]);
         Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
         PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
       }
@@ -2114,7 +2150,161 @@ void PartSet_SketcherMgr::onShowPoints(bool toShow)
     aViewer->update();
 }
 
+void PartSet_SketcherMgr::processEvent(const std::shared_ptr<Events_Message>& theMessage)
+{
+  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOF_OBJECTS)) {
+    std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+      std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    std::set<ObjectPtr> aObjects = anUpdateMsg->objects();
+    std::set<ObjectPtr>::const_iterator aIt;
+    QList<ModuleBase_ViewerPrsPtr> aPrsList;
+    for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aIt);
+      if (aFeature.get()) {
+        std::list<ResultPtr> aRes = aFeature->results();
+        std::list<ResultPtr>::const_iterator aIt;
+        for (aIt = aRes.cbegin(); aIt != aRes.cend(); ++aIt) {
+          ModuleBase_ViewerPrsPtr aPrsPtr(new ModuleBase_ViewerPrs(*aIt));
+          aPrsList.append(aPrsPtr);
+        }
+      }
+    }
+    if (aPrsList.size() > 0) {
+      myModule->workshop()->setSelected(aPrsList);
+    }
+  }
+}
+
+bool isExternal(const ObjectPtr& theObject)
+{
+  AttributeSelectionPtr aAttr =
+    theObject->data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
+  if (aAttr)
+    return aAttr->context().get() != NULL && !aAttr->isInvalid();
+  return false;
+}
+
+bool isCopy(const ObjectPtr& theObject)
+{
+  AttributeBooleanPtr anAttr = theObject->data()->boolean(SketchPlugin_SketchEntity::COPY_ID());
+  if (anAttr.get())
+    return anAttr->value();
+  return false;
+}
+
+bool isIncludeToResult(const ObjectPtr& theObject)
+{
+  AttributeBooleanPtr anAttr;
+  std::set<AttributePtr> aRefsToMe = theObject->data()->refsToMe();
+  std::set<AttributePtr>::const_iterator aIt;
+  for (aIt = aRefsToMe.cbegin(); aIt != aRefsToMe.cend(); ++aIt) {
+    if ((*aIt)->id() == SketchPlugin_Projection::PROJECTED_FEATURE_ID()) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
+      if (aFeature.get()) {
+        anAttr = aFeature->data()->boolean(SketchPlugin_Projection::INCLUDE_INTO_RESULT());
+        if (anAttr.get())
+          return anAttr->value();
+      }
+    }
+  }
+  return true;
+}
+
+//**************************************************************************************
+std::vector<int> PartSet_SketcherMgr::colorOfObject(const ObjectPtr& theObject,
+  const FeaturePtr& theFeature, bool isConstruction) const
+{
+  static const QStringList& aConstrIds = constraintsIdList();
+  PartSet_OverconstraintListener* aOCListener = myModule->overconstraintListener();
+  std::string aKind = theFeature->getKind();
+
+  if (isDistanceKind(aKind)) {
+    if (aOCListener->isConflictingObject(theObject))
+      return Config_PropManager::color("Visualization", "sketch_overconstraint_color");
+    return Config_PropManager::color("Visualization", "sketch_dimension_color");
+  }
+  if (isExternal(theFeature))
+    return Config_PropManager::color("Visualization", "sketch_external_color");
+  if (isConstruction)
+    return Config_PropManager::color("Visualization", "sketch_auxiliary_color");
+
+  if (aOCListener->isFullyConstrained()) {
+    return Config_PropManager::color("Visualization", "sketch_fully_constrained_color");
+  }
+  else if (aOCListener->isConflictingObject(theObject)) {
+    return Config_PropManager::color("Visualization", "sketch_overconstraint_color");
+  }
+  return Config_PropManager::color("Visualization", "sketch_entity_color");
+}
+
+//**************************************************************************************
+void PartSet_SketcherMgr::customizeSketchPresentation(const ObjectPtr& theObject,
+  const AISObjectPtr& thePrs) const
+{
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+
+  // set color from preferences
+  std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
+    aFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
+  bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
+
+  std::vector<int> aColor = colorOfObject(theObject, aFeature, isConstruction);
+  if (!aColor.empty()) {
+    // The code below causes redisplay again
+    if (ModelAPI_Session::get()->isOperation()) {
+      AttributeIntArrayPtr aColorAttr = theObject->data()->intArray(ModelAPI_Result::COLOR_ID());
+      if (aColorAttr.get()) {
+        aColorAttr->setSize(3, false);
+        // Set the color attribute in order do not use default colors in the presentation object
+        for (int i = 0; i < 3; i++)
+          aColorAttr->setValue(i, aColor[i], false);
+      }
+    }
+    thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+  }
+
+  int aShapeType = thePrs->getShapeType();
+  // a compound is processed like the edge because the
+  // arc feature uses the compound for presentable AIS
+  if (aShapeType != 6/*an edge*/ && aShapeType != 7/*a vertex*/ && aShapeType != 0/*compound*/)
+    return;
+
+  if (isExternal(aFeature)) {
+    thePrs->setWidth(1);
+    return;
+  }
+  std::string aKind = aFeature->getKind();
+  if (isDistanceKind(aKind))
+    return;
+
+  if (aShapeType == 6 || aShapeType == 0) { // if this is an edge or a compound
+    if (isConstruction) {
+      // Set axilliary line
+      thePrs->setWidth(SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY());
+      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());
+    }
+  }
+  else if (aShapeType == 7) { // otherwise this is a vertex
+                              // The width value do not have effect on the point presentation.
+                              // It is defined in order to extend selection area of the object.
+    thePrs->setWidth(17);
+    //  thePrs->setPointMarker(1, 1.); // Set point as a '+' symbol
+  }
+  if (isCopy(aFeature) && !isIncludeToResult(aFeature)) {
+    double aWidth = thePrs->width();
+    thePrs->setWidth(aWidth / 2.5);
+  }
+
+  double aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
+  thePrs->setDeflection(aDeflection);
+}
 
+//*************************************************************************************
 void PartSet_Fitter::fitAll(Handle(V3d_View) theView)
 {
   CompositeFeaturePtr aSketch = mySketchMgr->activeSketch();
index 7259514a4eb54083d520cf7e8863bc929d96a348..20ee6e6594dee9e42b0466dc1960b8c49021bc92 100644 (file)
 #include <ModelAPI_Attribute.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_Result.h>
+#include <Events_Listener.h>
 #include <ModuleBase_SelectionFilterType.h>
 
 #include <ModuleBase_Definitions.h>
 #include <ModuleBase_ModelWidget.h>
 
 #include <GeomAPI_Pln.h>
+#include <GeomAPI_AISObject.h>
 
 #ifdef HAVE_SALOME
   #include <OCCViewer_ViewModel.h>
@@ -97,7 +99,7 @@ private:
   displayed in the viewer. After the sketch create/edit operation is finished, the sub-feature
   are hidden, the sketch feature result is displayed
 */
-class PARTSET_EXPORT PartSet_SketcherMgr : public QObject
+class PARTSET_EXPORT PartSet_SketcherMgr : public QObject, public Events_Listener
 {
   Q_OBJECT
   /// Struct to define gp point, with the state is the point is initialized
@@ -217,7 +219,7 @@ public:
 
   /// 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
@@ -343,7 +345,7 @@ public:
   /// Create specific for the module presentation
   /// \param theResult an object for presentation
   /// \return created presentation or NULL(default value)
-  virtual Handle(AIS_InteractiveObject) createPresentation(const ResultPtr& theResult);
+  Handle(AIS_InteractiveObject) createPresentation(const ObjectPtr& theResult);
 
   /// Connects or disconnects to the value changed signal of the property panel widgets
   /// \param theWidget a property contol widget
@@ -357,7 +359,9 @@ public:
   /// If the current operation is a dimention one, the style of dimension visualization is send for
   /// the current object
   /// \param theObject an object to be customized
-  void customizePresentation(const ObjectPtr& theObject);
+  //void customisePresentation(const ObjectPtr& theObject);
+
+  void customizeSketchPresentation(const ObjectPtr& theObject, const AISObjectPtr& thePrs) const;
 
   /// Update sketch presentations according to the the state
   /// \param theType a type of sketch visualization style
@@ -371,6 +375,12 @@ public:
 
   PartSet_Module* module() const { return myModule; }
 
+  /** \brief Implementation of Event Listener method
+  *  \param[in] theMessage the data of the event
+  */
+  virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+
 public slots:
   /// Process sketch plane selected event
   void onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln);
@@ -467,6 +477,9 @@ private:
   /// Returns operation manager
   XGUI_OperationMgr* operationMgr() const;
 
+  std::vector<int> colorOfObject(const ObjectPtr& theObject,
+    const FeaturePtr& aFeature, bool isConstruction) const;
+
 private:
   PartSet_Module* myModule;
   PartSet_PreviewSketchPlane* mySketchPlane; // display/erase sketch plane on start/stop sketch
index 0ff7ad2e55b19e5261693d46cafb631bbd7d8343..fbb50228faf57290a384d347d72b2e8b0b0dffec 100644 (file)
@@ -36,6 +36,7 @@
 #include <ModelGeomAlgo_Point2D.h>
 
 #include <Events_Loop.h>
+#include <Events_InfoMessage.h>
 
 #include <SketcherPrs_Tools.h>
 
@@ -53,6 +54,7 @@
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Vertex.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <GeomAPI_Dir.h>
 #include <GeomAPI_XYZ.h>
@@ -794,3 +796,58 @@ void PartSet_Tools::getFirstAndLastIndexInFolder(const ObjectPtr& theFolder,
   theFirst = aDoc->index(aFirstFeatureInFolder);
   theLast = aDoc->index(aLastFeatureInFolder);
 }
+
+
+void PartSet_Tools::getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
+  std::vector<int>& theColor)
+{
+  theColor.clear();
+  // get default color from the preferences manager for the given result
+  if (theColor.empty()) {
+    std::string aSection, aName, aDefault;
+    theObject->colorConfigInfo(aSection, aName, aDefault);
+    if (!aSection.empty() && !aName.empty()) {
+      theColor = Config_PropManager::color(aSection, aName);
+    }
+  }
+  if (!isEmptyColorValid && theColor.empty()) {
+    // all AIS objects, where the color is not set, are in black.
+    // The color should be defined in XML or set in the attribute
+    theColor = Config_PropManager::color("Visualization", "object_default_color");
+    Events_InfoMessage("PartSet_Tools",
+      "A default color is not defined in the preferences for this result type").send();
+  }
+}
+
+double PartSet_Tools::getDefaultDeflection(const ObjectPtr& theObject)
+{
+  double aDeflection = -1;
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (aResult.get()) {
+    bool isConstruction = false;
+
+    std::string aResultGroup = aResult->groupName();
+    if (aResultGroup == ModelAPI_ResultConstruction::group())
+      isConstruction = true;
+    else if (aResultGroup == ModelAPI_ResultBody::group()) {
+      GeomShapePtr aGeomShape = aResult->shape();
+      if (aGeomShape.get()) {
+        // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
+        // correction of deviation for them should not influence to the application performance
+        GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE);
+        isConstruction = !anExp.more();
+      }
+    }
+    if (isConstruction)
+      aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
+    else
+      aDeflection = Config_PropManager::real("Visualization", "body_deflection");
+  }
+  return aDeflection;
+}
+
+
+double PartSet_Tools::getDefaultTransparency()
+{
+  return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
+}
index 0de36c1e24af8ca322a21f3a310043065f64f8ca..7f1c236abb474dc25a51394062dce820cc262cfe 100644 (file)
@@ -297,7 +297,26 @@ public:
                                                FeaturePtr& theCreatedFeature);
 
 
-  static void getFirstAndLastIndexInFolder(const ObjectPtr& theFolder, int& theFirst, int& theLast);
+  static void getFirstAndLastIndexInFolder(const ObjectPtr& theFolder,
+    int& theFirst, int& theLast);
+
+
+  /**
+  * Returns default color value for the given object
+  */
+  static void getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
+    std::vector<int>& theColor);
+
+  /**
+  * Returns default deflection value for the given object
+  */
+  static double getDefaultDeflection(const ObjectPtr& theObject);
+
+
+  /**
+  * Returns default transparency value
+  */
+  static double getDefaultTransparency();
 };
 
 #endif
index f44ca020954120fcca6e350e97f48e3fe0d9514a..7b5aff07db9500f3c91859e0433dc260a255222c 100644 (file)
@@ -30,6 +30,7 @@
 #include <ModuleBase_ISelection.h>
 #include <ModuleBase_ViewerPrs.h>
 
+#include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeReference.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_Feature.h>
@@ -66,10 +67,14 @@ PartSet_WidgetFeaturePointSelector::PartSet_WidgetFeaturePointSelector(QWidget*
   std::string anAttributes = theData->getProperty("selection_attributes");
   QStringList anAttributesList = QString(anAttributes.c_str()).split(' ', QString::SkipEmptyParts);
 
+  myHasPreview = anAttributesList.size() >= 4;
+
   mySelectedObjectAttribute = anAttributesList[0].toStdString();
   mySelectedPointAttribute = anAttributesList[1].toStdString();
-  myPreviewObjectAttribute = anAttributesList[2].toStdString();
-  myPreviewPointAttribute = anAttributesList[3].toStdString();
+  if (myHasPreview) {
+    myPreviewObjectAttribute = anAttributesList[2].toStdString();
+    myPreviewPointAttribute = anAttributesList[3].toStdString();
+  }
 }
 
 PartSet_WidgetFeaturePointSelector::~PartSet_WidgetFeaturePointSelector()
@@ -150,27 +155,42 @@ void PartSet_WidgetFeaturePointSelector::mouseReleased(ModuleBase_IViewWindow* t
   if (theEvent->button() != Qt::LeftButton)
     return;
 
-  std::shared_ptr<ModelAPI_AttributeReference> aRefPreviewAttr =
-                          std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                          feature()->data()->attribute(myPreviewObjectAttribute));
-  ObjectPtr aPreviewObject = aRefPreviewAttr->value();
+  ObjectPtr aPreviewObject;
+  GeomPnt2dPtr aPreviewPoint;
+  if (myHasPreview) {
+    std::shared_ptr<ModelAPI_AttributeReference> aRefPreviewAttr =
+                            std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
+                            feature()->data()->attribute(myPreviewObjectAttribute));
+    aPreviewObject = aRefPreviewAttr->value();
+
+    std::shared_ptr<GeomDataAPI_Point2D> aPointPreviewAttr =
+                            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                            feature()->data()->attribute(myPreviewPointAttribute));
+    aPreviewPoint = aPointPreviewAttr->pnt();
+  }
+  else {
+    aPreviewObject = myPreviewObject;
+    aPreviewPoint = myPreviewPoint;
+  }
+
   // do not move focus from the current widget if the object is not highlighted/selected
   if (!aPreviewObject.get())
     return;
 
   // set parameters of preview into parameters of selection in the feature
-  std::shared_ptr<ModelAPI_AttributeReference> aRefSelectedAttr =
-                          std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                          feature()->data()->attribute(mySelectedObjectAttribute));
-  aRefSelectedAttr->setValue(aRefPreviewAttr->value());
-
   std::shared_ptr<GeomDataAPI_Point2D> aPointSelectedAttr =
                           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
                           feature()->data()->attribute(mySelectedPointAttribute));
-  std::shared_ptr<GeomDataAPI_Point2D> aPointPreviewAttr =
-                          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                          feature()->data()->attribute(myPreviewPointAttribute));
-  aPointSelectedAttr->setValue(aPointPreviewAttr->x(), aPointPreviewAttr->y());
+  aPointSelectedAttr->setValue(aPreviewPoint);
+
+  AttributeReferencePtr aRefSelectedAttr = feature()->reference(mySelectedObjectAttribute);
+  if (aRefSelectedAttr)
+    aRefSelectedAttr->setValue(aPreviewObject);
+  else {
+    AttributeRefAttrPtr aRefAttrSelectedAttr = feature()->refattr(mySelectedObjectAttribute);
+    if (aRefAttrSelectedAttr)
+      aRefAttrSelectedAttr->setObject(aPreviewObject);
+  }
 
   updateObject(feature());
 
@@ -189,20 +209,21 @@ bool PartSet_WidgetFeaturePointSelector::fillFeature(
                             QMouseEvent* theEvent)
 {
   bool aFilled = false;
-  ObjectPtr anObject;
   if (theSelectedPrs.get() && theSelectedPrs->object().get())
-    anObject = theSelectedPrs->object();
-
-  std::shared_ptr<ModelAPI_AttributeReference> aRef =
-                          std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                          feature()->data()->attribute(myPreviewObjectAttribute));
-  aRef->setValue(anObject);
-
-  std::shared_ptr<GeomDataAPI_Point2D> anAttributePoint =
-                  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                  feature()->data()->attribute(myPreviewPointAttribute));
-  std::shared_ptr<GeomAPI_Pnt2d> aPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
-  anAttributePoint->setValue(aPoint);
+    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);
+  }
   // redisplay AIS presentation in viewer
 #ifndef HIGHLIGHT_STAYS_PROBLEM
   // an attempt to clear highlighted item in the viewer: but of OCCT
index 818253f4e43befa60e2fdfc4f63813d0e4adcfa1..972b30ede1e581a4ac69090b2e3aa3a25fd2fe83 100644 (file)
@@ -38,6 +38,7 @@ class ModuleBase_IViewWindow;
 class ModuleBase_ViewerPrs;
 
 class GeomAPI_Pnt;
+class GeomAPI_Pnt2d;
 class GeomDataAPI_Point2D;
 
 class QWidget;
@@ -132,6 +133,10 @@ protected:
   std::string mySelectedPointAttribute;
   std::string myPreviewObjectAttribute;
   std::string myPreviewPointAttribute;
+
+  bool myHasPreview;
+  std::shared_ptr<ModelAPI_Object> myPreviewObject;
+  std::shared_ptr<GeomAPI_Pnt2d>   myPreviewPoint;
 };
 
 #endif
\ No newline at end of file
index f4a880abf6a73a06673de76f797af8302c487f47..0e32b02850471f4c180c7ce07a36e824f3e526ce 100644 (file)
@@ -83,6 +83,9 @@ public:
   /// \return a boolean value
   virtual bool isValidSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
 
+  /// Returns True in case if the widget contains useful information for inspection tool
+  virtual bool isInformative() const { return false; }
+
 protected:
   /// If there is no operation in current session, start operation for modify parameters
   /// \return true if the operation was not opened
index 0dde98c1cd3e6756726da8dd72d136848cef31d9..0a14abf97dc356d03dd68d6a76c81ebb34ad22d4 100644 (file)
@@ -38,6 +38,7 @@
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Events.h>
 
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <QCheckBox>
 #include <QGroupBox>
 #include <QPushButton>
-#include <QStackedWidget>
 #include <QLineEdit>
 #include <QDoubleValidator>
+#include <QDialog>
+#include <QTimer>
 
 #ifndef DBL_MAX
 #define DBL_MAX 1.7976931348623158e+308
@@ -112,6 +114,23 @@ myIsSelection(false)
   mySizeOfView->setValidator(aValidator);
   aSizeLayout->addWidget(mySizeOfView);
 
+  myPartSetMessage = new QDialog(this, Qt::ToolTip);
+  myPartSetMessage->setModal(false);
+  myPartSetMessage->setStyleSheet("background-color:lightyellow;");
+  QVBoxLayout* aMsgLay = new QVBoxLayout(myPartSetMessage);
+  QString aMsg = tr("The Sketch is created in PartSet.\n"
+    "It will be necessary to create a Part in order to use this sketch for body creation");
+  aMsgLay->addWidget(new QLabel(aMsg, myPartSetMessage));
+  myPartSetMessage->hide();
+
+  mySizeMessage = new QDialog(mySizeOfView, Qt::ToolTip);
+  mySizeMessage->setModal(false);
+  mySizeMessage->setStyleSheet("background-color:lightyellow;");
+  aMsgLay = new QVBoxLayout(mySizeMessage);
+  aMsg = tr("A size of Sketch view can be defined here.");
+  aMsgLay->addWidget(new QLabel(aMsg, mySizeMessage));
+  mySizeMessage->hide();
+
   QString aText = translate(theData->getProperty("title"));
   QLabel* aLabel = new QLabel(aText, aFirstWgt);
   aLabel->setWordWrap(true);
@@ -182,9 +201,16 @@ myIsSelection(false)
   connect(aPlaneBtn, SIGNAL(clicked(bool)), SLOT(onChangePlane()));
   aLayout->addWidget(aPlaneBtn);
 
+  aLayout->addSpacing(15);
+
   myDoFLabel = new QLabel("", aSecondWgt);
   aLayout->addWidget(myDoFLabel);
 
+  myShowDOFBtn = new QPushButton(tr("Show remaining DoFs"), aSecondWgt);
+  aLayout->addWidget(myShowDOFBtn);
+  myShowDOFBtn->setEnabled(false);
+  connect(myShowDOFBtn, SIGNAL(clicked(bool)), SLOT(onShowDOF()));
+
   myStackWidget->addWidget(aSecondWgt);
   //setLayout(aLayout);
 
@@ -309,6 +335,10 @@ void PartSet_WidgetSketchLabel::updateByPlaneSelected(const ModuleBase_ViewerPrs
   GeomPlanePtr aPlane = plane();
   if (!aPlane.get())
     return;
+
+  myPartSetMessage->hide();
+  mySizeMessage->hide();
+
   // 1. hide main planes if they have been displayed and display sketch preview plane
   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
 
@@ -548,6 +578,27 @@ void PartSet_WidgetSketchLabel::activateCustom()
     mySizeOfViewWidget->setVisible(false);
 }
 
+void PartSet_WidgetSketchLabel::showEvent(QShowEvent* theEvent)
+{
+  ModuleBase_WidgetValidated::showEvent(theEvent);
+  QTimer::singleShot(10, this, SLOT(onShowPanel()));
+}
+
+void PartSet_WidgetSketchLabel::onShowPanel()
+{
+  if (mySizeOfViewWidget->isVisible()) {
+    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();
+  }
+}
+
 void PartSet_WidgetSketchLabel::deactivate()
 {
   ModuleBase_WidgetValidated::deactivate();
@@ -752,14 +803,29 @@ bool PartSet_WidgetSketchLabel::restoreValueCustom()
         int aDoF = aVal.toInt();
         if (aDoF == 0) {
           myDoFLabel->setText(tr("Sketch is fully fixed (DoF = 0)"));
+          myShowDOFBtn->setEnabled(false);
         } else {
           myDoFLabel->setText(tr("DoF (degrees of freedom) = ") + aVal);
+          myShowDOFBtn->setEnabled(true);
         }
       }
     }
     else {
       myDoFLabel->setText("");
+      myShowDOFBtn->setEnabled(false);
     }
   }
   return true;
 }
+
+
+void PartSet_WidgetSketchLabel::onShowDOF()
+{
+  CompositeFeaturePtr aCompFeature =
+    std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
+  if (aCompFeature.get()) {
+    static const Events_ID anEvent = Events_Loop::eventByName(EVENT_GET_DOF_OBJECTS);
+    ModelAPI_EventCreator::get()->sendUpdated(aCompFeature, anEvent);
+    Events_Loop::loop()->flush(anEvent);
+  }
+}
index fe9c147160014b099b18171cdc48c911ffdfcd06..ba5c2bb50185909acf9f1e81bb5950cdd459a628 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <TopoDS_Shape.hxx>
 
+#include <QStackedWidget>
 #include <QMap>
 
 class PartSet_PreviewPlanes;
@@ -41,6 +42,8 @@ class XGUI_Workshop;
 class QCheckBox;
 class QStackedWidget;
 class QLineEdit;
+class QPushButton;
+class QDialog;
 
 /**
 * \ingroup Modules
@@ -109,6 +112,12 @@ public:
   /// \param thePrs a presentation
   static bool canFillSketch(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
 
+  /// If widgets has several panels then this method has to show a page which contains information
+  /// for current feature. By default does nothing
+  virtual void showInformativePage() {
+    if (myStackWidget) myStackWidget->setCurrentIndex(1);
+  }
+
 signals:
   /// Signal on plane selection
   void planeSelected(const std::shared_ptr<GeomAPI_Pln>& thePln);
@@ -193,6 +202,9 @@ protected:
   /// \param thePrs a presentation
   bool fillSketchPlaneBySelection(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
 
+
+  virtual void showEvent(QShowEvent* theEvent);
+
 private slots:
   /// A slot called on set sketch plane view
   void onSetPlaneView();
@@ -203,6 +215,10 @@ private slots:
 
   void onChangePlane();
 
+  void onShowDOF();
+
+  void onShowPanel();
+
 private:
   /// Set sketch plane by shape
   /// \param theShape a planar face
@@ -235,9 +251,13 @@ private:
   QStackedWidget* myStackWidget;
 
   QLabel* myDoFLabel;
+  QPushButton* myShowDOFBtn;
 
   bool myOpenTransaction;
   bool myIsSelection;
+
+  QDialog* myPartSetMessage;
+  QDialog* mySizeMessage;
 };
 
 #endif
diff --git a/src/PartSet/PartSet_msg_fr.ts b/src/PartSet/PartSet_msg_fr.ts
new file mode 100644 (file)
index 0000000..2bb1a66
--- /dev/null
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+    <name>PartSet_MenuMgr</name>
+    <message>
+        <source>Auxiliary</source>
+        <translation>Auxiliaire</translation>
+    </message>
+    <message>
+        <source>Activate</source>
+        <translation>Activer</translation>
+    </message>
+    <message>
+        <source>Edit...</source>
+        <translation>Modifier...</translation>
+    </message>
+    <message>
+        <source>Detach</source>
+        <translation>Détacher</translation>
+    </message>
+    <message>
+        <source>Detach %1</source>
+        <translation>Détachez %1</translation>
+    </message>
+</context>
+<context>
+    <name>PartSet_WidgetPoint2D</name>
+    <message>
+        <source>X</source>
+        <translation>X</translation>
+    </message>
+    <message>
+        <source>Y</source>
+        <translation>Y</translation>
+    </message>
+</context>
+<context>
+    <name>PartSet_WidgetSketchCreator</name>
+    <message>
+        <source>Size of the view</source>
+        <translation>Taille de la vue</translation>
+    </message>
+    <message>
+        <source>Apply current feature</source>
+        <translation>Appliquer la fonctionnalité actuelle</translation>
+    </message>
+    <message>
+        <source>Sketch is invalid and will be deleted.
+Error: %1</source>
+        <translation>L&apos;esquisse n&apos;est pas valide et sera supprimée.
+Erreur : %1</translation>
+    </message>
+</context>
+<context>
+    <name>PartSet_WidgetSketchLabel</name>
+    <message>
+        <source>Size of the view</source>
+        <translation>Taille de la vue</translation>
+    </message>
+    <message>
+        <source>Remove external dependencies</source>
+        <translation>Supprimer les dépendances externes</translation>
+    </message>
+    <message>
+        <source>Sketcher plane</source>
+        <translation>Plan du Sketcher</translation>
+    </message>
+    <message>
+        <source>Reversed</source>
+        <translation>Renversé</translation>
+    </message>
+    <message>
+        <source>Set plane view</source>
+        <translation>Définir la vue plane</translation>
+    </message>
+    <message>
+        <source>Show geometrical constraints</source>
+        <translation>Afficher les contraintes géométriques</translation>
+    </message>
+    <message>
+        <source>Show dimensional constraints</source>
+        <translation>Afficher les contraintes dimensionnelles</translation>
+    </message>
+    <message>
+        <source>Show existing expressions</source>
+        <translation>Afficher les expressions existantes</translation>
+    </message>
+    <message>
+        <source>Show free points</source>
+        <translation>Afficher les points libres</translation>
+    </message>
+    <message>
+        <source>Automatic constraints</source>
+        <translation>Contraintes automatiques</translation>
+    </message>
+    <message>
+        <source>Automatic vertical and horizontal constraints</source>
+        <translation>Automatique des contraintes verticales et horizontales</translation>
+    </message>
+    <message>
+        <source>Change sketch plane</source>
+        <translation>Changer le plan d&apos;esquisse</translation>
+    </message>
+    <message>
+        <source>Sketch is fully fixed (DoF = 0)</source>
+        <translation>L&apos;esquisse est entièrement fixée (DdL = 0)</translation>
+    </message>
+    <message>
+        <source>DoF (degrees of freedom) = </source>
+        <translation>DdL (degrés de liberté) = </translation>
+    </message>
+    <message>
+        <source>Show remaining DoFs</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>Parameters</source>
+        <translation>Paramètres</translation>
+    </message>
+    <message>
+        <source>Constructions</source>
+        <translation>Constructions</translation>
+    </message>
+    <message>
+        <source>Parts</source>
+        <translation>Pièces</translation>
+    </message>
+    <message>
+        <source>Results</source>
+        <translation>Résultats</translation>
+    </message>
+    <message>
+        <source>Fields</source>
+        <translation>Champs</translation>
+    </message>
+    <message>
+        <source>Groups</source>
+        <translation>Groupes</translation>
+    </message>
+</context>
+</TS>
index 068f1781b4face1367945f2b1858fcf258191dbd..9b3079ba32f5f97bceafc82e75bae368bf07ae22 100644 (file)
@@ -39,7 +39,7 @@ SET(XML_RESOURCES
 )
 
 SET(TEXT_RESOURCES
-#    PartSetPlugin_msg_fr.ts
+    PartSetPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
diff --git a/src/PartSetPlugin/PartSetPlugin_msg_fr.ts b/src/PartSetPlugin/PartSetPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..2e5579c
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Part</source>
+      <translation>Pièce</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Duplicate</name>
+    <message>
+      <source>Duplicate active part</source>
+      <translation>Dupliquer la pièce active</translation>
+    </message>
+    <message>
+      <source>Duplicate part</source>
+      <translation>Dupliquer pièce</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Part</name>
+    <message>
+      <source>Create part</source>
+      <translation>Créer une pièce</translation>
+    </message>
+    <message>
+      <source>New part</source>
+      <translation>Nouvelle pièce</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Remove</name>
+    <message>
+      <source>Remove active part</source>
+      <translation>Supprimer la pièce active</translation>
+    </message>
+    <message>
+      <source>Remove part</source>
+      <translation>Supprimer une partie</translation>
+    </message>
+  </context>
+
+</TS>
index 244061636257a252dcf9b87a9bf89ba7f5d99e8d..abc07fbac28a56c08e93093c374c84372768d538 100644 (file)
@@ -46,7 +46,7 @@ SET(XML_RESOURCES
 )
 
 SET(TEXT_RESOURCES
-#    PrimitivesPlugin_msg_fr.ts
+    PrimitivesPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_msg_fr.ts b/src/PrimitivesPlugin/PrimitivesPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..d53345e
--- /dev/null
@@ -0,0 +1,388 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Primitives</source>
+      <translation>Primitives</translation>
+    </message>
+    <message>
+      <source>Box</source>
+      <translation>Boîte</translation>
+    </message>
+    <message>
+      <source>Cone</source>
+      <translation>Cône</translation>
+    </message>
+    <message>
+      <source>Cylinder</source>
+      <translation>Cylindre</translation>
+    </message>
+    <message>
+      <source>Sphere</source>
+      <translation>Sphère</translation>
+    </message>
+    <message>
+      <source>Torus</source>
+      <translation>Tore</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Box</name>
+    <message>
+      <source>Box</source>
+      <translation>Boîte</translation>
+    </message>
+    <message>
+      <source>Create a box</source>
+      <translation>Créer une boîte</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:CreationMethod</name>
+    <message>
+      <source>By dimensions</source>
+      <translation>Par dimensions</translation>
+    </message>
+    <message>
+      <source>By two points</source>
+      <translation>Par deux points</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:FirstPoint</name>
+    <message>
+      <source>First point</source>
+      <translation>Premier point</translation>
+    </message>
+    <message>
+      <source>Select a first point</source>
+      <translation>Sélectionnez un premier point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:FirstPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un premier point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:SecondPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un deuxième point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:SecondPoint</name>
+    <message>
+      <source>Second point</source>
+      <translation>Deuxième point</translation>
+    </message>
+    <message>
+      <source>Select a second point</source>
+      <translation>Sélectionnez un deuxième point</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:dx</name>
+    <message>
+      <source>DX</source>
+      <translation>DX</translation>
+    </message>
+    <message>
+      <source>Dimension in X</source>
+      <translation>Dimension en X</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:dy</name>
+    <message>
+      <source>DY</source>
+      <translation>DY</translation>
+    </message>
+    <message>
+      <source>Dimension in Y</source>
+      <translation>Dimension en Y</translation>
+    </message>
+  </context>
+  <context>
+    <name>Box:dz</name>
+    <message>
+      <source>DZ</source>
+      <translation>DZ</translation>
+    </message>
+    <message>
+      <source>Dimension in Z</source>
+      <translation>Dimension en Z</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Cone</name>
+    <message>
+      <source>Cone</source>
+      <translation>Cône</translation>
+    </message>
+    <message>
+      <source>Create a Cone</source>
+      <translation>Créer un cône</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:axis</name>
+    <message>
+      <source>Select the axis of the cone</source>
+      <translation>Sélectionnez l&apos;axe du cône</translation>
+    </message>
+    <message>
+      <source>axis</source>
+      <translation>axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:base_point</name>
+    <message>
+      <source>Select the center of the base of the cone</source>
+      <translation>Sélectionnez le centre de la base du cône</translation>
+    </message>
+    <message>
+      <source>base_point</source>
+      <translation>point de base</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:base_radius</name>
+    <message>
+      <source>Base radius</source>
+      <translation>Rayon de la base</translation>
+    </message>
+    <message>
+      <source>Enter the base radius of the cone</source>
+      <translation>Entrez le rayon de base du cône</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:height</name>
+    <message>
+      <source>Enter the height of the cone</source>
+      <translation>Entrez la hauteur du cône</translation>
+    </message>
+    <message>
+      <source>height</source>
+      <translation>hauteur</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:top_radius</name>
+    <message>
+      <source>Enter the top radius of the cone</source>
+      <translation>Entrez le rayon supérieur du cône</translation>
+    </message>
+    <message>
+      <source>Top radius</source>
+      <translation>Rayon supérieur</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:base_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le centre de la base du cône.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cone:base_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Cylinder</name>
+    <message>
+      <source>Create a cylinder</source>
+      <translation>Créer un cylindre</translation>
+    </message>
+    <message>
+      <source>Cylinder</source>
+      <translation>Cylindre</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:CreationMethod</name>
+    <message>
+      <source>Cylinder</source>
+      <translation>Cylindre</translation>
+    </message>
+    <message>
+      <source>Portion of cylinder</source>
+      <translation>Portion de cylindre</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:angle</name>
+    <message>
+      <source>Enter the angle of the portion of the cylinder</source>
+      <translation>Entrez l&apos;angle de la portion du cylindre</translation>
+    </message>
+    <message>
+      <source>angle</source>
+      <translation>angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:axis</name>
+    <message>
+      <source>Select the axis of the cylinder</source>
+      <translation>Sélectionnez l&apos;axe du cylindre</translation>
+    </message>
+    <message>
+      <source>axis</source>
+      <translation>axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:base_point</name>
+    <message>
+      <source>Select the center of the base of the cylinder</source>
+      <translation>Sélectionnez le centre de la base du cylindre</translation>
+    </message>
+    <message>
+      <source>base_point</source>
+      <translation>point de base</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:height</name>
+    <message>
+      <source>Enter the height of the cylinder</source>
+      <translation>Entrez la hauteur du cylindre</translation>
+    </message>
+    <message>
+      <source>height</source>
+      <translation>hauteur</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:radius</name>
+    <message>
+      <source>Enter the radius of the cylinder</source>
+      <translation>Entrez le rayon du cylindre</translation>
+    </message>
+    <message>
+      <source>radius</source>
+      <translation>rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:base_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le centre de la base du cylindre.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Cylinder:base_point:GeomValidators_ConstructionComposite</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le résultat est vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Sphere</name>
+    <message>
+      <source>Create a sphere</source>
+      <translation>Créer une sphère</translation>
+    </message>
+    <message>
+      <source>Sphere</source>
+      <translation>Sphère</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sphere:center_point</name>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+    <message>
+      <source>Select a center point</source>
+      <translation>Sélectionnez un point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sphere:radius</name>
+    <message>
+      <source>Enter a radius</source>
+      <translation>Entrez un rayon</translation>
+    </message>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Torus</name>
+    <message>
+      <source>Create a Torus</source>
+      <translation>Créer un tore</translation>
+    </message>
+    <message>
+      <source>Torus</source>
+      <translation>Tore</translation>
+    </message>
+  </context>
+  <context>
+    <name>Torus:axis</name>
+    <message>
+      <source>Select the axis of the torus</source>
+      <translation>Sélectionnez l&apos;axe du tore</translation>
+    </message>
+    <message>
+      <source>axis</source>
+      <translation>axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>Torus:base_point</name>
+    <message>
+      <source>Select the center of the torus</source>
+      <translation>Sélectionnez le centre du tore</translation>
+    </message>
+    <message>
+      <source>base_point</source>
+      <translation>point de base</translation>
+    </message>
+  </context>
+  <context>
+    <name>Torus:radius</name>
+    <message>
+      <source>Enter the radius of the torus</source>
+      <translation>Entrez le rayon du tore</translation>
+    </message>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>Torus:ring_radius</name>
+    <message>
+      <source>Enter the ring radius of the torus</source>
+      <translation>Entrez le rayon de l&apos;anneau du tore</translation>
+    </message>
+    <message>
+      <source>Ring radius</source>
+      <translation>Rayon de l&apos;anneau</translation>
+    </message>
+  </context>
+
+</TS>
index 308e1e6f3929ba4b695a77e6065b8d0cd8ffa40d..5bd0d6c0b6cc60348c27786a3803a169112d49f3 100644 (file)
@@ -19,4 +19,7 @@
 """Package for Exchange plugin for the Parametric Geometry API of the Modeler.
 """
 
-from ExchangeAPI import addImport, exportToFile, exportToXAO
\ No newline at end of file
+from ExchangeAPI import addImport, exportToFile, exportToXAO
+from ExchangeAPI import exportPart, importPart
+
+from .tools import *
diff --git a/src/PythonAPI/model/exchange/tools.py b/src/PythonAPI/model/exchange/tools.py
new file mode 100644 (file)
index 0000000..a80db1b
--- /dev/null
@@ -0,0 +1,25 @@
+# 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
+#
+
+import os
+
+def removeFile(theFilename):
+    try: os.remove(theFilename)
+    except OSError: pass
+    assert not os.path.exists(theFilename), "Cannot remove file {}".format(theFilename)
index 2360f5844cbe26f3a5433bba857653654273183d..7bdfeb86c8ea13f32282eeaf4dbadb6b9b718e03 100644 (file)
@@ -64,7 +64,7 @@ SET(PROJECT_RESOURCES
 )
 
 SET(TEXT_RESOURCES
-#    SHAPERGUI_msg_fr.ts
+    SHAPERGUI_msg_fr.ts
 )
 
 IF (${UPDATE_TRANSLATION})
@@ -72,10 +72,12 @@ IF (${UPDATE_TRANSLATION})
     QT5_CREATE_TRANSLATION(QM_RESOURCES
                            ${PROJECT_FILES}
                            ${TEXT_RESOURCES}
-                           OPTIONS -extensions cpp -no-recursive
+                           OPTIONS -extensions cpp -no-recursive -locations none
                           )
 ELSE(${UPDATE_TRANSLATION})
-    QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    IF(${MAKE_TRANSLATION})
+        QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    ENDIF(${MAKE_TRANSLATION})
 ENDIF(${UPDATE_TRANSLATION})
 
 
index 0ac188e119a9146604c8bf955da901dc15ef4daa..bfac1ab628b70ac844930099f6fa4bddcbeaf581 100644 (file)
@@ -322,6 +322,14 @@ bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
     XGUI_Displayer* aDisp = myWorkshop->displayer();
     QObjectPtrList aObjList = aDisp->displayedObjects();
 
+    //if (myHighlightPointAspect.IsNull()) {
+    //  Handle(AIS_Trihedron) aTrihedron = mySelector->viewer()->getTrihedron();
+    //  myHighlightPointAspect =
+    //    new Graphic3d_AspectMarker3d(aTrihedron->getHighlightPointAspect()->Aspect().operator*());
+    //}
+    if (myOldSelectionColor.size() == 0)
+      myOldSelectionColor = aDisp->selectionColor();
+
     AIS_ListOfInteractive aList;
     aContext->DisplayedObjects(aList);
     AIS_ListIteratorOfListOfInteractive aLIt;
@@ -400,6 +408,12 @@ bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
   }
   // Delete selector because it has to be redefined on next activation
   if (mySelector) {
+    //if (!myHighlightPointAspect.IsNull()) {
+    //  Handle(AIS_Trihedron) aTrihedron = mySelector->viewer()->getTrihedron();
+    //  aTrihedron->getHighlightPointAspect()->SetAspect(myHighlightPointAspect);
+    //  myHighlightPointAspect.Nullify();
+    //}
+    myWorkshop->displayer()->setSelectionColor(myOldSelectionColor);
     myProxyViewer->setSelector(0);
     delete mySelector;
     mySelector = 0;
@@ -412,6 +426,8 @@ bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
   aResMgr->setValue("Study", "store_positions", myIsStorePositions);
   getApp()->setEditEnabled(myIsEditEnabled);
 
+  myOldSelectionColor.clear();
+
   // Post-processing for LoadScriptId to remove created(if it was created) SALOME Object Browser
   disconnect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
              this, SLOT(onScriptLoaded()));
@@ -501,6 +517,7 @@ void SHAPERGUI::onScriptLoaded()
   if (aBrowser)
     delete aBrowser;
   myWorkshop->displayer()->updateViewer();
+  myWorkshop->updateCommandStatus();
 }
 
 //******************************************************
@@ -532,6 +549,12 @@ SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
 {
   if (theMgr->getType() == OCCViewer_Viewer::Type()) {
     OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
+
+    //if (myHighlightPointAspect.IsNull()) {
+    //  Handle(AIS_Trihedron) aTrihedron = aViewer->getTrihedron();
+    //  myHighlightPointAspect =
+    //    new Graphic3d_AspectMarker3d(aTrihedron->getHighlightPointAspect()->Aspect().operator*());
+    //}
     SHAPERGUI_OCCSelector* aSelector = new SHAPERGUI_OCCSelector(aViewer,
                                                                  getApp()->selectionMgr());
 #ifdef SALOME_PATCH_FOR_CTRL_WHEEL
@@ -545,6 +568,12 @@ SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
       aSel->setEnabled(aSel == aSelector);
     }
     myProxyViewer->setSelector(aSelector);
+
+    if (myOldSelectionColor.size() == 0)
+      myOldSelectionColor = myWorkshop->displayer()->selectionColor();
+
+    std::vector<int> aColor = Config_PropManager::color("Visualization", "selection_color");
+    myWorkshop->displayer()->setSelectionColor(aColor);
     return aSelector;
   }
   return 0;
@@ -857,6 +886,11 @@ void SHAPERGUI::preferencesChanged(const QString& theSection, const QString& the
   }
   aProp->setValue(aValue);
 
+  if ((theSection == "Visualization") && (theParam == "selection_color")) {
+    std::vector<int> aColor = Config_PropManager::color("Visualization", "selection_color");
+    myWorkshop->displayer()->setSelectionColor(aColor);
+  }
+
   myWorkshop->displayer()->redisplayObjects();
 }
 
index 32b5035cde8ac7006a3e06d8ced4d768411a8c77..1c52678385d50ea1ab3a12f52032bbd8579d5f45 100644 (file)
@@ -277,6 +277,9 @@ private slots:
   QMap<QString, QIntList> myToolbars;
   QMap<QString, QIntList> myDefaultToolbars;
   bool myIsToolbarsModified;
+
+  std::vector<int> myOldSelectionColor;
+  Handle(Graphic3d_AspectMarker3d) myHighlightPointAspect;
 };
 
 #endif
diff --git a/src/SHAPERGUI/SHAPERGUI_msg_fr.ts b/src/SHAPERGUI/SHAPERGUI_msg_fr.ts
new file mode 100644 (file)
index 0000000..99bf031
--- /dev/null
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+    <name>SHAPERGUI</name>
+    <message>
+        <source>Inspection</source>
+        <translation>Inspection</translation>
+    </message>
+    <message>
+        <source>Information</source>
+        <translation>Information</translation>
+    </message>
+    <message>
+        <source>Show inspection window</source>
+        <translation>Afficher la fenêtre d&apos;inspection</translation>
+    </message>
+    <message>
+        <source>What Is</source>
+        <translation>Qu’est-ce que c’est</translation>
+    </message>
+    <message>
+        <source>Inspection tool</source>
+        <translation>Outil d&apos;inspection</translation>
+    </message>
+    <message>
+        <source>Edit toolbars of the module</source>
+        <translation>Editer les barres d&apos;outils du module</translation>
+    </message>
+    <message>
+        <source>Edit toolbars...</source>
+        <translation>Editer les barres d&apos;outils...</translation>
+    </message>
+    <message>
+        <source>Viewer</source>
+        <translation>Vue</translation>
+    </message>
+    <message>
+        <source>Default selection</source>
+        <translation>Sélection par défaut</translation>
+    </message>
+    <message>
+        <source>Faces</source>
+        <translation>Faces</translation>
+    </message>
+    <message>
+        <source>Edges</source>
+        <translation>Arêtes</translation>
+    </message>
+    <message>
+        <source>Vertices</source>
+        <translation>Sommets</translation>
+    </message>
+    <message>
+        <source>Selection sensitivity</source>
+        <translation>Sensibilité de sélection</translation>
+    </message>
+    <message>
+        <source>Vertex</source>
+        <translation>Sommet</translation>
+    </message>
+    <message>
+        <source>Edge</source>
+        <translation>Bord</translation>
+    </message>
+    <message>
+        <source>Additional highlighting</source>
+        <translation>Mise en évidence supplémentaire</translation>
+    </message>
+    <message>
+        <source>In 3d mode</source>
+        <translation>En mode 3D</translation>
+    </message>
+    <message>
+        <source>In 2d mode</source>
+        <translation>En mode 2D</translation>
+    </message>
+    <message>
+        <source>Color scale</source>
+        <translation>Échelle de couleur</translation>
+    </message>
+    <message>
+        <source>X position</source>
+        <translation>Position X</translation>
+    </message>
+    <message>
+        <source>Y position</source>
+        <translation>Position Y</translation>
+    </message>
+    <message>
+        <source>Width</source>
+        <translation>Largeur</translation>
+    </message>
+    <message>
+        <source>Height</source>
+        <translation>Hauteur</translation>
+    </message>
+    <message>
+        <source>Intervals number</source>
+        <translation>Nombre d&apos;intervalles</translation>
+    </message>
+    <message>
+        <source>Text height</source>
+        <translation>Hauteur du texte</translation>
+    </message>
+    <message>
+        <source>Text color</source>
+        <translation>Couleur du texte</translation>
+    </message>
+    <message>
+        <source>MEN_DESK_EDIT</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SHAPERGUI_ToolbarItemsDlg</name>
+    <message>
+        <source>Edit toolbar</source>
+        <translation>Editer la barre d&apos;outils</translation>
+    </message>
+    <message>
+        <source>Toolbar name:</source>
+        <translation>Nom de la barre d&apos;outils:</translation>
+    </message>
+    <message>
+        <source>Out of toolbars:</source>
+        <translation>Hors des barres d&apos;outils:</translation>
+    </message>
+    <message>
+        <source>In the toolbar:</source>
+        <translation>Dans la barre d&apos;outils:</translation>
+    </message>
+</context>
+<context>
+    <name>SHAPERGUI_ToolbarsDlg</name>
+    <message>
+        <source>Toolbars</source>
+        <translation>Barres d&apos;outils</translation>
+    </message>
+    <message>
+        <source>Toolbars:</source>
+        <translation>Barres d&apos;outils:</translation>
+    </message>
+    <message>
+        <source>Number of commands out of toolbars:</source>
+        <translation>Nombre de commandes hors des barres d&apos;outils:</translation>
+    </message>
+    <message>
+        <source>Add...</source>
+        <translation>Ajouter...</translation>
+    </message>
+    <message>
+        <source>Add a new empty toolbar to the toolbars list</source>
+        <translation>Ajouter une nouvelle barre d&apos;outils vide à la liste des barres d&apos;outils</translation>
+    </message>
+    <message>
+        <source>Edit...</source>
+        <translation>Modifier...</translation>
+    </message>
+    <message>
+        <source>Edit currently selected toolbar</source>
+        <translation>Modifier la barre d&apos;outils actuellement sélectionnée</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Effacer</translation>
+    </message>
+    <message>
+        <source>Delete currently selected toolbar</source>
+        <translation>Supprimer la barre d&apos;outils actuellement sélectionnée</translation>
+    </message>
+    <message>
+        <source>Reset</source>
+        <translation>Réinitialiser</translation>
+    </message>
+    <message>
+        <source>Restore default toolbars structure</source>
+        <translation>Restaurer la structure des barres d&apos;outils par défaut</translation>
+    </message>
+    <message>
+        <source>Create toolbar</source>
+        <translation>Créer une barre d&apos;outils</translation>
+    </message>
+    <message>
+        <source>Name of a new toolbar</source>
+        <translation>Nom d&apos;une nouvelle barre d&apos;outils</translation>
+    </message>
+    <message>
+        <source>A tool bar with name %1 already exists</source>
+        <translation>Une barre d&apos;outils portant le nom %1 existe déjà</translation>
+    </message>
+    <message>
+        <source>Toolbar %1 will be deleted. Continue?</source>
+        <translation>La barre d&apos;outils %1 sera supprimée. Continuez ?</translation>
+    </message>
+    <message>
+        <source>Delete toolbar</source>
+        <translation>Supprimer la barre d&apos;outils</translation>
+    </message>
+    <message>
+        <source> (%1 commands)</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+</TS>
index 0504e411d9daccf4e2251f6d8ce4e63faaf879a8..b2ca766988edd68862c7c6894ec35672e5de608e 100644 (file)
@@ -1146,10 +1146,13 @@ static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnArc(const FeaturePtr& theFeat
   return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
 }
 
-static std::shared_ptr<GeomAPI_Pnt2d> pointOnEllipse(const FeaturePtr& theFeature)
+static std::shared_ptr<GeomAPI_Pnt2d> pointOnEllipse(const FeaturePtr& theFeature,
+                                                     bool isEllipse = true)
 {
+  const std::string& anAttrName = isEllipse ? SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() :
+                                  SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID();
   AttributePoint2DPtr aMajorAxisEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()));
+      theFeature->attribute(anAttrName));
   return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
 }
 
@@ -1170,6 +1173,8 @@ static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
       aMiddlePoint = middlePointOnArc(aFeature);
     else if (aFeatureKind == SketchPlugin_Ellipse::ID())
       aMiddlePoint = pointOnEllipse(aFeature);
+    else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
+      aMiddlePoint = pointOnEllipse(aFeature, false);
   }
   return aMiddlePoint;
 }
index d32b708caa6481d26549c66ec3a3b34e1c824351..c660b7aeb3ffad83dbcdf0577fd387857bb26390 100644 (file)
@@ -136,6 +136,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
        SketchPlugin_msg_en.ts
+       SketchPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
@@ -202,6 +203,8 @@ ADD_UNIT_TESTS(
   Test2860.py
   Test2894.py
   Test3019.py
+  Test3087_1.py
+  Test3087_2.py
   TestArcBehavior.py
   TestChangeSketchPlane1.py
   TestChangeSketchPlane2.py
@@ -219,6 +222,9 @@ ADD_UNIT_TESTS(
   TestConstraintDistanceBehavior.py
   TestConstraintDistanceHorizontal.py
   TestConstraintDistanceVertical.py
+  TestConstraintDistanceZero.py
+  TestConstraintDistanceHorizontalZero.py
+  TestConstraintDistanceVerticalZero.py
   TestConstraintEqual.py
   TestConstraintEqualEllipse.py
   TestConstraintFixed.py
@@ -283,6 +289,7 @@ ADD_UNIT_TESTS(
   TestProjectionIntoResult.py
   TestProjectionUpdate.py
   TestRectangle.py
+  TestRemainingDoF.py
   TestRemoveEllipse.py
   TestRemoveEllipticArc.py
   TestRemoveSketch.py
@@ -322,6 +329,7 @@ if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
     TestMoveArc.py
     TestMoveCircle.py
     TestMoveEllipse.py
+    TestMoveEllipticArc.py
     TestMoveLine.py
     TestMovementComplex.py
     TestMovePoint.py
index b856543b3921c3ca51a3eb9f7213912b4fddd554..bf2f211d96b99f99ce15e407a27ef176135e3147 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "SketchPlugin_ConstraintAngle.h"
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Tools.h>
 #include <SketcherPrs_Tools.h>
 
 #include <ModelAPI_AttributeDouble.h>
@@ -37,7 +38,9 @@
 #include <SketcherPrs_Factory.h>
 #include <SketcherPrs_Tools.h>
 
-#include <math.h>
+#include <cmath>
+#include <regex>
+#include <sstream>
 
 const double tolerance = 1.e-7;
 #define PI 3.1415926535897932
@@ -53,24 +56,34 @@ SketchPlugin_ConstraintAngle::SketchPlugin_ConstraintAngle()
 
 void SketchPlugin_ConstraintAngle::initAttributes()
 {
+  ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
+
   data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
 
-  data()->addAttribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID(),
-                       ModelAPI_AttributeDouble::typeId());
-  data()->addAttribute(SketchPlugin_ConstraintAngle::TYPE_ID(),
-                       ModelAPI_AttributeInteger::typeId());
+  data()->addAttribute(ANGLE_VALUE_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(TYPE_ID(), ModelAPI_AttributeInteger::typeId());
+
+  data()->addAttribute(ANGLE_REVERSED_FIRST_LINE_ID(), ModelAPI_AttributeBoolean::typeId());
+  data()->addAttribute(ANGLE_REVERSED_SECOND_LINE_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  data()->addAttribute(LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
+  aValidators->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
+
+  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()->addAttribute(SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID(),
-                       ModelAPI_AttributeBoolean::typeId());
-  data()->addAttribute(SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID(),
-                       ModelAPI_AttributeBoolean::typeId());
+  data()->addAttribute(SELECTED_SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->attribute(SELECTED_SECOND_POINT_ID())->setIsArgument(false);
+  aValidators->registerNotObligatory(getKind(), SELECTED_SECOND_POINT_ID());
 
-  data()->addAttribute(SketchPlugin_ConstraintAngle::LOCATION_TYPE_ID(),
-                       ModelAPI_AttributeInteger::typeId());
-  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
+  if (attribute(TYPE_ID())->isInitialized())
+    myPrevAngleType = integer(TYPE_ID())->value();
+  else
+    myPrevAngleType = (int)SketcherPrs_Tools::ANGLE_DIRECT;
 }
 
 void SketchPlugin_ConstraintAngle::colorConfigInfo(std::string& theSection, std::string& theName,
@@ -85,21 +98,15 @@ void SketchPlugin_ConstraintAngle::execute()
 {
   std::shared_ptr<ModelAPI_Data> aData = data();
 
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrA =
-    aData->refattr(SketchPlugin_Constraint::ENTITY_A());
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrB =
-    aData->refattr(SketchPlugin_Constraint::ENTITY_B());
+  AttributeRefAttrPtr anAttrA = aData->refattr(SketchPlugin_Constraint::ENTITY_A());
+  AttributeRefAttrPtr anAttrB = aData->refattr(SketchPlugin_Constraint::ENTITY_B());
   if (!anAttrA->isInitialized() || !anAttrB->isInitialized())
     return;
 
-  AttributeDoublePtr anAttrValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-      aData->attribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
+  AttributeDoublePtr anAttrValue = real(ANGLE_VALUE_ID());
+  if (!anAttrValue->isInitialized())
+    calculateAngle();
 
-  if (!anAttrValue->isInitialized()) {
-    double anAngle = calculateAngle();
-    anAttrValue->setValue(anAngle);
-    updateConstraintValueByAngleValue();
-  }
   // the value should to be computed here, not in the
   // getAISObject in order to change the model value
   // inside the object transaction. This is important for creating a constraint by preselection.
@@ -117,6 +124,8 @@ AISObjectPtr SketchPlugin_ConstraintAngle::getAISObject(AISObjectPtr thePrevious
 
   AISObjectPtr anAIS = SketcherPrs_Factory::angleConstraint(this, sketch(),
                                                             thePrevious);
+  if (anAIS.get() && !thePrevious.get())
+    SketchPlugin_Tools::setDimensionColor(anAIS);
   return anAIS;
 }
 
@@ -125,37 +134,26 @@ void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
   std::shared_ptr<ModelAPI_Data> aData = data();
   if (!aData)
     return;
-  FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
-  FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
+
+  if (theID == TYPE_ID())
+    updateAngleValue();
+
+  FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
+  FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
   if (!aLineA || !aLineB)
     return;
 
-  if (theID == SketchPlugin_Constraint::ENTITY_A() ||
-      theID == SketchPlugin_Constraint::ENTITY_B()) {
-    AttributeDoublePtr aValueAttr = real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID());
-    AttributeDoublePtr aConstrValueAttr = real(SketchPlugin_Constraint::VALUE());
-    // only if one of attributes is not initialized, try to compute the current value
-    if (!aValueAttr->isInitialized() || !aConstrValueAttr->isInitialized()) {
-      if (aValueAttr->isInitialized() && !aConstrValueAttr->isInitialized())
-        // initialize base value of constraint
-        updateConstraintValueByAngleValue();
-      double anAngle = calculateAngle();
-      aValueAttr->setValue(anAngle);
-      updateConstraintValueByAngleValue();
-    }
-  } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
+  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(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+      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());
-    FeaturePtr aLineA =
-      SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
-    FeaturePtr aLineB =
-      SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
 
     // Intersection of lines
     std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
@@ -168,111 +166,167 @@ void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
       aFlyoutAttr->setValue(aFlyoutAttr->x() + tolerance, aFlyoutAttr->y());
     myFlyoutUpdate = false;
   }
-  else if (theID == SketchPlugin_ConstraintAngle::TYPE_ID()) {
-    std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
-    double anAngle = calculateAngle();
-    if (aValueAttr->text().empty())
-      aValueAttr->setValue(anAngle);
-    else {
-      aValueAttr = std::dynamic_pointer_cast<
-        ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_ConstraintAngle::VALUE()));
-      aValueAttr->setValue(anAngle);
-    }
-  }
-  else if (theID == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) {
-    updateConstraintValueByAngleValue();
-  }
 }
 
-double SketchPlugin_ConstraintAngle::calculateAngle()
+void SketchPlugin_ConstraintAngle::calculateAngle()
 {
+  // update *_REVERSED_* flags
+  calculateAnglePosition();
+
   std::shared_ptr<ModelAPI_Data> 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());
 
-  std::shared_ptr<GeomDataAPI_Point2D> aStartA = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineA->attribute(SketchPlugin_Line::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aEndA = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineA->attribute(SketchPlugin_Line::END_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aStartB = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineB->attribute(SketchPlugin_Line::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aEndB = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineB->attribute(SketchPlugin_Line::END_ID()));
-
-  std::shared_ptr<GeomAPI_Angle2d> anAng;
-  if (!attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() ||
-      !attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized())
-    anAng = std::shared_ptr<GeomAPI_Angle2d>(new GeomAPI_Angle2d(
-        aStartA->pnt(), aEndA->pnt(), aStartB->pnt(), aEndB->pnt()));
-  else {
-    std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA->pnt(), aEndA->pnt()));
-    bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
-    std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB->pnt(), aEndB->pnt()));
-    bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
-    anAng = std::shared_ptr<GeomAPI_Angle2d>(
+  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_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
+  std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
+
+  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();
-  std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeDouble>(data()->attribute(VALUE()));
-  std::shared_ptr<ModelAPI_AttributeDouble> anAngleValueAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeDouble>(data()->attribute(ANGLE_VALUE_ID()));
-  if (!aValueAttr->isInitialized())
-    aValueAttr->setValue(anAngle);
-  /// an angle value should be corrected by the current angle type
-  anAngle = getAngleForType(anAngleValueAttr->text().empty() ?
-                            anAngle : anAngleValueAttr->value());
-  boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(anAng->isReversed(0));
-  boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(anAng->isReversed(1));
-  return anAngle;
+
+  AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
+  if (!anAngleValueAttr->isInitialized())
+    anAngleValueAttr->setValue(getAngleForType(fabs(anAngle)));
+
+  anAngle /= fabs(anAngle);
+  anAngle *= getAngleForType(anAngleValueAttr->value());
+
+  // update value of the constraint to be passed to the solver
+  real(SketchPlugin_Constraint::VALUE())->setValue(anAngle);
 }
 
-double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle, bool isPreviousValueObtuse)
+void SketchPlugin_ConstraintAngle::calculateAnglePosition()
 {
-  double anAngle = theAngle;
+  if (attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
+      attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized())
+    return; // already calculated
 
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  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());
-  switch (anAngleType) {
+  DataPtr aData = data();
+  FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
+  FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, 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());
+
+  bool isReversed1 = false;
+  bool isReversed2 = false;
+
+  GeomPnt2dPtr aSelected1 = SketcherPrs_Tools::getPoint(this, SELECTED_FIRST_POINT_ID());
+  GeomPnt2dPtr aSelected2 = SketcherPrs_Tools::getPoint(this, SELECTED_SECOND_POINT_ID());
+  if (aSelected1 && aSelected2) {
+    GeomPnt2dPtr anInterPnt = intersect(aLineA, aLineB);
+    if (!anInterPnt)
+      return;
+    std::shared_ptr<GeomAPI_XY> anInterXY = anInterPnt->xy();
+    isReversed1 = aSelected1->xy()->decreased(anInterXY)->dot(
+                  aEndA->xy()->decreased(aStartA->xy())) < -tolerance;
+    isReversed2 = aSelected2->xy()->decreased(anInterXY)->dot(
+                  aEndB->xy()->decreased(aStartB->xy())) < -tolerance;
+  }
+  else {
+    // no point is selected (document opened or Python script is loaded),
+    // calculate basing on the value
+    std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
+    isReversed1 = anAng->isReversed(0);
+    isReversed2 = anAng->isReversed(1);
+  }
+
+  // adjust reversed flags according to the angle type
+  AttributeIntegerPtr aTypeAttr = integer(TYPE_ID());
+  if (aTypeAttr && aTypeAttr->isInitialized() &&
+     (SketcherPrs_Tools::AngleType)(aTypeAttr->value()) == SketcherPrs_Tools::ANGLE_COMPLEMENTARY)
+    isReversed1 = !isReversed1;
+
+  boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
+  boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
+}
+
+static double angleForType(const double theAngle, const int theType)
+{
+  double anAngle = theAngle;
+  switch ((SketcherPrs_Tools::AngleType)theType) {
     case SketcherPrs_Tools::ANGLE_DIRECT:
       anAngle = theAngle;
-    break;
-    case SketcherPrs_Tools::ANGLE_COMPLEMENTARY: {
-      if (theAngle > 180 || isPreviousValueObtuse)
-        anAngle = theAngle - 180.0;
-      else
-        anAngle = 180.0 - theAngle;
-
-      if (anAngle < 0.0)
-        anAngle += 360.0;
-    }
-    break;
+      break;
+    case SketcherPrs_Tools::ANGLE_COMPLEMENTARY:
+      anAngle = 180.0 - theAngle;
+      break;
     case SketcherPrs_Tools::ANGLE_BACKWARD:
       anAngle = 360.0 - theAngle;
-    break;
+      break;
     default:
       break;
   }
   return anAngle;
 }
 
-void SketchPlugin_ConstraintAngle::updateConstraintValueByAngleValue()
+double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle)
 {
-  std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
-    ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
-  double anAngle = aValueAttr->value();
-
-  /// an angle value should be corrected by the current angle type
-  aValueAttr = std::dynamic_pointer_cast<
-                  ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
-  if (!aValueAttr->isInitialized())
-    calculateAngle();
-  anAngle = getAngleForType(anAngle, aValueAttr->value() > 180.0);
-  aValueAttr->setValue(anAngle);
+  return angleForType(theAngle, integer(TYPE_ID())->value());
+}
+
+void SketchPlugin_ConstraintAngle::updateAngleValue()
+{
+  AttributeIntegerPtr anAngleType = integer(TYPE_ID());
+  AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
+  if (anAngleValueAttr->isInitialized()) {
+    if (anAngleValueAttr->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);
+    }
+    else {
+      // process the parametric value
+      std::string anAngleText = anAngleValueAttr->text();
+      std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)",
+                              std::regex_constants::ECMAScript);
+
+      double anAnglePrefix = 0.0;
+      static const char aSignPrefix[2] = { '-', '+' };
+      int aSignInd = 1;
+
+      std::smatch aResult;
+      if (std::regex_search(anAngleText, aResult, anAngleRegex)) {
+        anAnglePrefix = std::atof(aResult[1].str().c_str());
+        aSignInd = aResult[2].str()[0] == aSignPrefix[0] ? 0 : 1;
+        anAngleText = aResult[3].str();
+      }
+
+      if (myPrevAngleType != SketcherPrs_Tools::ANGLE_DIRECT)
+        aSignInd = 1 - aSignInd;
+      anAnglePrefix = angleForType(anAnglePrefix, myPrevAngleType);
+
+      if (anAngleType->value() != SketcherPrs_Tools::ANGLE_DIRECT)
+        aSignInd = 1 - aSignInd;
+      anAnglePrefix = angleForType(anAnglePrefix, anAngleType->value());
+
+      std::ostringstream aText;
+      bool isPrintSign = true;
+      if (fabs(anAnglePrefix) > tolerance)
+        aText << anAnglePrefix;
+      else
+        isPrintSign = aSignInd == 0;
+      if (isPrintSign)
+        aText << " " << aSignPrefix[aSignInd] << " (";
+      aText << anAngleText << (isPrintSign ? ")" : "");
+      anAngleValueAttr->setText(aText.str());
+    }
+  }
+  myPrevAngleType = anAngleType->value();
 }
 
 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
@@ -297,23 +351,13 @@ bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
     return false;
 
   // Start and end points of lines
-  std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineA->attribute(SketchPlugin_Line::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineA->attribute(SketchPlugin_Line::END_ID()));
-
-  std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
+  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)
     return false;
 
-  std::shared_ptr<GeomDataAPI_Point2D> aPointB1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineB->attribute(SketchPlugin_Line::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aPointB2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineB->attribute(SketchPlugin_Line::END_ID()));
-
-  std::shared_ptr<GeomAPI_Pnt2d> aStartB = aPointB1->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aEndB = aPointB2->pnt();
+  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;
 
@@ -332,20 +376,12 @@ bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
 std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
 {
   // Start and end points of lines
-  std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theLine1->attribute(SketchPlugin_Line::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theLine1->attribute(SketchPlugin_Line::END_ID()));
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPointB1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theLine2->attribute(SketchPlugin_Line::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aPointB2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theLine2->attribute(SketchPlugin_Line::END_ID()));
-
-  std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aStartB = aPointB1->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aEndB   = aPointB2->pnt();
+  const std::string& aLineStartAttr = SketchPlugin_Line::START_ID();
+  const std::string& aLineEndAttr = SketchPlugin_Line::END_ID();
+  GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineStartAttr);
+  GeomPnt2dPtr aEndA   = SketcherPrs_Tools::getPoint(theLine1.get(), aLineEndAttr);
+  GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineStartAttr);
+  GeomPnt2dPtr aEndB   = SketcherPrs_Tools::getPoint(theLine2.get(), aLineEndAttr);
   if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance)
     std::shared_ptr<GeomAPI_Pnt2d>();
 
index 39caab3845a0dfeb80c92d3261bb063173e332ed..3983acff6b2f15c0ac0c205c8cc006205f9f2416 100644 (file)
@@ -81,6 +81,19 @@ class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase
     return MY_LOCATION_TYPE_ID;
   }
 
+  /// attribute name indicating the first point selected
+  inline static const std::string& SELECTED_FIRST_POINT_ID()
+  {
+    static const std::string MY_SELECTED_FIRST_POINT_ID("SelectedPointA");
+    return MY_SELECTED_FIRST_POINT_ID;
+  }
+
+  /// attribute name indicating the second point selected
+  inline static const std::string& SELECTED_SECOND_POINT_ID()
+  {
+    static const std::string MY_SELECTED_SECOND_POINT_ID("SelectedPointB");
+    return MY_SELECTED_SECOND_POINT_ID;
+  }
 
   /// \brief Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
@@ -104,24 +117,28 @@ class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintAngle();
+
+protected:
   /// Calculate current value of the angle
-  double calculateAngle();
+  void calculateAngle();
+
+  /// Compute the position of the angle presentation (the quarter selected by the user)
+  void calculateAnglePosition();
 
   /// Converts the angle value according to the current angle type and sketch plane normal.
   /// The in/out angle is in degree.
   /// \param theAngle a source for the calculated angle
-  /// \param isPreviousValueObtuse a flag if obtuse should be processed
   /// \param a double angle value
-  double getAngleForType(double theAngle, bool isPreviousValueObtuse = false);
+  double getAngleForType(double theAngle);
 
-  /// Update value of VALUE attribute by the combination of the current angle type and angle value
-  void updateConstraintValueByAngleValue();
-
-  /// \brief Use plugin manager for features creation
-  SketchPlugin_ConstraintAngle();
+  /// Update value of ANGLE_VALUE attribute according to the current type
+  void updateAngleValue();
 
 private:
   bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point
+  int myPrevAngleType;
 };
 
 #endif
index 16a0451d4044c1987e970bf4b56adea306ed4e8a..8503f6fe141f02665010aededb2be00a111fdfdb 100644 (file)
@@ -21,6 +21,7 @@
 #include <SketchPlugin_Point.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Tools.h>
 
 #include <SketcherPrs_Tools.h>
 #include <SketcherPrs_Factory.h>
@@ -30,6 +31,7 @@
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Dir.h>
 
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeInteger.h>
@@ -61,6 +63,11 @@ void SketchPlugin_ConstraintDistance::initAttributes()
   data()->addAttribute(SketchPlugin_ConstraintDistance::LOCATION_TYPE_ID(),
                        ModelAPI_AttributeInteger::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
+
+  AttributePtr anAttr = data()->addAttribute(SketchPlugin_ConstraintDistance::DIRECTION_ID(),
+                                             GeomDataAPI_Dir::typeId());
+  anAttr->setIsArgument(false);
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), DIRECTION_ID());
 }
 
 void SketchPlugin_ConstraintDistance::colorConfigInfo(std::string& theSection, std::string& theName,
@@ -95,9 +102,25 @@ AISObjectPtr SketchPlugin_ConstraintDistance::getAISObject(AISObjectPtr thePrevi
   AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
                                                                       sketch(),
                                                                       thePrevious);
+  if (anAIS.get() && !thePrevious.get())
+    SketchPlugin_Tools::setDimensionColor(anAIS);
   return anAIS;
 }
 
+static std::shared_ptr<GeomAPI_Lin2d> getLine(DataPtr theData, const std::string& theAttrName)
+{
+  FeaturePtr aLineFeature = SketcherPrs_Tools::getFeatureLine(theData, theAttrName);
+  if (!aLineFeature)
+    return GeomLine2dPtr();
+
+  std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+
+  return GeomLine2dPtr(new GeomAPI_Lin2d(aStart->x(), aStart->y(), aEnd->x(), aEnd->y()));
+}
+
 double SketchPlugin_ConstraintDistance::calculateCurrentDistance()
 {
   double aDistance = -1.;
@@ -109,25 +132,39 @@ double SketchPlugin_ConstraintDistance::calculateCurrentDistance()
   std::shared_ptr<GeomDataAPI_Point2D> aPointB =
       SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
 
+  GeomPnt2dPtr aGeomPntA, aGeomPntB;
+  GeomLine2dPtr aLine;
   if (aPointA.get() && aPointB.get()) {  // both points
-    aDistance = aPointA->pnt()->distance(aPointB->pnt());
+    aGeomPntA = aPointA->pnt();
+    aGeomPntB = aPointB->pnt();
   } else {
-    FeaturePtr aLineFeature;
-    std::shared_ptr<SketchPlugin_Line> aLine;
     if (!aPointA.get() && aPointB.get()) {  //Line and point
-      aLineFeature = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
-      aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aLineFeature);
-      if (aLine.get()) {
-        aDistance = aLine->distanceToPoint(aPointB->pnt());
-      }
+      aLine = getLine(aData, SketchPlugin_Constraint::ENTITY_A());
+      aGeomPntB = aPointB->pnt();
+      aGeomPntA = aLine ? aLine->project(aGeomPntB) : GeomPnt2dPtr();
     } else if (aPointA.get() && !aPointB.get()) {  // Point and line
-      aLineFeature = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
-      aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aLineFeature);
-      if (aLine.get()) {
-        aDistance = aLine->distanceToPoint(aPointA->pnt());
-      }
+      aLine = getLine(aData, SketchPlugin_Constraint::ENTITY_B());
+      aGeomPntA = aPointA->pnt();
+      aGeomPntB = aLine ? aLine->project(aGeomPntA) : GeomPnt2dPtr();
     }
   }
+
+  if (aGeomPntA.get() && aGeomPntB.get()) {
+    aDistance = aGeomPntA->distance(aGeomPntB);
+    if (aDistance < tolerance)
+      aDistance = 0.0;
+  }
+
+  // keep the direction between arguments for processing of the zero distance
+  std::shared_ptr<GeomDataAPI_Dir> aPointPointDir =
+      std::dynamic_pointer_cast<GeomDataAPI_Dir>(attribute(DIRECTION_ID()));
+  if (aDistance > tolerance)
+    aPointPointDir->setValue(aGeomPntB->x() - aGeomPntA->x(), aGeomPntB->y() - aGeomPntA->y(), 0.0);
+  else if (aLine) {
+    GeomDir2dPtr aLineDir = aLine->direction();
+    aPointPointDir->setValue(-aLineDir->y(), aLineDir->x(), 0.0);
+  }
+
   return aDistance;
 }
 
@@ -167,7 +204,7 @@ void SketchPlugin_ConstraintDistance::attributeChanged(const std::string& theID)
     if (!aValueAttr->isInitialized()) {
       // only if it is not initialized, try to compute the current value
       double aDistance = calculateCurrentDistance();
-      if (aDistance > 0) { // set as value the length of updated references
+      if (aDistance >= 0) { // set as value the length of updated references
         aValueAttr->setValue(aDistance);
       }
     }
@@ -212,16 +249,16 @@ void SketchPlugin_ConstraintDistance::attributeChanged(const std::string& theID)
     } else
       return;
 
-    if (aEndPnt->distance(aStartPnt) < tolerance)
-      return;
-
     myFlyoutUpdate = true;
-    std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aStartPnt);
-
-    double X = aFlyoutDir->dot(aLineDir->xy());
-    double Y = -aFlyoutDir->cross(aLineDir->xy());
-    aFlyoutAttr->setValue(X, Y);
+    if (aEndPnt->distance(aStartPnt) >= tolerance) {
+      std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
+      double X = aFlyoutDir->dot(aLineDir->xy());
+      double Y = -aFlyoutDir->cross(aLineDir->xy());
+      aFlyoutAttr->setValue(X, Y);
+    }
+    else
+      aFlyoutAttr->setValue(aFlyoutDir->x(), aFlyoutDir->y());
     myFlyoutUpdate = false;
   }
 }
index 082fb84a897927910399878373ec109bfec7a2f5..9ce5afbe79d47bed7d1c0cabb612d7b0b7ed77e5 100644 (file)
@@ -64,6 +64,14 @@ class SketchPlugin_ConstraintDistance : public SketchPlugin_ConstraintBase
     return MY_SIGNED;
   }
 
+  /// \brief The direction from the first object to the second.
+  ///        To change distance value from zero to non-zero correctly.
+  inline static const std::string& DIRECTION_ID()
+  {
+    static const std::string MY_DIRECTION_ID("DistanceDirection");
+    return MY_DIRECTION_ID;
+  }
+
   /// attribute name of dimension location type
   inline static const std::string& LOCATION_TYPE_ID()
   {
index 3357d5819f52c9e97f0d48dd055a097894243242..bd45029bafd3d17f65b1185a07f45b8d6af34fbe 100644 (file)
@@ -22,6 +22,7 @@
 // Author:  Artem ZHIDKOV
 
 #include <SketchPlugin_ConstraintDistanceAlongDir.h>
+#include <SketchPlugin_Tools.h>
 
 #include <SketcherPrs_Tools.h>
 #include <SketcherPrs_Factory.h>
@@ -84,6 +85,8 @@ AISObjectPtr SketchPlugin_ConstraintDistanceAlongDir::getAISObject(AISObjectPtr
   AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
                                                                       sketch(),
                                                                       thePrevious);
+  if (anAIS.get() && !thePrevious.get())
+    SketchPlugin_Tools::setDimensionColor(anAIS);
   return anAIS;
 }
 
index 1ba4aa081ff9e54a91a7af1b61fb40fd824aa74a..ad6ee92b540721d4df98d217917d2eee2c9efc47 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "SketchPlugin_ConstraintLength.h"
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Tools.h>
 
 #include <GeomDataAPI_Point2D.h>
 
@@ -171,6 +172,8 @@ AISObjectPtr SketchPlugin_ConstraintLength::getAISObject(AISObjectPtr thePreviou
 
   AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
     sketch(), thePrevious);
+  if (anAIS.get() && !thePrevious.get())
+    SketchPlugin_Tools::setDimensionColor(anAIS);
   return anAIS;
 }
 
index b27190e0a556f406ca0325e778b407da433d139c..a58609b2dcc64e814effe66c84f71c77367e46c6 100644 (file)
@@ -22,6 +22,7 @@
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
 
 #include <SketcherPrs_Factory.h>
 #include <SketcherPrs_Tools.h>
@@ -177,6 +178,8 @@ AISObjectPtr SketchPlugin_ConstraintRadius::getAISObject(AISObjectPtr thePreviou
 
   AISObjectPtr anAIS = SketcherPrs_Factory::radiusConstraint(this, sketch(),
                                                              thePrevious);
+  if (anAIS.get() && !thePrevious.get())
+    SketchPlugin_Tools::setDimensionColor(anAIS);
   return anAIS;
 }
 
index e076f47c2454d2b1ba6081c6dc91f7fb6e9b8f43..9507cad1a9970b0b557863383d559d498b114031 100644 (file)
@@ -193,6 +193,11 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
     anAISObject = AISObjectPtr(new GeomAPI_AISObject);
   }
   anAISObject->createShape(anArcShape);
+  bool isAxiliary = false;
+  AttributeBooleanPtr aAttr = boolean(AUXILIARY_ID());
+  if (aAttr.get())
+    isAxiliary = aAttr->value();
+  SketchPlugin_Tools::customizeFeaturePrs(anAISObject, isAxiliary);
   return anAISObject;
 }
 
index f01a332f296b0b90d751165547938b937376df3f..3e9e9fd394b413d15268d2706b820be04b9ec53e 100644 (file)
@@ -104,28 +104,6 @@ std::string SketchPlugin_Line::processEvent(const std::shared_ptr<Events_Message
 }
 // LCOV_EXCL_STOP
 
-double SketchPlugin_Line::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
-{
-  double aDelta = 0;
-
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint1 =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint2 =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(END_ID()));
-
-  GeomAPI_Lin2d aLin2d(aPoint1->x(), aPoint1->y(), aPoint2->x(), aPoint2->y());
-
-  if (false/*projection*/) {  // TODO: if it has not been necessary, remove this block
-    std::shared_ptr<GeomAPI_Pnt2d> aResult = aLin2d.project(thePoint);
-    aDelta = aResult->distance(thePoint);
-  } else {  // distance
-    aDelta = aLin2d.distance(thePoint);
-  }
-
-  return aDelta;
-}
-
 const std::string& SketchPlugin_Line::getKind()
 {
   static std::string MY_KIND = SketchPlugin_Line::ID();
index 7a23944ae6260d0ab8714a83579e07ea033e931a..28d60dcd0ccab75233db146247cbfc8c9cc1a963 100644 (file)
@@ -80,10 +80,6 @@ class SketchPlugin_Line : public SketchPlugin_SketchEntity,
   /// if message has selected object
   virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
-  /// Return the distance between the feature and the point
-  /// \param thePoint the point
-  double distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
-
   /// Called on change of any argument-attribute of this object
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
 
index ecd064a088075dc90bfae63f75d5d668602ce888..ed2caaf650386a1d4079a0e5ffab1be0bd22c0cf 100644 (file)
@@ -302,6 +302,7 @@ AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
     anAIS.reset(new GeomAPI_AISObject());
   }
   anAIS->createShape(aCompound);
+  SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
   return anAIS;
 }
 
index 0bcabf4ff4731a90b7d26c7f2f34fffe07ca4cc9..7a0572702e263fd4c8d020120995af46bc7a3fc8 100644 (file)
@@ -389,6 +389,10 @@ AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
     anAIS.reset(new GeomAPI_AISObject());
   }
   anAIS->createShape(aCompound);
+
+  // Modify attributes
+  SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
   return anAIS;
 }
 
index e1e79e3aedac61736e6a65b37a920ec6cba00d3e..2cf1cbc7f011bcf9ff4c7a6e314d46c57f395705 100644 (file)
@@ -380,5 +380,9 @@ AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
   if (!anAIS)
     anAIS.reset(new GeomAPI_AISObject());
   anAIS->createShape(aCompound);
+
+  // Modify attributes
+  SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
   return anAIS;
 }
index 984a759261cd1ace2416455d69f18a2531452b50..bd8290c0c5db33c4d749befe5146c0bfb09049a9 100644 (file)
@@ -350,6 +350,7 @@ AISObjectPtr SketchPlugin_MacroEllipticArc::getAISObject(AISObjectPtr thePreviou
   if (!anAIS)
     anAIS.reset(new GeomAPI_AISObject());
   anAIS->createShape(aCompound);
+  SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
   return anAIS;
 }
 
index d9e967e60a7e7f07a18eea5fba7f0de76e47a31d..ac1b442c82da8b06b32c948a929aaa7427cbc7c4 100644 (file)
@@ -171,6 +171,10 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                                    "Sketch fully constrained color",
                                    Config_Prop::Color, SKETCH_FULLY_CONSTRAINED_COLOR);
 
+  Config_PropManager::registerProp("Visualization", "sketch_line_width",
+                                   "Sketch line width",
+                                   Config_Prop::IntSpin, "3");
+
   // register sketcher properties
 #ifdef SET_PLANES_COLOR_IN_PREFERENCES
   Config_PropManager::registerProp("Visualization", "yz_plane_color", "YZ plane color",
index 79eb675ca240ca273480dd8d6d4c92ed3b8f08d9..e04031fee6db7cee731dd447ce225900018759b9 100644 (file)
@@ -35,6 +35,9 @@
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Tools.h>
+#include <ModelAPI_Events.h>
+
+#include <Events_Loop.h>
 
 #include <GeomAPI_Circ.h>
 #include <GeomAPI_Edge.h>
@@ -51,6 +54,7 @@
 
 static const double tolerance = 1.e-7;
 
+
 SketchPlugin_Projection::SketchPlugin_Projection()
     : SketchPlugin_SketchEntity(),
       myIsComputing(false)
@@ -371,6 +375,9 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
       setResult(aResult);
       GeomShapePtr anEmptyVal;
       aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
+
+      static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
+      ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
     }
   }
 }
index 9c247446cfeeebb6d666134c7616727e45c15c1f..692ac5d0ed2be3377aad617f6744f1ca75773a5d 100644 (file)
@@ -315,6 +315,7 @@ void SketchPlugin_Sketch::attributeChanged(const std::string& theID) {
           std::shared_ptr<GeomAPI_Dir> aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir)));
           std::shared_ptr<GeomAPI_Dir> aXDir(new GeomAPI_Dir(aYDir->cross(aNormDir)));
 
+          bool aWasBlocked = data()->blockSendAttributeUpdated(true);
           // update position of the sketch
           std::shared_ptr<GeomDataAPI_Point> anOrigin = std::dynamic_pointer_cast
             <GeomDataAPI_Point>(data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
@@ -325,7 +326,7 @@ void SketchPlugin_Sketch::attributeChanged(const std::string& theID) {
           std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
             data()->attribute(SketchPlugin_Sketch::DIRX_ID()));
           aDirX->setValue(aXDir);
-          std::shared_ptr<GeomAPI_Dir> aDir = aPlane->direction();
+          data()->blockSendAttributeUpdated(aWasBlocked, true);
         }
       }
     }
index 7f63c5bb2ca4643eee898b0878d9ba81f3528389..6feda008dd89d3a607d48306566c0f362184592f 100644 (file)
@@ -43,7 +43,7 @@
  * \ingroup Plugins
  * \brief Feature for creation of the new part in PartSet.
  */
-class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICustomPrs
+class SketchPlugin_Sketch : public ModelAPI_CompositeFeature//, public GeomAPI_ICustomPrs
 {
  public:
   /// Sketch feature kind
@@ -257,18 +257,18 @@ class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICu
   static std::shared_ptr<GeomAPI_Ax3> plane(SketchPlugin_Sketch* theSketch);
 
   /// Customize presentation of the feature
-  virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
-                                     std::shared_ptr<GeomAPI_ICustomPrs> theDefaultPrs)
-  {
-    bool isCustomized = false;
-    // apply the color of the result to the presentation
-    if (theDefaultPrs.get())
-      isCustomized = theDefaultPrs->customisePresentation(theResult, thePrs, theDefaultPrs);
-    // set the sketch presentation bold
-    isCustomized = thePrs->setWidth(2) || isCustomized;
-
-    return isCustomized;
-  }
+  //virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
+  //                                   std::shared_ptr<GeomAPI_ICustomPrs> theDefaultPrs)
+  //{
+  //  bool isCustomized = false;
+  //  // apply the color of the result to the presentation
+  //  if (theDefaultPrs.get())
+  //    isCustomized = theDefaultPrs->customisePresentation(theResult, thePrs, theDefaultPrs);
+  //  // set the sketch presentation bold
+  //  isCustomized = thePrs->setWidth(2) || isCustomized;
+
+  //  return isCustomized;
+  //}
 
 private:
   /// Substitute all links to external objects by newly created features.
index 0f653e4196f5122b60f21553e0ee2c0325b00d01..4d85894e574e9a695de5d7f2e9ccab3c9474f43e 100644 (file)
@@ -41,7 +41,7 @@
  * This is an abstract class to give
  * an interface to create the entity features such as line, circle, arc and point.
  */
-class SketchPlugin_SketchEntity : public SketchPlugin_Feature, public GeomAPI_ICustomPrs
+class SketchPlugin_SketchEntity : public SketchPlugin_Feature //, public GeomAPI_ICustomPrs
 {
  public:
   /// Reference to the construction type of the feature
@@ -73,15 +73,15 @@ class SketchPlugin_SketchEntity : public SketchPlugin_Feature, public GeomAPI_IC
   }
 
   /// Width of the auxiliary line
-  inline static const double SKETCH_LINE_WIDTH_AUXILIARY()
+  inline static const int SKETCH_LINE_WIDTH_AUXILIARY()
   {
     return 2;
   }
 
   /// Width of the line
-  inline static const double SKETCH_LINE_WIDTH()
+  inline static const int SKETCH_LINE_WIDTH()
   {
-    return 3;
+    return Config_PropManager::integer("Visualization", "sketch_line_width");
   }
 
   /// Style of the auxiliary line
@@ -118,87 +118,106 @@ class SketchPlugin_SketchEntity : public SketchPlugin_Feature, public GeomAPI_IC
     return false;
   }
 
+  //virtual bool isIncludeToResult() const
+  //{
+  //  AttributeBooleanPtr anAttr;
+  //  std::set<AttributePtr> aRefsToMe = data()->refsToMe();
+  //  std::set<AttributePtr>::const_iterator aIt;
+  //  for (aIt = aRefsToMe.cbegin(); aIt != aRefsToMe.cend(); ++aIt) {
+  //    if ((*aIt)->id() == "ProjectedFeature") {
+  //      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
+  //      if (aFeature.get()) {
+  //        anAttr = aFeature->data()->boolean("IncludeToResult");
+  //        if (anAttr.get())
+  //          return anAttr->value();
+  //      }
+  //    }
+  //  }
+  //  return true;
+  //}
+
 // LCOV_EXCL_START
   /// Customize presentation of the feature
-  virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
-                                     std::shared_ptr<GeomAPI_ICustomPrs> theDefaultPrs)
-  {
-    /// Store previous color values of the presentation to check it after setting specific entity
-    /// color. Default color is set into presentation to have not modified isCustomized state
-    /// after default customize prs is completed.
-    std::vector<int> aPrevColor;
-    aPrevColor.resize(3);
-    thePrs->getColor(aPrevColor[0], aPrevColor[1], aPrevColor[2]);
-    if (theResult.get()) {
-      std::string aSection, aName, aDefault;
-      theResult->colorConfigInfo(aSection, aName, aDefault);
-      std::vector<int> aColor;
-      aColor = Config_PropManager::color(aSection, aName);
-      thePrs->setColor(aColor[0], aColor[1], aColor[2]);
-    }
-
-    bool isCustomized = theDefaultPrs.get() != NULL &&
-                        theDefaultPrs->customisePresentation(theResult, thePrs, theDefaultPrs);
-    int aShapeType = thePrs->getShapeType();
-    // a compound is processed like the edge because the
-    // arc feature uses the compound for presentable AIS
-    if (aShapeType != 6/*an edge*/ && aShapeType != 7/*a vertex*/ && aShapeType != 0/*compound*/)
-      return false;
-
-    // set color from preferences
-    std::vector<int> aColor;
-    std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
-                                    data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
-    bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
-    if (isConstruction) {
-      aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
-    }
-    else if (isExternal()) {
-      aColor = Config_PropManager::color("Visualization", "sketch_external_color");
-    }
-    else {
-      aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
-    }
-    if (!aColor.empty()) {
-      if (theResult.get() && ModelAPI_Session::get()->isOperation()) {
-        AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
-        aColorAttr->setSize(3);
-        // Set the color attribute in order do not use default colors in the presentation object
-        for (int i = 0; i < 3; i++)
-          aColorAttr->setValue(i, aColor[i]);
-      }
-      thePrs->setColor(aColor[0], aColor[1], aColor[2]);
-      for (int i = 0; i < 3 && !isCustomized; i++)
-        isCustomized = aColor[i] != aPrevColor[i];
-    }
-
-    if (aShapeType == 6 || aShapeType == 0) { // if this is an edge or a compound
-      if (isConstruction) {
-        isCustomized = thePrs->setWidth(SKETCH_LINE_WIDTH_AUXILIARY()) || isCustomized;
-        isCustomized = thePrs->setLineStyle(SKETCH_LINE_STYLE_AUXILIARY()) || isCustomized;
-      }
-      else {
-        isCustomized = thePrs->setWidth(SKETCH_LINE_WIDTH()) || isCustomized;
-        isCustomized = thePrs->setLineStyle(SKETCH_LINE_STYLE()) || isCustomized;
-      }
-    }
-    else if (aShapeType == 7) { // otherwise this is a vertex
-      // The width value do not have effect on the point presentation.
-      // It is defined in order to extend selection area of the object.
-      thePrs->setWidth(17);
-    //  thePrs->setPointMarker(1, 1.); // Set point as a '+' symbol
-    }
-    if(isCopy()) {
-      double aWidth = thePrs->width();
-      isCustomized = thePrs->setWidth(aWidth / 2.5) || isCustomized;
-    }
-
-    if (!theResult.get()) {
-      double aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
-      thePrs->setDeflection(aDeflection);
-    }
-    return isCustomized;
-  }
+  //virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
+  //                                   std::shared_ptr<GeomAPI_ICustomPrs> theDefaultPrs)
+  //{
+  //  /// Store previous color values of the presentation to check it after setting specific entity
+  //  /// color. Default color is set into presentation to have not modified isCustomized state
+  //  /// after default customize prs is completed.
+  //  std::vector<int> aPrevColor;
+  //  aPrevColor.resize(3);
+  //  thePrs->getColor(aPrevColor[0], aPrevColor[1], aPrevColor[2]);
+  //  if (theResult.get()) {
+  //    std::string aSection, aName, aDefault;
+  //    theResult->colorConfigInfo(aSection, aName, aDefault);
+  //    std::vector<int> aColor;
+  //    aColor = Config_PropManager::color(aSection, aName);
+  //    thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+  //  }
+
+  //  bool isCustomized = theDefaultPrs.get() != NULL &&
+  //                      theDefaultPrs->customisePresentation(theResult, thePrs, theDefaultPrs);
+  //  int aShapeType = thePrs->getShapeType();
+  //  // a compound is processed like the edge because the
+  //  // arc feature uses the compound for presentable AIS
+  //  if (aShapeType != 6/*an edge*/ && aShapeType != 7/*a vertex*/ && aShapeType != 0/*compound*/)
+  //    return false;
+
+  //  // set color from preferences
+  //  std::vector<int> aColor;
+  //  std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
+  //                                  data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
+  //  bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
+  //  if (isConstruction) {
+  //    aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
+  //  }
+  //  else if (isExternal()) {
+  //    aColor = Config_PropManager::color("Visualization", "sketch_external_color");
+  //  }
+  //  else {
+  //    aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
+  //  }
+  //  if (!aColor.empty()) {
+  //    if (theResult.get() && ModelAPI_Session::get()->isOperation()) {
+  //      AttributeIntArrayPtr aColorAttr =
+  //          theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
+  //      aColorAttr->setSize(3);
+  //      // Set the color attribute in order do not use default colors in the presentation object
+  //      for (int i = 0; i < 3; i++)
+  //        aColorAttr->setValue(i, aColor[i]);
+  //    }
+  //    thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+  //    for (int i = 0; i < 3 && !isCustomized; i++)
+  //      isCustomized = aColor[i] != aPrevColor[i];
+  //  }
+
+  //  if (aShapeType == 6 || aShapeType == 0) { // if this is an edge or a compound
+  //    if (isConstruction) {
+  //      isCustomized = thePrs->setWidth(SKETCH_LINE_WIDTH_AUXILIARY()) || isCustomized;
+  //      isCustomized = thePrs->setLineStyle(SKETCH_LINE_STYLE_AUXILIARY()) || isCustomized;
+  //    }
+  //    else {
+  //      isCustomized = thePrs->setWidth(SKETCH_LINE_WIDTH()) || isCustomized;
+  //      isCustomized = thePrs->setLineStyle(SKETCH_LINE_STYLE()) || isCustomized;
+  //    }
+  //  }
+  //  else if (aShapeType == 7) { // otherwise this is a vertex
+  //    // The width value do not have effect on the point presentation.
+  //    // It is defined in order to extend selection area of the object.
+  //    thePrs->setWidth(17);
+  //  //  thePrs->setPointMarker(1, 1.); // Set point as a '+' symbol
+  //  }
+  //  if(isCopy() && !isIncludeToResult()) {
+  //    double aWidth = thePrs->width();
+  //    isCustomized = thePrs->setWidth(aWidth / 2.5) || isCustomized;
+  //  }
+
+  //  if (!theResult.get()) {
+  //    double aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
+  //    thePrs->setDeflection(aDeflection);
+  //  }
+  //  return isCustomized;
+  //}
 // LCOV_EXCL_STOP
 
 protected:
index a285ea2431c1e7b8a2364b91047292a88f43e56e..0147ba521d38ed1f2be00ff5aa870a3d85f3f6a3 100644 (file)
@@ -537,6 +537,32 @@ GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
   return GeomPnt2dPtr(new GeomAPI_Pnt2d(X, Y));
 }
 
+
+void customizeFeaturePrs(const AISObjectPtr& thePrs, bool isAxiliary)
+{
+  std::vector<int> aColor;
+  int aWidth = 1;
+  if (isAxiliary) {
+    thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY());
+    aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
+    aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
+  }
+  else {
+    thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE());
+    aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
+    aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
+  }
+  thePrs->setWidth(aWidth);
+  thePrs->setColor(aColor[0], aColor[1], aColor[2]);
+}
+
+void setDimensionColor(const AISObjectPtr& theDimPrs)
+{
+  std::vector<int> aColor = Config_PropManager::color("Visualization", "sketch_dimension_color");
+  if (aColor.size() == 3)
+    theDimPrs->setColor(aColor[0], aColor[1], aColor[2]);
+}
+
 } // namespace SketchPlugin_Tools
 
 
index f29e192dffa83622bd7b849635dd80738fe1c194..a45ecf05a85899eeef033f8964028dabdc8e3e9c 100644 (file)
@@ -26,6 +26,7 @@
 #include <ModelAPI_Attribute.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <GeomAPI_Shape.h>
+#include <GeomAPI_AISObject.h>
 #include <GeomDataAPI_Point2D.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 
@@ -135,9 +136,16 @@ void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr&      theRefA
                                          std::shared_ptr<GeomAPI_Shape>& theTangentCurve,
                                          std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint);
 
-
 /// Calculate global coordinates for flyout point of Length constraint
 GeomPnt2dPtr flyoutPointCoordinates(const std::shared_ptr<SketchPlugin_Constraint>& theConstraint);
+
+/// Sets attributes of feature presentation
+/// \param[in] thePrs a presentation
+/// \param[in] isAxiliary is axiliary flag
+void customizeFeaturePrs(const AISObjectPtr& thePrs, bool isAxiliary);
+
+void setDimensionColor(const AISObjectPtr& theDimPrs);
+
 }; // namespace SketchPlugin_Tools
 
 namespace SketchPlugin_SegmentationTools
diff --git a/src/SketchPlugin/SketchPlugin_msg_fr.ts b/src/SketchPlugin/SketchPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..d22b51e
--- /dev/null
@@ -0,0 +1,4716 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Macros</source>
+      <translation>Macros</translation>
+    </message>
+    <message>
+      <source>Sketch</source>
+      <translation>Esquisse</translation>
+    </message>
+    <message>
+      <source>Sketch drawer</source>
+      <translation>Tiroir à esquisse</translation>
+    </message>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Angular copy</source>
+      <translation>Copie angulaire</translation>
+    </message>
+    <message>
+      <source>Arc</source>
+      <translation>Arc</translation>
+    </message>
+    <message>
+      <source>Circle</source>
+      <translation>Cercle</translation>
+    </message>
+    <message>
+      <source>Coincident</source>
+      <translation>Coïncident</translation>
+    </message>
+    <message>
+      <source>Collinear</source>
+      <translation>Colinéaire</translation>
+    </message>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Ellipse</source>
+      <translation>Ellipse</translation>
+    </message>
+    <message>
+      <source>Equal</source>
+      <translation>Égal</translation>
+    </message>
+    <message>
+      <source>Fixed</source>
+      <translation>Fixé</translation>
+    </message>
+    <message>
+      <source>Horizontal</source>
+      <translation>Horizontal</translation>
+    </message>
+    <message>
+      <source>Horizontal Distance</source>
+      <translation>Distance horizontale</translation>
+    </message>
+    <message>
+      <source>Length</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Middle point</source>
+      <translation>Point milieu</translation>
+    </message>
+    <message>
+      <source>Mirror copy</source>
+      <translation>Copie miroir</translation>
+    </message>
+    <message>
+      <source>Parallel</source>
+      <translation>Parallèle</translation>
+    </message>
+    <message>
+      <source>Perpendicular</source>
+      <translation>Perpendiculaire</translation>
+    </message>
+    <message>
+      <source>Projection</source>
+      <translation>Projection</translation>
+    </message>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+    <message>
+      <source>Rectangle</source>
+      <translation>Rectangle</translation>
+    </message>
+    <message>
+      <source>Tangent</source>
+      <translation>Tangente</translation>
+    </message>
+    <message>
+      <source>Trim</source>
+      <translation>Réduire</translation>
+    </message>
+    <message>
+      <source>Vertical</source>
+      <translation>Verticale</translation>
+    </message>
+    <message>
+      <source>Vertical Distance</source>
+      <translation>Distance verticale</translation>
+    </message>
+  </context>
+
+  <!-- Validators -->
+
+  <context>
+    <name>Sketch:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un plan pour l&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:DirX</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un plan pour l&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:External:GeomValidators_Face</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Seule la sélection d&apos;attribut peut être utilisée pour la face d&apos;esquisse, pas %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:External:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>L&apos;esquisse ne peut être créée que sur une face</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:External:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>L&apos;esquisse ne peut être créée que sur une face plane</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:External:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a cylinder.</source>
+      <translation>L&apos;esquisse ne peut être créée que sur une face cylindrique</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:External:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not an available face.</source>
+      <translation>L&apos;esquisse ne peut pas être créée sur la face sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un plan pour l&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:Features</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Les objets d&apos;esquisse ne sont pas définis</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroCircle:CircleRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La valeur du rayon est trop petite</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Un point central n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:CircleCenter</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:FirstPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:SecondPoint</name>
+    <message>
+      <source>Attribute "SecondPoint" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:ThirdPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:CircleRadius</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:CircleRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Le rayon entier n&apos;est pas initialisé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:CircleRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>Le rayon entier doit être défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:center_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point dans la vue</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Un point central n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:center_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue</translation>
+    </message>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:first_point</name>
+    <message>
+      <source>First point</source>
+      <translation>Premier point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue</translation>
+    </message>
+    <message>
+      <source>Passed point</source>
+      <translation>Point passé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:second_point</name>
+    <message>
+      <source>Second point</source>
+      <translation>Deuxième point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:circle_radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:passed_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:third_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroCircle:third_point</name>
+    <message>
+      <source>Third point</source>
+      <translation>Troisième point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchCircle:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchCircle:circle_center</name>
+    <message>
+      <source>Center</source>
+      <translation>Centre</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchCircle:circle_radius</name>
+    <message>
+      <source>Set radius</source>
+      <translation>Définir le rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchCircle:circle_radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintHorizontal:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal</name>
+    <message>
+      <source>ModelAPI_StateInvalidArgument</source>
+      <translation>Mauvais objet sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>L&apos;argument de contrainte ne contient pas d&apos;élément avec un type de forme acceptable. Le type devrait être l&apos;un des suivants : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>L&apos;argument de contrainte ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>L&apos;argument de contrainte fait référence à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;argument de contrainte de type %1 n&apos;est pas pris en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintPerpendicular:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La première ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>La première ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>La deuxième ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>La deuxième ligne fait référence à un type de forme non acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La deuxième ligne ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>La deuxième ligne fait référence à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>La deuxième ligne de type %1 n&apos;est pas prise en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>La deuxième ligne se réfère à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La deuxième ligne se réfère à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Deux lignes externes ne peuvent pas être contraintes comme perpendiculaires</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La première ligne ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme de la première ligne est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Deux lignes externes ne peuvent pas être contraintes comme perpendiculaires</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintRadius:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le cercle n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le cercle n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintFlyoutValuePnt</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>La valeur du rayon n&apos;est pas positive</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Le rayon est trop petit</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Le rayon entier doit être défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>Le rayon entier doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>L&apos;argument du cercle ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme d&apos;argument de cercle est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintVertical</name>
+    <message>
+      <source>ModelAPI_StateInvalidArgument</source>
+      <translation>Mauvais objet sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>La première ligne fait référence à un type de forme non acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La première ligne ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>La première ligne fait référence à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>La première ligne de type %1 n&apos;est pas prise en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>La première ligne fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La première ligne se réfère à la forme vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchLine:GeomValidators_Different</name>
+    <message>
+      <source>Attributes StartPoint and EndPoint are equal.</source>
+      <translation>Le point de départ et le point final sont identiques</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point final n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:EndPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point d&apos;arrivée dans la vue</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:StartPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point de départ dans la vue</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:StartPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point de départ n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:EndPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point final n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point final n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:EndPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point d&apos;arrivée dans la vue</translation>
+    </message>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:StartPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point de départ dans la vue</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:LineLength</name>
+    <message>
+      <source>Length</source>
+      <translation>Longueur</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchPoint:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchPoint:PointCoordinates</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchPoint:PointCoordinates</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchPoint:PointCoordinates</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchRectangle:GeomValidators_Different</name>
+    <message>
+      <source>Attributes RectStartPoint and RectEndPoint are equal.</source>
+      <translation>Le point de départ et le point final doivent être différents</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectEndPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point final du rectangle.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectStartPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectEndPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point final du rectangle.</translation>
+    </message>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectStartPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectEndPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectStartPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchArc:ArcRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>La valeur du rayon n&apos;est pas positive</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcTangentPoint:SketchPlugin_ArcTangentPoint</name>
+    <message>
+      <source>The attribute ArcTangentPoint should be a point</source>
+      <translation>Le point d&apos;arc tangent n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcCenter</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcCenter</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point central n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcEndPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point d&apos;arrivée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcPassedPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point intermédiaire</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcStartPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:GeomValidators_Different</name>
+    <message>
+      <source>Attributes ArcCenter and ArcStartPoint are equal.</source>
+      <translation>Le point central et le point final doivent être différents</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:GeomValidators_Different</name>
+    <message>
+      <source>Attributes ArcStartPoint and ArcEndPoint are equal.</source>
+      <translation>Le point de départ et le point final doivent être différents</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point final n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Le rayon de l&apos;arc est trop petit</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Le rayon de l&apos;arc entier doit être défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:ArcRadius:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>Le rayon de l&apos;arc entier doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:Model_FeatureValidator:ArcStartPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point de départ d&apos;arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:angle</name>
+    <message>
+      <source>Set angle</source>
+      <translation>Définir l&apos;angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:center_point</name>
+    <message>
+      <source>Center</source>
+      <translation>Centre</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:end_point</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:radius</name>
+    <message>
+      <source>Set radius</source>
+      <translation>Définir le rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:start_point</name>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchArc:radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintMirror:ConstraintMirrorList</name>
+    <message>
+      <source>Segments</source>
+      <translation>Segments</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne miroir n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne miroir n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>La ligne miroir renvoie à un type de forme non acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La ligne de miroir ne renvoie à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>La ligne miroir renvoie à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>La ligne miroir de type %1 n&apos;est pas prise en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>La ligne miroir renvoie à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La ligne en miroir fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintMirrorList</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionner des objets</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMultiRotation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le type d&apos;angle n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le centre de rotation n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Le nombre total d&apos;objets pivotés n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Le nombre total d&apos;objets en rotation doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Le nombre total d&apos;objets pivotés n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>Le nombre total d&apos;objets en rotation doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationList:SketchPlugin_CopyValidator</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationList:SketchPlugin_CopyValidator</name>
+    <message>
+      <source>The object %1 is a result of copy</source>
+      <translation>L&apos;objet %1 est le résultat d&apos;une copie et ne peut pas être pivoté</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le centre de rotation ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme du centre de rotation est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le centre de rotation fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Le centre de rotation se réfère à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationList</name>
+    <message>
+      <source>Segments</source>
+      <translation>Segments</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMultiTranslation:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point final du vecteur de translation n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le point final du vecteur de translation n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le point final du vecteur de translation n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le point de départ du vecteur de translation n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Le nombre total d&apos;objets traduits n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Le nombre total d&apos;objets traduits doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Le nombre total d&apos;objets traduits n&apos;est pas défini</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationObjects:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>Le nombre total d&apos;objets traduits doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationList:SketchPlugin_CopyValidator</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationList:SketchPlugin_CopyValidator</name>
+    <message>
+      <source>The object %1 is a result of copy</source>
+      <translation>L&apos;objet %1 est le résultat d&apos;une copie et ne peut pas être traduit</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le point de départ de la translation ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme du point de départ de la translation est &quot;%1&quot;, il doit correspondre à &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le point de départ du vecteur de translation n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le point de départ se réfère à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Le point de départ se réfère à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le point final de la translation ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme du point final de la translation est &quot;%1&quot;, il doit correspondre à &quot;%2&quot;.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Sélectionnez un point d&apos;arrivée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>Le point final fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>Le point final fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationList</name>
+    <message>
+      <source>Segments</source>
+      <translation>Segments</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintAngle:ConstraintFlyoutValuePnt</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Il n’est pas possible de créer un angle entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:AngleReversedLine1</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le premier objet ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le premier type de forme d&apos;objet est &quot;%1&quot;, il devrait correspondre à &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Il n’est pas possible de créer un angle entre deux entités externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le deuxième objet ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le deuxième type de forme d&apos;objet est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityA:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityB:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Une coïncidence ne peut pas être créée entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Une coïncidence ne peut pas être créée entre deux objets externes</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintDistance:ConstraintFlyoutValuePnt</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>La distance doit être définie</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La distance est trop petite</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>La valeur de distance entière doit être définie</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>La valeur de distance entière doit être positive</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>La distance ne peut pas être définie entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le premier objet ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le premier type de forme d&apos;objet est &quot;%1&quot;, il devrait correspondre à &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>La distance ne peut pas être définie entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>Le deuxième objet ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le deuxième type de forme d&apos;objet est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityA:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityB:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityB:SketchPlugin_EqualAttr</name>
+    <message>
+      <source>An empty object is used.</source>
+      <translation>Un objet vide est utilisé</translation>
+    </message>
+    <message>
+      <source>The %1 feature is not supported by the Equal constraint.</source>
+      <translation>La fonctionnalité %1 n&apos;est pas prise en charge par la contrainte Equal.</translation>
+    </message>
+    <message>
+      <source>Features with kinds %1 and %2 can not be equal.</source>
+      <translation>Les caractéristiques avec les types %1 et %2 ne peuvent pas être égales.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Une égalité ne peut pas être définie entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Une égalité ne peut pas être définie entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityA</name>
+    <message>
+      <source>Select edge</source>
+      <translation>Sélectionnez une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityB</name>
+    <message>
+      <source>Select edge</source>
+      <translation>Sélectionnez une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le premier arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le deuxième arête</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintLength:ConstraintFlyoutValuePnt</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Définir la valeur de la longueur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La longueur est trop petite</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Définir la valeur de la longueur entière</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>La valeur de la longueur entière n&apos;est pas positive</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La ligne ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme de ligne est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityA:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityB:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityB:SketchPlugin_MiddlePointAttr</name>
+    <message>
+      <source>Middle point constraint allows points and lines only</source>
+      <translation>Pas de point ou de ligne sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Un milieu ne peut pas être défini pour deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Un milieu ne peut pas être défini pour deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>La première ligne n&apos;est pas sélectionnée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Une parallèle ne peut pas être définie entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La première ligne ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme de la première ligne est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA:SketchPlugin_ExternalValidator</name>
+    <message>
+      <source>Both features, attribute and attribute in parameter, are external.</source>
+      <translation>Une parallèle ne peut pas être définie entre deux objets externes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>Le type de forme doit être %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La deuxième ligne ne fait référence à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>Le type de forme de la deuxième ligne est &quot;%1&quot;, il devrait être &quot;%2&quot;</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>L&apos;attribut avec le type %1 n&apos;est pas traité</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>L&apos;argument de contrainte fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It does not contain element with acceptable shape type. The type should be one of the next: %1</source>
+      <translation>La contrainte fixe fait référence à un type de forme non acceptable. Le type doit être : %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>It has reference to an empty attribute</source>
+      <translation>La contrainte fixe ne renvoie à rien</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>Shape type is "%1", it should be "%2"</source>
+      <translation>La contrainte fixe fait référence à %1 mais doit être %2</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>La contrainte fixe de type %1 n&apos;est pas prise en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The result is empty</source>
+      <translation>La contrainte fixe fait référence à un élément non existant</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The shape is empty</source>
+      <translation>La contrainte fixe fait référence à la forme vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA</name>
+    <message>
+      <source>Select point, curve or its boundary point.</source>
+      <translation>Sélectionnez un point, une courbe ou son point limite.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityA:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityB:PartSet_DifferentObjects</name>
+    <message>
+      <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
+      <translation>Différents objets doivent être sélectionnés</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityA:SketchPlugin_TangentAttr</name>
+    <message>
+      <source>Two segments cannot be tangent</source>
+      <translation>Deux segments ne peuvent pas être tangents</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityB:SketchPlugin_TangentAttr</name>
+    <message>
+      <source>It uses an empty object</source>
+      <translation>La sélection n&apos;est pas valide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le deuxième objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintSplit:ConstraintEntityA:SketchPlugin_SplitValidator</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Seule la sélection d&apos;attribut peut être utilisée pour la face d&apos;esquisse, pas %1</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Définir le rayon du congé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>Le rayon du congé doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not initialized.</source>
+      <translation>Définir le rayon du congé entier</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
+    <message>
+      <source>Integer is not positive.</source>
+      <translation>Le rayon du congé entier doit être positif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ou plusieurs points pour le congé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:fillet_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ou plusieurs points pour le congé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <message>
+      <source>Error: List of points is empty.</source>
+      <translation>La liste des points est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <message>
+      <source>Error: one of the selected point does not have coincidence.</source>
+      <translation>Un des points sélectionné n&apos;a pas de coïncidence</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <message>
+      <source>Error: One of the selected points does not have two suitable edges for fillet.</source>
+      <translation>Un des points sélectionnés ne possède pas deux arêtes appropriées pour le congé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <message>
+      <source>Error: Edges in selected point has tangent constraint.</source>
+      <translation>Les arêtes du point sélectionné ont une contrainte de tangence</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <message>
+      <source>Error: Edges in selected point has tangent constraint.</source>
+      <translation>Les arêtes du point sélectionné ont une contrainte de tangence</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Un argument de type %1 de la fonctionnalité de projection n&apos;est pas pris en charge</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
+    <message>
+      <source>The attribute %1 should be an edge</source>
+      <translation>L&apos;attribut %1 doit être une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
+    <message>
+      <source>There is no sketch referring to the current feature</source>
+      <translation>La fonction de projection n&apos;a pas d&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Sketch</name>
+    <message>
+      <source>Create sketch</source>
+      <translation>Créer une esquisse</translation>
+    </message>
+    <message>
+      <source>Sketch</source>
+      <translation>Esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:External</name>
+    <message>
+      <source>Select a plane on which to create a sketch</source>
+      <translation>Sélectionnez un plan sur lequel créer une esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>Sketch:SketchPlugin_SolverErrorValidator</name>
+    <message>
+      <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&apos;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>
+  </context>
+
+  <context>
+    <name>SketchConstraintAngle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Set fixed angle between two line segments</source>
+      <translation>Définir un angle fixe entre deux segments</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:AngleType</name>
+    <message>
+      <source>Additional</source>
+      <translation>Additionnel</translation>
+    </message>
+    <message>
+      <source>Angle type</source>
+      <translation>Type d&apos;angle</translation>
+    </message>
+    <message>
+      <source>Complementary</source>
+      <translation>Complémentaire</translation>
+    </message>
+    <message>
+      <source>Direct</source>
+      <translation>Direct</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:AngleValue</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Value</source>
+      <translation>Valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityA</name>
+    <message>
+      <source>Line 1</source>
+      <translation>Ligne 1</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:ConstraintEntityB</name>
+    <message>
+      <source>Line 2</source>
+      <translation>Ligne 2</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:LocationType</name>
+    <message>
+      <source>Automatic</source>
+      <translation>Automatique</translation>
+    </message>
+    <message>
+      <source>Left</source>
+      <translation>Gauche</translation>
+    </message>
+    <message>
+      <source>Right</source>
+      <translation>Droite</translation>
+    </message>
+    <message>
+      <source>Text location</source>
+      <translation>Localisation du texte</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintAngle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Le premier objet n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintCoincidence</name>
+    <message>
+      <source>Coincident</source>
+      <translation>Coïncident</translation>
+    </message>
+    <message>
+      <source>Create constraint for the coincidence of two points or point on line or circle</source>
+      <translation>Créer une contrainte pour la coïncidence de deux points ou d&apos;un point sur une ligne ou un cercle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityA</name>
+    <message>
+      <source>First object</source>
+      <translation>Premier objet</translation>
+    </message>
+    <message>
+      <source>Select a first object</source>
+      <translation>Sélectionnez un premier objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCoincidence:ConstraintEntityB</name>
+    <message>
+      <source>Second object</source>
+      <translation>Deuxième objet</translation>
+    </message>
+    <message>
+      <source>Select a second object</source>
+      <translation>Sélectionnez un deuxième objet</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintCollinear</name>
+    <message>
+      <source>Collinear</source>
+      <translation>Colinéaire</translation>
+    </message>
+    <message>
+      <source>Create constraint defining collinearity of two lines</source>
+      <translation>Créer une contrainte définissant la colinéarité de deux lignes</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:ConstraintEntityA</name>
+    <message>
+      <source>First line</source>
+      <translation>Première ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:ConstraintEntityB</name>
+    <message>
+      <source>Second line</source>
+      <translation>Deuxième ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le premier ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintCollinear:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le deuxième ligne</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintDistance</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Set fixed distance from a point to an object</source>
+      <translation>Définir une distance fixe entre un point et un objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance</name>
+    <message>
+      <source>Select objects for distance definition. Following objects can be accepted: point, line or arc end point, center of circle or arc.</source>
+      <translation>Sélectionnez des objets pour la définition de la distance. Les objets suivants peuvent être acceptés : point, ligne ou arc point final, centre du cercle ou arc.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityA</name>
+    <message>
+      <source>First object</source>
+      <translation>Premier objet</translation>
+    </message>
+    <message>
+      <source>Select point, line end point, line, center of circle or arc.</source>
+      <translation>Sélectionner un point, une fin de ligne, une ligne, le centre du cercle ou un arc.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintEntityB</name>
+    <message>
+      <source>Second object</source>
+      <translation>Deuxième objet</translation>
+    </message>
+    <message>
+      <source>Select point, line end point, line, center of circle or arc.</source>
+      <translation>Sélectionner un point, une fin de ligne, une ligne, le centre du cercle ou un arc.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:ConstraintValue</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Value</source>
+      <translation>Valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:LocationType</name>
+    <message>
+      <source>Automatic</source>
+      <translation>Automatique</translation>
+    </message>
+    <message>
+      <source>Left</source>
+      <translation>Gauche</translation>
+    </message>
+    <message>
+      <source>Right</source>
+      <translation>Droite</translation>
+    </message>
+    <message>
+      <source>Text location</source>
+      <translation>Localisation du texte</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistance:SignedDistance</name>
+    <message>
+      <source>Keep distance orientation</source>
+      <translation>Garder l&apos;orientation de la distance</translation>
+    </message>
+    <message>
+      <source>Keep orientation</source>
+      <translation>Gardez l&apos;orientation</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintDistanceHorizontal</name>
+    <message>
+      <source>Horizontal Distance</source>
+      <translation>Distance horizontale</translation>
+    </message>
+    <message>
+      <source>Set horizontal distance between two points</source>
+      <translation>Définir la distance horizontale entre deux points</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintEntityA</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal</name>
+    <message>
+      <source>Select points for distance definition.</source>
+      <translation>Sélectionner des points pour la définition de la distance.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintEntityA</name>
+    <message>
+      <source>First point</source>
+      <translation>Premier point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintEntityB</name>
+    <message>
+      <source>Second point</source>
+      <translation>Deuxième point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintEntityB</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:DistanceValue</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Value</source>
+      <translation>Valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:DistanceValue:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Double n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:DistanceValue:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La valeur est trop petite</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:LocationType</name>
+    <message>
+      <source>Automatic</source>
+      <translation>Automatique</translation>
+    </message>
+    <message>
+      <source>Left</source>
+      <translation>Gauche</translation>
+    </message>
+    <message>
+      <source>Right</source>
+      <translation>Droite</translation>
+    </message>
+    <message>
+      <source>Text location</source>
+      <translation>Localisation du texte</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceHorizontal:ConstraintFlyoutValuePnt</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintDistanceVertical</name>
+    <message>
+      <source>Set vertical distance between two points</source>
+      <translation>Définir la distance verticale entre deux points</translation>
+    </message>
+    <message>
+      <source>Vertical Distance</source>
+      <translation>Distance verticale</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical</name>
+    <message>
+      <source>Select points for distance definition.</source>
+      <translation>Sélectionner des points pour la définition de la distance.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:ConstraintEntityA</name>
+    <message>
+      <source>First point</source>
+      <translation>Premier point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:ConstraintEntityA:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:ConstraintEntityB</name>
+    <message>
+      <source>Second point</source>
+      <translation>Deuxième point</translation>
+    </message>
+    <message>
+      <source>Select point.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:ConstraintEntityB:GeomValidators_ShapeType</name>
+    <message>
+      <source>The object is empty</source>
+      <translation>L&apos;objet est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:DistanceValue</name>
+    <message>
+      <source>Distance</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>Value</source>
+      <translation>Valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:DistanceValue:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Double n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:LocationType</name>
+    <message>
+      <source>Automatic</source>
+      <translation>Automatique</translation>
+    </message>
+    <message>
+      <source>Left</source>
+      <translation>Gauche</translation>
+    </message>
+    <message>
+      <source>Right</source>
+      <translation>Droite</translation>
+    </message>
+    <message>
+      <source>Text location</source>
+      <translation>Localisation du texte</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:ConstraintFlyoutValuePnt</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintDistanceVertical:DistanceValue:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La valeur est trop petite.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintEqual</name>
+    <message>
+      <source>Create constraint defining equal lengths of two lines or line and arc or equal radiuses of two arcs or two circles or arc and circle</source>
+      <translation>Créer une contrainte définissant des longueurs égales de deux lignes, ou une ligne et un arc, ou des rayons égaux de deux arcs ou de deux cercles ou d&apos;un arc et d&apos;un cercle</translation>
+    </message>
+    <message>
+      <source>Equal</source>
+      <translation>Égal</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityA</name>
+    <message>
+      <source>First object</source>
+      <translation>Premier objet</translation>
+    </message>
+    <message>
+      <source>Select line, circle or arc</source>
+      <translation>Sélectionnez une ligne, un cercle ou un arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintEqual:ConstraintEntityB</name>
+    <message>
+      <source>Second object</source>
+      <translation>Deuxième objet</translation>
+    </message>
+    <message>
+      <source>Select line, circle or arc</source>
+      <translation>Sélectionnez une ligne, un cercle ou un arc</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintHorizontal</name>
+    <message>
+      <source>Create constraint defining horizontal line</source>
+      <translation>Créer une contrainte définissant une ligne horizontale</translation>
+    </message>
+    <message>
+      <source>Horizontal</source>
+      <translation>Horizontal</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintHorizontal:ConstraintEntityA</name>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintLength</name>
+    <message>
+      <source>Length</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>Set fixed length of a line segment</source>
+      <translation>Définir la longueur fixe d&apos;un segment</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength</name>
+    <message>
+      <source>Select a line on which to calculate length</source>
+      <translation>Sélectionnez une ligne sur laquelle calculer la longueur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintEntityA</name>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:ConstraintValue</name>
+    <message>
+      <source>Length</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>Value</source>
+      <translation>Valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintLength:LocationType</name>
+    <message>
+      <source>Automatic</source>
+      <translation>Automatique</translation>
+    </message>
+    <message>
+      <source>Left</source>
+      <translation>Gauche</translation>
+    </message>
+    <message>
+      <source>Right</source>
+      <translation>Droite</translation>
+    </message>
+    <message>
+      <source>Text location</source>
+      <translation>Localisation du texte</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintMiddle</name>
+    <message>
+      <source>Create constraint for setting middle point on a line</source>
+      <translation>Créer une contrainte pour définir le milieu de la ligne</translation>
+    </message>
+    <message>
+      <source>Middle point</source>
+      <translation>Point milieu</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityA</name>
+    <message>
+      <source>First object</source>
+      <translation>Premier objet</translation>
+    </message>
+    <message>
+      <source>Select a first object</source>
+      <translation>Sélectionnez un premier objet</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMiddle:ConstraintEntityB</name>
+    <message>
+      <source>Second object</source>
+      <translation>Deuxième objet</translation>
+    </message>
+    <message>
+      <source>Select a second object</source>
+      <translation>Sélectionnez un deuxième objet</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintMirror</name>
+    <message>
+      <source>Create constraint, mirroring group of objects</source>
+      <translation>Créer une contrainte, mettre en miroir un groupe d&apos;objets</translation>
+    </message>
+    <message>
+      <source>Mirror copy</source>
+      <translation>Copie miroir</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintEntityA</name>
+    <message>
+      <source>Mirror line</source>
+      <translation>Ligne miroir</translation>
+    </message>
+    <message>
+      <source>Select mirror line</source>
+      <translation>Sélectionnez la ligne miroir</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintMirror:ConstraintMirrorList</name>
+    <message>
+      <source>Select list of objects to be mirrored</source>
+      <translation>Sélectionner la liste des objets à mettre en miroir</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintParallel</name>
+    <message>
+      <source>Create constraint defining two parallel lines</source>
+      <translation>Créer une contrainte définissant deux lignes parallèles</translation>
+    </message>
+    <message>
+      <source>Parallel</source>
+      <translation>Parallèle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityA</name>
+    <message>
+      <source>First line</source>
+      <translation>Première ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintParallel:ConstraintEntityB</name>
+    <message>
+      <source>Second line</source>
+      <translation>Deuxième ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintPerpendicular</name>
+    <message>
+      <source>Create constraint defining two orthogonal objects</source>
+      <translation>Créer une contrainte définissant deux objets orthogonaux</translation>
+    </message>
+    <message>
+      <source>Perpendicular</source>
+      <translation>Perpendiculaire</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityA</name>
+    <message>
+      <source>First object</source>
+      <translation>Premier objet</translation>
+    </message>
+    <message>
+      <source>Select line or arc</source>
+      <translation>Sélectionnez une ligne ou un arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintPerpendicular:ConstraintEntityB</name>
+    <message>
+      <source>Second object</source>
+      <translation>Deuxième objet</translation>
+    </message>
+    <message>
+      <source>Select line or arc</source>
+      <translation>Sélectionnez une ligne ou un arc</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintRadius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+    <message>
+      <source>Set fixed radius of a circle or an arc</source>
+      <translation>Définir le rayon fixe d&apos;un cercle ou d&apos;un arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius</name>
+    <message>
+      <source>Select a circle or an arc on which to calculate radius</source>
+      <translation>Sélectionnez un cercle ou un arc sur lequel calculer le rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintEntityA</name>
+    <message>
+      <source>Circle or Arc</source>
+      <translation>Cercle ou arc</translation>
+    </message>
+    <message>
+      <source>Select a circle or an arc</source>
+      <translation>Sélectionnez un cercle ou un arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:ConstraintValue</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+    <message>
+      <source>Value</source>
+      <translation>Valeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRadius:LocationType</name>
+    <message>
+      <source>Automatic</source>
+      <translation>Automatique</translation>
+    </message>
+    <message>
+      <source>Left</source>
+      <translation>Gauche</translation>
+    </message>
+    <message>
+      <source>Right</source>
+      <translation>Droite</translation>
+    </message>
+    <message>
+      <source>Text location</source>
+      <translation>Localisation du texte</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintRigid</name>
+    <message>
+      <source>Fix an object</source>
+      <translation>Maintenir un objet</translation>
+    </message>
+    <message>
+      <source>Fixed</source>
+      <translation>Fixé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintRigid:ConstraintEntityA</name>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Select point, line end point, line, center of circle or arc.</source>
+      <translation>Sélectionner un point, une fin de ligne, une ligne, le centre du cercle ou un arc.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintTangent</name>
+    <message>
+      <source>Create constraint defining tangency of two segments with common coincident point</source>
+      <translation>Créer une contrainte définissant la tangence de deux segments avec un point de coïncidence commun</translation>
+    </message>
+    <message>
+      <source>Tangent</source>
+      <translation>Tangente</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityA</name>
+    <message>
+      <source>First object</source>
+      <translation>Premier objet</translation>
+    </message>
+    <message>
+      <source>Select line or arc</source>
+      <translation>Sélectionnez une ligne ou un arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityB</name>
+    <message>
+      <source>Second object</source>
+      <translation>Deuxième objet</translation>
+    </message>
+    <message>
+      <source>Select line or arc</source>
+      <translation>Sélectionnez une ligne ou un arc</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchConstraintVertical</name>
+    <message>
+      <source>Create constraint defining vertical line</source>
+      <translation>Créer une contrainte définissant une ligne verticale</translation>
+    </message>
+    <message>
+      <source>Vertical</source>
+      <translation>Verticale</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintVertical:ConstraintEntityA</name>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+    <message>
+      <source>Select a line</source>
+      <translation>Sélectionnez une ligne</translation>
+    </message>
+  </context>
+
+  <!-- SketchDrawer -->
+  <context>
+    <name>SketchDrawer</name>
+    <message>
+      <source>Creates sketch using elements of selected shape belonging to selected plane</source>
+      <translation>Crée une esquisse en utilisant des éléments de la forme sélectionnée appartenant au plan sélectionné</translation>
+    </message>
+    <message>
+      <source>Sketch drawer</source>
+      <translation>Tiroir à esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchDrawer:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchDrawer:add_dimensions</name>
+    <message>
+      <source>Create dimensions</source>
+      <translation>Créer des dimensions</translation>
+    </message>
+    <message>
+      <source>To add dimensions into created sketch</source>
+      <translation>Pour ajouter des cotes à l&apos;esquisse créée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchDrawer:base_shape</name>
+    <message>
+      <source>Select a shape for extraction to sketch.</source>
+      <translation>Sélectionnez une forme à extraire pour l&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Shape:</source>
+      <translation>Forme:</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchDrawer:plane</name>
+    <message>
+      <source>Plane:</source>
+      <translation>Plan:</translation>
+    </message>
+    <message>
+      <source>Select plane for sketch</source>
+      <translation>Sélectionner un plan pour l&apos;esquisse</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchFillet</name>
+    <message>
+      <source>Create constraint defining fillet between two connected segments</source>
+      <translation>Créer une contrainte définissant un congé entre deux segments connectés</translation>
+    </message>
+    <message>
+      <source>Fillet</source>
+      <translation>Congé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un ou plusieurs points pour le congé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:fillet_point</name>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+    <message>
+      <source>Select point for fillet (should be shared by two entities only)</source>
+      <translation>Sélectionnez un point pour le congé (doit être partagé par deux entités uniquement)</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchFillet:fillet_point:SketchPlugin_FilletVertexValidator</name>
+    <message>
+      <source>Error: Bad point selected.</source>
+      <translation>Erreur : mauvais point sélectionné.</translation>
+    </message>
+    <message>
+      <source>Error: Edges in selected point has tangent constraint.</source>
+      <translation>Erreur : les arêtes du point sélectionné ont une contrainte de tangence.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchIntersectionPoint</name>
+    <message>
+      <source>Intersect edge with sketch plane</source>
+      <translation>Intersecter un bord avec un plan d&apos;esquisse</translation>
+    </message>
+    <message>
+      <source>Intersection</source>
+      <translation>Section</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchIntersectionPoint:ExternalFeature</name>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Select external edge.</source>
+      <translation>Sélectionnez le bord externe.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchIntersectionPoint:ExternalFeature:SketchPlugin_IntersectionValidator</name>
+    <message>
+      <source>The attribute %1 should be an edge</source>
+      <translation>L&apos;attribut %1 doit être une arête</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchIntersectionPoint:IncludeToResult</name>
+    <message>
+      <source>Include into the sketch result</source>
+      <translation>Inclure dans le résultat de l&apos;esquisse</translation>
+    </message>
+    <message>
+      <source>Include projected feature into the sketch result</source>
+      <translation>Inclure la fonctionnalité projetée dans le résultat de l&apos;esquisse</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchIntersectionPoint:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchIntersectionPoint:ExternalFeature</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le bord externe.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchLine</name>
+    <message>
+      <source>Create line</source>
+      <translation>Créer une ligne</translation>
+    </message>
+    <message>
+      <source>Line</source>
+      <translation>Ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchLine:LineLength</name>
+    <message>
+      <source>Length:</source>
+      <translation>Longueur:</translation>
+    </message>
+    <message>
+      <source>Line length</source>
+      <translation>Longueur de la ligne</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroArc</name>
+    <message>
+      <source>Arc</source>
+      <translation>Arc</translation>
+    </message>
+    <message>
+      <source>Create arc</source>
+      <translation>Créer un arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:center_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:arc_type</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:angle</name>
+    <message>
+      <source>Set angle</source>
+      <translation>Définir l&apos;angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:arc_type</name>
+    <message>
+      <source>Center and two points</source>
+      <translation>Centre et deux points</translation>
+    </message>
+    <message>
+      <source>Perpendicular to line</source>
+      <translation>Perpendiculaire à la ligne</translation>
+    </message>
+    <message>
+      <source>Tangent with edge</source>
+      <translation>Tangente avec bord</translation>
+    </message>
+    <message>
+      <source>Three points on arc</source>
+      <translation>Trois points sur l&apos;arc</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:passed_point:SketchPlugin_ThirdPointValidator</name>
+    <message>
+      <source>Selected points are on the same line</source>
+      <translation>Les points sélectionnés sont sur la même ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:radius</name>
+    <message>
+      <source>Set radius</source>
+      <translation>Définir le rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:tangent_point</name>
+    <message>
+      <source>Select point on line</source>
+      <translation>Sélectionnez un point sur la ligne</translation>
+    </message>
+    <message>
+      <source>Tangent point</source>
+      <translation>Point tangent</translation>
+    </message>
+    <message>
+      <source>Point on the perpendicular line</source>
+      <translation>Point sur la perpendiculaire</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:tangent_point:SketchPlugin_ArcTangentPoint</name>
+    <message>
+      <source>The attribute %1 should be a point</source>
+      <translation>L&apos;attribut %1 doit être un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:tangent_point:SketchPlugin_ArcTransversalPoint</name>
+    <message>
+      <source>The attribute %1 should be a point</source>
+      <translation>L&apos;attribut %1 doit être un point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:tangent_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:center_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point central.</translation>
+    </message>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_1</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point d&apos;arrivée dans la vue.</translation>
+    </message>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_1</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point d&apos;arrivée dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_2</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_3</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:passed_point</name>
+    <message>
+      <source>Passed point</source>
+      <translation>Point passé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:passed_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_1</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point de départ.</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_2</name>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:angle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_2</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:radius</name>
+    <message>
+      <source>Radius</source>
+      <translation>Rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_1</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_2</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:tangent_point:SketchPlugin_ArcTransversalPoint</name>
+    <message>
+      <source>Unable to build perpendicular arc on %1</source>
+      <translation>Impossible de créer un arc perpendiculaire sur %1</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_2</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_3</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_2</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point dans la vue.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroCircle</name>
+    <message>
+      <source>Circle</source>
+      <translation>Cercle</translation>
+    </message>
+    <message>
+      <source>Create circle</source>
+      <translation>Créer un cercle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Un point central n&apos;est pas sélectionné</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:circle_radius</name>
+    <message>
+      <source>Set radius</source>
+      <translation>Définir le rayon</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:circle_radius:GeomValidators_Positive</name>
+    <message>
+      <source>Value is too small.</source>
+      <translation>La valeur est trop petite.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:circle_type</name>
+    <message>
+      <source>Center and passed points</source>
+      <translation>Points centrés et passés</translation>
+    </message>
+    <message>
+      <source>Three points</source>
+      <translation>Trois points</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:third_point:SketchPlugin_ThirdPointValidator</name>
+    <message>
+      <source>Selected points are on the same line</source>
+      <translation>Les points sélectionnés sont sur la même ligne</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:first_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:second_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:third_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:circle_type</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:second_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le deuxième point.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroEllipse</name>
+    <message>
+      <source>Create ellipse</source>
+      <translation>Créer une ellipse</translation>
+    </message>
+    <message>
+      <source>Ellipse</source>
+      <translation>Ellipse</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:ellipse_type</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:passed_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:ellipse_type</name>
+    <message>
+      <source>Center, major semi-axis and passing point</source>
+      <translation>Centre, grand demi-axe et point de passage</translation>
+    </message>
+    <message>
+      <source>Major axis and passing point</source>
+      <translation>Grand axe et point de passage</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:first_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un premier point dans la vue.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:major_radius</name>
+    <message>
+      <source>Set major radius</source>
+      <translation>Définir le rayon majeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:major_radius:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Double n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:minor_radius</name>
+    <message>
+      <source>Set minor radius</source>
+      <translation>Définir le rayon mineur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:minor_radius:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Double n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:first_point</name>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+    <message>
+      <source>Major axis start point</source>
+      <translation>Point de départ du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point passé.</translation>
+    </message>
+    <message>
+      <source>Passed point</source>
+      <translation>Point passé</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:second_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un deuxième point.</translation>
+    </message>
+    <message>
+      <source>Major axis end point</source>
+      <translation>Point final du grand axe</translation>
+    </message>
+    <message>
+      <source>Major axis point</source>
+      <translation>Point du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:second_point</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchEllipse:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_center</name>
+    <message>
+      <source>Center</source>
+      <translation>Centre</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_first_focus</name>
+    <message>
+      <source>First focus</source>
+      <translation>Premier foyer</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_major_axis_end_point</name>
+    <message>
+      <source>Major axis end</source>
+      <translation>Fin du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_major_axis_start_point</name>
+    <message>
+      <source>Major axis start</source>
+      <translation>Début du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_major_radius</name>
+    <message>
+      <source>Set major radius</source>
+      <translation>Définir le rayon majeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_minor_axis_end_point</name>
+    <message>
+      <source>Minor axis end</source>
+      <translation>Fin du petit axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_minor_axis_start_point</name>
+    <message>
+      <source>Minor axis start</source>
+      <translation>Début du petit axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_minor_radius</name>
+    <message>
+      <source>Set minor radius</source>
+      <translation>Définir le rayon mineur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_second_focus</name>
+    <message>
+      <source>Second focus</source>
+      <translation>Deuxième objectif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_major_radius</name>
+    <message>
+      <source>Major radius</source>
+      <translation>Rayon majeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipse:ellipse_minor_radius</name>
+    <message>
+      <source>Minor radius</source>
+      <translation>Rayon mineur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:major_radius</name>
+    <message>
+      <source>Major radius</source>
+      <translation>Rayon majeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:minor_radius</name>
+    <message>
+      <source>Minor radius</source>
+      <translation>Rayon mineur</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchEllipticArc:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_center</name>
+    <message>
+      <source>Center</source>
+      <translation>Centre</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_first_focus</name>
+    <message>
+      <source>First focus</source>
+      <translation>Premier foyer</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_major_axis_end_point</name>
+    <message>
+      <source>Major axis end</source>
+      <translation>Fin du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_major_axis_start_point</name>
+    <message>
+      <source>Major axis start</source>
+      <translation>Début du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_major_radius</name>
+    <message>
+      <source>Major radius</source>
+      <translation>Rayon majeur</translation>
+    </message>
+    <message>
+      <source>Set major radius</source>
+      <translation>Définir le rayon majeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_minor_axis_end_point</name>
+    <message>
+      <source>Minor axis end</source>
+      <translation>Fin du petit axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_minor_axis_start_point</name>
+    <message>
+      <source>Minor axis start</source>
+      <translation>Début du petit axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_minor_radius</name>
+    <message>
+      <source>Minor radius</source>
+      <translation>Rayon mineur</translation>
+    </message>
+    <message>
+      <source>Set minor radius</source>
+      <translation>Définir le rayon mineur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:ellipse_second_focus</name>
+    <message>
+      <source>Second focus</source>
+      <translation>Deuxième objectif</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:end_point</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchEllipticArc:start_point</name>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc</name>
+    <message>
+      <source>Create elliptic arc</source>
+      <translation>Créer un arc elliptique</translation>
+    </message>
+    <message>
+      <source>Elliptic arc</source>
+      <translation>Arc elliptique</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:center</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point central.</translation>
+    </message>
+    <message>
+      <source>Center point</source>
+      <translation>Point central</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:end_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point d&apos;arrivée.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point d&apos;arrivée.</translation>
+    </message>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:major_axis_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Sélectionnez un point d&apos;axe majeur.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un point d&apos;axe majeur.</translation>
+    </message>
+    <message>
+      <source>Major axis point</source>
+      <translation>Point du grand axe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:major_radius</name>
+    <message>
+      <source>Major radius</source>
+      <translation>Rayon majeur</translation>
+    </message>
+    <message>
+      <source>Set major radius</source>
+      <translation>Définir le rayon majeur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:major_radius:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Double n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:minor_radius</name>
+    <message>
+      <source>Minor radius</source>
+      <translation>Rayon mineur</translation>
+    </message>
+    <message>
+      <source>Set minor radius</source>
+      <translation>Définir le rayon mineur</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:minor_radius:GeomValidators_Positive</name>
+    <message>
+      <source>Double is not initialized.</source>
+      <translation>Double n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:start_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>L&apos;attribut &quot;%1&quot; est verrouillé par la valeur de modification dans la vue.</translation>
+    </message>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+  </context>
+  <context>
+    <name>workshop</name>
+    <message>
+      <source>Elliptic arc</source>
+      <translation>Arc elliptique</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMultiRotation</name>
+    <message>
+      <source>Angular copy</source>
+      <translation>Copie angulaire</translation>
+    </message>
+    <message>
+      <source>Copy objects and rotate</source>
+      <translation>Copier des objets et faire pivoter</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:AngleType</name>
+    <message>
+      <source>Full angle</source>
+      <translation>Angle complet</translation>
+    </message>
+    <message>
+      <source>Single angle</source>
+      <translation>Angle unique</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationAngle</name>
+    <message>
+      <source>Angle</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>Rotation angle</source>
+      <translation>Angle de rotation</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationCenter</name>
+    <message>
+      <source>Center of rotation</source>
+      <translation>Centre de rotation</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationList</name>
+    <message>
+      <source>Segments:</source>
+      <translation>Segments:</translation>
+    </message>
+    <message>
+      <source>Select list of objects to be rotated</source>
+      <translation>Sélectionnez la liste des objets à faire pivoter</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationObjects</name>
+    <message>
+      <source>Total number of objects</source>
+      <translation>Nombre total d&apos;objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiRotation:MultiRotationReversed</name>
+    <message>
+      <source>Reverse angular copy</source>
+      <translation>Copie angulaire inverse</translation>
+    </message>
+    <message>
+      <source>Reversed</source>
+      <translation>Renversé</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMultiTranslation</name>
+    <message>
+      <source>Copy objects and move</source>
+      <translation>Copier des objets et les déplacer</translation>
+    </message>
+    <message>
+      <source>Direction</source>
+      <translation>Direction</translation>
+    </message>
+    <message>
+      <source>Linear copy</source>
+      <translation>Copie linéaire</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationEndPoint</name>
+    <message>
+      <source>End point</source>
+      <translation>Point final</translation>
+    </message>
+    <message>
+      <source>Final point of translation</source>
+      <translation>Dernier point de translation</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationList</name>
+    <message>
+      <source>Segments:</source>
+      <translation>Segments:</translation>
+    </message>
+    <message>
+      <source>Select list of objects to be translated</source>
+      <translation>Sélectionner la liste des objets à translater</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationObjects</name>
+    <message>
+      <source>Total number of objects</source>
+      <translation>Nombre total d&apos;objets</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:MultiTranslationStartPoint</name>
+    <message>
+      <source>Start point</source>
+      <translation>Point de départ</translation>
+    </message>
+    <message>
+      <source>Start point of translation</source>
+      <translation>Point de départ de la translation</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMultiTranslation:ValueType</name>
+    <message>
+      <source>Full value</source>
+      <translation>Pleine valeur</translation>
+    </message>
+    <message>
+      <source>Single value</source>
+      <translation>Valeur unique</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchPoint</name>
+    <message>
+      <source>Create point</source>
+      <translation>Créer un point</translation>
+    </message>
+    <message>
+      <source>Point</source>
+      <translation>Point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchPoint:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchProjection</name>
+    <message>
+      <source>Project feature onto sketch plane</source>
+      <translation>Projeter une entité sur un plan d&apos;esquisse</translation>
+    </message>
+    <message>
+      <source>Projection</source>
+      <translation>Projection</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature</name>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Select external edge or vertex.</source>
+      <translation>Sélectionnez une arête externe ou un sommet.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Un argument de type %1 de la fonctionnalité de projection n&apos;est pas pris en charge</translation>
+    </message>
+    <message>
+      <source>The attribute %1 should be an edge or vertex</source>
+      <translation>L&apos;élément projeté doit être une arête ou un sommet</translation>
+    </message>
+    <message>
+      <source>There is no sketch referring to the current feature</source>
+      <translation>La fonction de projection n&apos;a pas d&apos;esquisse</translation>
+    </message>
+    <message>
+      <source>Unable to project feature from the same sketch</source>
+      <translation>Les fonctions de l&apos;esquisse en cours ne peuvent pas être projetées</translation>
+    </message>
+    <message>
+      <source>Error: Line is orthogonal to the sketch plane.</source>
+      <translation>Erreur : La ligne est orthogonale au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Circle is orthogonal to the sketch plane.</source>
+      <translation>Erreur : Le cercle est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Arc is orthogonal to the sketch plane.</source>
+      <translation>Erreur : L&apos;arc est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Ellipse is orthogonal to the sketch plane.</source>
+      <translation>Erreur : L’ellipse est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
+      <translation>Erreur : L&apos;arc elliptique est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Selected object is not supported for projection.</source>
+      <translation>Erreur : L&apos;objet sélectionné n&apos;est pas pris en charge pour la projection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:IncludeToResult</name>
+    <message>
+      <source>Include into the sketch result</source>
+      <translation>Inclure dans le résultat de l&apos;esquisse</translation>
+    </message>
+    <message>
+      <source>Include projected feature into the sketch result</source>
+      <translation>Inclure la fonctionnalité projetée dans le résultat de l&apos;esquisse</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchRectangle</name>
+    <message>
+      <source>Create rectangle</source>
+      <translation>Créer un rectangle</translation>
+    </message>
+    <message>
+      <source>Rectangle</source>
+      <translation>Rectangle</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:Auxiliary</name>
+    <message>
+      <source>Auxiliary</source>
+      <translation>Auxiliaire</translation>
+    </message>
+    <message>
+      <source>Construction element</source>
+      <translation>Élément de construction</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchSplit</name>
+    <message>
+      <source>Cut selected segment arc or circle on existing coincident points</source>
+      <translation>Couper l&apos;arc ou le cercle du segment sélectionné sur les points coïncidents existants</translation>
+    </message>
+    <message>
+      <source>Split</source>
+      <translation>Diviser</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchSplit:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un segment à diviser dans la vue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchSplit:SelectedObject</name>
+    <message>
+      <source>Segment</source>
+      <translation>Segment</translation>
+    </message>
+    <message>
+      <source>Select segment for split</source>
+      <translation>Sélectionnez le segment à diviser</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchSplit:SelectedObject:SketchPlugin_SplitValidator</name>
+    <message>
+      <source>Unknown error.</source>
+      <translation>Erreur inconnue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchSplit:SelectedObject</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le segment à diviser</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchTrim</name>
+    <message>
+      <source>Trim</source>
+      <translation>Réduire</translation>
+    </message>
+    <message>
+      <source>Trim selected segment arc or circle on intersection points nearest to the graphic selection</source>
+      <translation>Couper l&apos;arc ou le cercle du segment sélectionné sur les points d&apos;intersection les plus proches de la sélection graphique</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchTrim:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchTrim:SelectedObject</name>
+    <message>
+      <source>Segment</source>
+      <translation>Segment</translation>
+    </message>
+    <message>
+      <source>Select segment for trim</source>
+      <translation>Sélectionner un segment pour la coupe</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchTrim:SelectedObject:SketchPlugin_TrimValidator</name>
+    <message>
+      <source>Unknown error.</source>
+      <translation>Erreur inconnue.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchTrim:SelectedObject</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionner un segment pour la coupe</translation>
+    </message>
+  </context>
+
+</TS>
diff --git a/src/SketchPlugin/Test/Test3087_1.py b/src/SketchPlugin/Test/Test3087_1.py
new file mode 100644 (file)
index 0000000..92a0fe4
--- /dev/null
@@ -0,0 +1,63 @@
+# 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 salome.shaper import model
+
+from EventsAPI import *
+from ModelAPI import *
+
+class FreeShapesListener(EventsAPI.Events_Listener):
+    def __init__(self):
+        Events_Listener.__init__(self)
+        # register as a listener
+        Events_Loop.loop().registerListener(self, Events_Loop.eventByName("DoFObjects"))
+        self.myEventProcessed = False
+
+    def __del__(self):
+        Events_Loop.loop().removeListener(self)
+
+    def processEvent(self, theMessage):
+        message = messageToUpdatedMessage(theMessage)
+        objs = message.objects()
+        assert(len(objs) == 3)
+        self.myEventProcessed = True
+
+
+if __name__ == "__main__":
+    # create the listener
+    listener = FreeShapesListener()
+
+    model.begin()
+    partSet = model.moduleDocument()
+    Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+    SketchLine_1 = Sketch_1.addLine(10, 10, -10, 10)
+    SketchLine_2 = Sketch_1.addLine(-10, 10, -10, -10)
+    SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+    SketchLine_3 = Sketch_1.addLine(-10, -10, 10, -10)
+    SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+    SketchConstraintRigid_1 = Sketch_1.setFixed(SketchLine_1.startPoint())
+    SketchConstraintRigid_2 = Sketch_1.setFixed(SketchLine_3.endPoint())
+    model.end()
+
+    # send message to find the free shapes in the sketch
+    event = Events_Loop.eventByName("GetDoFObjects")
+    ModelAPI_EventCreator.get().sendUpdated(Sketch_1.feature(), event);
+    Events_Loop.loop().flush(event);
+
+    assert(listener.myEventProcessed)
diff --git a/src/SketchPlugin/Test/Test3087_2.py b/src/SketchPlugin/Test/Test3087_2.py
new file mode 100644 (file)
index 0000000..4fb18ea
--- /dev/null
@@ -0,0 +1,66 @@
+# 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 salome.shaper import model
+
+from EventsAPI import *
+from ModelAPI import *
+
+class FreeShapesListener(EventsAPI.Events_Listener):
+    def __init__(self):
+        Events_Listener.__init__(self)
+        # register as a listener
+        Events_Loop.loop().registerListener(self, Events_Loop.eventByName("DoFObjects"))
+        self.myEventProcessed = False
+
+    def __del__(self):
+        Events_Loop.loop().removeListener(self)
+
+    def processEvent(self, theMessage):
+        message = messageToUpdatedMessage(theMessage)
+        objs = message.objects()
+        assert(len(objs) == 4)
+        self.myEventProcessed = True
+
+
+if __name__ == "__main__":
+    # create the listener
+    listener = FreeShapesListener()
+
+    model.begin()
+    partSet = model.moduleDocument()
+    Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+    SketchLine_1 = Sketch_1.addLine(10, 10, -10, 10)
+    SketchLine_2 = Sketch_1.addLine(-10, 10, -10, -10)
+    SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+    SketchLine_3 = Sketch_1.addLine(-10, -10, 10, -10)
+    SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+    SketchConstraintRigid_1 = Sketch_1.setFixed(SketchLine_1.startPoint())
+    SketchConstraintRigid_2 = Sketch_1.setFixed(SketchLine_3.endPoint())
+    SketchCircle_1 = Sketch_1.addCircle(-10, 10, 10)
+    SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchCircle_1.center())
+    SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10)
+    model.end()
+
+    # send message to find the free shapes in the sketch
+    event = Events_Loop.eventByName("GetDoFObjects")
+    ModelAPI_EventCreator.get().sendUpdated(Sketch_1.feature(), event);
+    Events_Loop.loop().flush(event);
+
+    assert(listener.myEventProcessed)
index 413331d7238e016769e7f86fc8a4af98e61818b4..f230ce1d4ade5583923676cac0376bb2371a206f 100644 (file)
@@ -44,7 +44,7 @@ SketchConstraintDistanceHorizontal_1.feature().real("ConstraintValue").setText(D
 model.do()
 
 # changing the parameter
-for param in range(-30, 31, 2):
+for param in range(-31, 30, 2):
     if param == 0:
         continue
     DistanceParam.setValue(param)
@@ -68,7 +68,7 @@ SketchConstraintDistanceVertical_1.feature().real("ConstraintValue").setText(Dis
 model.do()
 
 # changing the parameter
-for param in range(-30, 31, 2):
+for param in range(-31, 30, 2):
     if param == 0:
         continue
     DistanceParam.setValue(param)
@@ -94,8 +94,10 @@ model.do()
 for param in range(-30, 31, 2):
     DistanceParam.setValue(param)
     model.do()
-    if param <= 0:
+    if param < 0:
         assert SketchConstraintDistance_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
+    elif param == 0: # constraint is valid, but lead to degenerated geometry
+        assert Sketch_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
     else:
         dist = model.distancePointPoint(firstPoint, secondPoint)
         assert math.fabs(dist - math.fabs(param)) < TOLERANCE, "Incorrect distance {}, expected {}".format(dist, math.fabs(param))
index 1a6bcbfa1d035154aa5e25004750f27f565873ce..155f4d79eaa8ee6a76086042770caf461acfee96 100644 (file)
@@ -117,17 +117,14 @@ assert (model.dof(aSketchFeature) == 3)
 #=========================================================================
 # Change a distance value
 #=========================================================================
-d = DISTANCE1 + 20.
+d = DISTANCE1 + 21.
 dStep = -5.
 while d >= -30.:
     aSession.startOperation()
     DISTANCE1 = d
     aDistance.setValue(DISTANCE1)
     aSession.finishOperation()
-    if DISTANCE1 == 0:
-        assert(aHDist1.error() != "")
-    else:
-        assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
     d += dStep
 assert (model.dof(aSketchFeature) == 3)
 
@@ -154,18 +151,15 @@ assert (model.dof(aSketchFeature) == 2)
 # Change a distance value (check previous constraint is applied too)
 #=========================================================================
 d = DISTANCE2
-dStep = -5.
+dStep = -7.
 while d >= -50.:
     aSession.startOperation()
     DISTANCE2 = d
     aDistance.setValue(DISTANCE2)
     aSession.finishOperation()
-    if DISTANCE2 == 0:
-        assert(aHDist2.error() != "")
-    else:
-        assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
-        assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
-        assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+    assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+    assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
     d += dStep
 assert (model.dof(aSketchFeature) == 2)
 
@@ -216,16 +210,13 @@ assert (model.dof(aSketchFeature) == 6)
 # Change a distance value
 #=========================================================================
 d = DISTANCE3
-dStep = -5.
+dStep = -7.
 while d >= -50.:
     aSession.startOperation()
     DISTANCE3 = d
     aDistance.setValue(DISTANCE3)
     aSession.finishOperation()
-    if DISTANCE3 == 0:
-        assert(aHDist3.error() != "")
-    else:
-        assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+    assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
     d += dStep
 assert (model.dof(aSketchFeature) == 6)
 
diff --git a/src/SketchPlugin/Test/TestConstraintDistanceHorizontalZero.py b/src/SketchPlugin/Test/TestConstraintDistanceHorizontalZero.py
new file mode 100644 (file)
index 0000000..cccb7b9
--- /dev/null
@@ -0,0 +1,122 @@
+# 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
+#
+
+"""
+    Test the zero value of the constraint "DistanceHorizontal"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistanceHorizontal(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+    self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+    self.myLine3 = self.mySketch.addLine(10, 0, 10, 10)
+    model.do()
+    self.myDOF = 12
+
+  def tearDown(self):
+    model.end()
+    model.checkSketch(self.mySketch, self.myDOF)
+
+  def assertDistanceHorizontal(self, theObject1, theObject2, theDistance):
+    dist = theObject2.x() - theObject1.x()
+    self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+    model.checkSketch(self.mySketch, self.myDOF)
+
+
+  def test_distance_positive_nzznz(self):
+    """ Test 1. Change distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+  def test_distance_negative_nzznz(self):
+    """ Test 2. Change distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setHorizontalDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 15)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), -15)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), -10)
+
+  def test_distance_equal_znzz(self):
+    """ Test 3. Change distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+  def test_distance_notequal_znzz(self):
+    """ Test 4. Change distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
index b4365147f67b06b0567650fafd1d9b46466b2b4f..8c0b1b6c384ed24730540c88a0dcf6d1b28e1a68 100644 (file)
@@ -117,17 +117,14 @@ assert (model.dof(aSketchFeature) == 3)
 #=========================================================================
 # Change a distance value
 #=========================================================================
-d = DISTANCE1 + 20.
+d = DISTANCE1 + 21.
 dStep = -5.
 while d >= -30.:
     aSession.startOperation()
     DISTANCE1 = d
     aDistance.setValue(DISTANCE1)
     aSession.finishOperation()
-    if DISTANCE1 == 0:
-        assert(aVDist1.error() != "")
-    else:
-        assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
     d += dStep
 assert (model.dof(aSketchFeature) == 3)
 
@@ -154,18 +151,15 @@ assert (model.dof(aSketchFeature) == 2)
 # Change a distance value (check previous constraint is applied too)
 #=========================================================================
 d = DISTANCE2
-dStep = -5.
+dStep = -7.
 while d >= -50.:
     aSession.startOperation()
     DISTANCE2 = d
     aDistance.setValue(DISTANCE2)
     aSession.finishOperation()
-    if DISTANCE2 == 0:
-        assert(aVDist2.error() != "")
-    else:
-        assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
-        assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
-        assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+    assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+    assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
     d += dStep
 assert (model.dof(aSketchFeature) == 2)
 
@@ -216,16 +210,13 @@ assert (model.dof(aSketchFeature) == 6)
 # Change a distance value
 #=========================================================================
 d = DISTANCE3
-dStep = -5.
+dStep = -7.
 while d >= -50.:
     aSession.startOperation()
     DISTANCE3 = d
     aDistance.setValue(DISTANCE3)
     aSession.finishOperation()
-    if DISTANCE3 == 0:
-        assert(aVDist3.error() != "")
-    else:
-        assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+    assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
     d += dStep
 assert (model.dof(aSketchFeature) == 6)
 
diff --git a/src/SketchPlugin/Test/TestConstraintDistanceVerticalZero.py b/src/SketchPlugin/Test/TestConstraintDistanceVerticalZero.py
new file mode 100644 (file)
index 0000000..7578a72
--- /dev/null
@@ -0,0 +1,122 @@
+# 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
+#
+
+"""
+    Test the zero value of the constraint "DistanceVertical"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistanceVertical(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+    self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+    self.myLine3 = self.mySketch.addLine(0, 10, 10, 10)
+    model.do()
+    self.myDOF = 12
+
+  def tearDown(self):
+    model.end()
+    model.checkSketch(self.mySketch, self.myDOF)
+
+  def assertDistanceVertical(self, theObject1, theObject2, theDistance):
+    dist = theObject2.y() - theObject1.y()
+    self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+    model.checkSketch(self.mySketch, self.myDOF)
+
+
+  def test_distance_positive_nzznz(self):
+    """ Test 1. Change distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine2.startPoint(), 5)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 5)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+  def test_distance_negative_nzznz(self):
+    """ Test 2. Change distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setVerticalDistance(self.myLine1.endPoint(), self.myLine2.startPoint(), 12.5)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), -12.5)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(12.5)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), -12.5)
+
+  def test_distance_equal_znzz(self):
+    """ Test 3. Change distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+  def test_distance_notequal_znzz(self):
+    """ Test 4. Change distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
diff --git a/src/SketchPlugin/Test/TestConstraintDistanceZero.py b/src/SketchPlugin/Test/TestConstraintDistanceZero.py
new file mode 100644 (file)
index 0000000..cf9a69d
--- /dev/null
@@ -0,0 +1,188 @@
+# 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
+#
+
+"""
+    Test the zero value of the constraint "Distance"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistance(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+    self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+    self.myLine3 = self.mySketch.addLine(10, 0, 10, 10)
+    model.do()
+    self.myDOF = 12
+
+  def tearDown(self):
+    model.end()
+    model.checkSketch(self.mySketch, self.myDOF)
+
+  def assertDistance(self, theObject1, theObject2, theDistance, isSigned = False):
+    dist = -1.
+    if issubclass(type(theObject1), SketchAPI_SketchEntity):
+      if isSigned:
+        dist = model.signedDistancePointLine(theObject2, theObject1)
+      else:
+        dist = model.distancePointLine(theObject2, theObject1)
+    elif issubclass(type(theObject2), SketchAPI_SketchEntity):
+      if isSigned:
+        dist = model.signedDistancePointLine(theObject1, theObject2)
+      else:
+        dist = model.distancePointLine(theObject1, theObject2)
+    else:
+      dist = model.distancePointPoint(theObject1, theObject2)
+    self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+    model.checkSketch(self.mySketch, self.myDOF)
+
+
+  def test_distance_points_nzznz(self):
+    """ Test 1. Change point-point distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(20)
+    self.myDOF += 1
+    model.do()
+    self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+
+  def test_distance_points_znzz(self):
+    """ Test 2. Change point-point distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+    self.myDOF -= 2
+    model.do()
+    self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    self.myDOF += 1
+    model.do()
+    self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+
+  def test_unsigned_distance_nzznz(self):
+    """ Test 3. Change unsigned point-line distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setDistance(self.myLine1.result(), self.myLine2.endPoint(), 20)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine2.endPoint(), 20)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine2.endPoint(), 0)
+
+    SketchAPI_Constraint(dist).setValue(20)
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine2.endPoint(), 20)
+
+  def test_unsigned_distance_znzz(self):
+    """ Test 4. Change unsigned point-line distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setDistance(self.myLine2.startPoint(), self.myLine1.result(), 0)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistance(self.myLine2.startPoint(), self.myLine1, 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+
+  def test_signed_distance_nzznz(self):
+    """ Test 5. Change signed point-line distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setDistance(self.myLine1.result(), self.myLine2.endPoint(), 20, True)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine2.endPoint(), -20, True)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine2.endPoint(), 0, True)
+
+    SketchAPI_Constraint(dist).setValue(20)
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine2.endPoint(), -20, True)
+
+  def test_signed_distance_nzznz_2(self):
+    """ Test 6. Change signed point-line distance from non-zero to zero and back to non-zero
+    """
+    dist = self.mySketch.setDistance(self.myLine3.startPoint(), self.myLine1.result(), 10, True)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine3.startPoint(), 10, True)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine3.startPoint(), 0, True)
+
+    SketchAPI_Constraint(dist).setValue(20)
+    model.do()
+    self.assertDistance(self.myLine1, self.myLine3.startPoint(), 20, True)
+
+  def test_signed_distance_znzz(self):
+    """ Test 7. Change signed point-line distance from zero to non-zero and back to zero
+    """
+    dist = self.mySketch.setDistance(self.myLine2.startPoint(), self.myLine1.result(), 0, True)
+    self.myDOF -= 1
+    model.do()
+    self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+    SketchAPI_Constraint(dist).setValue(10)
+    model.do()
+    self.assertDistance(self.myLine2.startPoint(), self.myLine1, 10)
+
+    SketchAPI_Constraint(dist).setValue(0)
+    model.do()
+    self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
index 72e5e02322787366753fc443bb571aaec699fad5..0c77e447d5153401b62893cc661dca412ea02427 100644 (file)
@@ -189,7 +189,7 @@ class TestTangentEllipticArc(unittest.TestCase):
     self.myDOF += 4
     model.do()
 
-    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.mySketch.setTangent(aLine.result(), self.myEllipticArc.result())
     self.myNbTangency += 1
     self.myDOF -= 1
     model.do()
diff --git a/src/SketchPlugin/Test/TestMoveEllipticArc.py b/src/SketchPlugin/Test/TestMoveEllipticArc.py
new file mode 100644 (file)
index 0000000..a1d02e6
--- /dev/null
@@ -0,0 +1,298 @@
+# 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
+#
+
+"""
+    Test movement of the sketch ellipse
+"""
+
+import unittest
+import math
+from GeomAPI import GeomAPI_Pnt2d
+from SketchAPI import *
+from salome.shaper import model
+
+__updated__ = "2019-10-15"
+
+class TestMoveEllipticArc(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myCenter = GeomAPI_Pnt2d(70., 50.)
+    self.myAxisPoint = GeomAPI_Pnt2d(100., 70.)
+    self.myStartPoint = GeomAPI_Pnt2d(75., 75.)
+    self.myEndPoint = GeomAPI_Pnt2d(45., 55.)
+    macroEllipticArc = self.mySketch.addEllipticArc(self.myCenter, self.myAxisPoint, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF = 7
+    model.do()
+    self.checkDOF()
+    self.myEllipticArc = SketchAPI_EllipticArc(model.lastSubFeature(self.mySketch, "SketchEllipticArc"))
+    self.myMajorRadius = self.myEllipticArc.majorRadius().value()
+    self.myMinorRadius = self.myEllipticArc.minorRadius().value()
+
+  def tearDown(self):
+    self.checkDOF()
+    self.checkPointOnEllipse(self.myEllipticArc.startPoint(), self.myEllipticArc)
+    self.checkPointOnEllipse(self.myEllipticArc.endPoint(), self.myEllipticArc)
+    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 checkPointOnEllipse(self, theCoordinates, theEllipticArc):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipticArc.firstFocus().x(), theEllipticArc.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipticArc.secondFocus().x(), theEllipticArc.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * theEllipticArc.majorRadius().value(), 7 - math.floor(math.log10(theEllipticArc.majorRadius().value())))
+
+  def fixMajorRadius(self):
+    self.mySketch.setDistance(self.myEllipticArc.center(), self.myEllipticArc.majorAxisPositive(), self.myMajorRadius)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+  def fixMinorRadius(self):
+    self.mySketch.setDistance(self.myEllipticArc.center(), self.myEllipticArc.minorAxisPositive(), self.myMinorRadius)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+  def fixPoint(self, thePoint):
+    self.mySketch.setFixed(thePoint)
+    self.myDOF -= 2
+    model.do()
+    self.checkDOF()
+
+
+  def test_move_center_free_ellipse(self):
+    """ Test 1. Movement of central point of a free elliptic arc
+    """
+    newPosition = [self.myCenter.x() + 20., self.myCenter.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), newPosition)
+
+  def test_move_free_ellipse(self):
+    """ Test 2. Movement of a free ellipse dragging the edge
+    """
+    newPosition = GeomAPI_Pnt2d(110., 80.)
+    self.mySketch.move(self.myEllipticArc.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), self.myCenter)
+    self.checkPointOnEllipse(newPosition, self.myEllipticArc)
+    self.assertNotEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_center_ellipse_fixed_major_radius(self):
+    """ Test 3. Movement of central point of ellipse with fixed major radius
+    """
+    self.fixMajorRadius()
+
+    newPosition = [self.myCenter.x() + 20., self.myCenter.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), newPosition)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_ellipse_fixed_major_radius(self):
+    """ Test 4. Movement of ellipse with fixed major radius
+    """
+    self.fixMajorRadius()
+
+    newPosition = GeomAPI_Pnt2d(80., 80.)
+    self.mySketch.move(self.myEllipticArc.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipticArc)
+    self.assertNotEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_center_ellipse_fixed_minor_radius(self):
+    """ Test 5. Movement of central point of ellipse with fixed minor radius
+    """
+    self.fixMinorRadius()
+
+    newPosition = [self.myCenter.x() + 20., self.myCenter.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), newPosition)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+
+  def test_move_ellipse_fixed_minor_radius(self):
+    """ Test 6. Movement of ellipse with fixed minor radius
+    """
+    self.fixMinorRadius()
+
+    newPosition = GeomAPI_Pnt2d(110., 80.)
+    self.mySketch.move(self.myEllipticArc.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipticArc)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_center_ellipse_fixed_center(self):
+    """ Test 7. Movement of central point of ellipse with fixed center (nothing should be changed)
+    """
+    self.fixPoint(self.myEllipticArc.center())
+
+    newPosition = [self.myCenter.x() + 20., self.myCenter.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), self.myCenter)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_ellipse_fixed_center(self):
+    """ Test 8. Movement of ellipse with fixed center
+    """
+    self.fixPoint(self.myEllipticArc.center())
+
+    newPosition = GeomAPI_Pnt2d(110., 80.)
+    self.mySketch.move(self.myEllipticArc.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipticArc)
+    self.assertNotEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_center_ellipse_fixed_focus(self):
+    """ Test 9. Movement of central point of ellipse with fixed focus
+    """
+    focus = [self.myEllipticArc.firstFocus().x(), self.myEllipticArc.firstFocus().y()]
+    self.fixPoint(self.myEllipticArc.firstFocus())
+
+    newPosition = GeomAPI_Pnt2d(self.myCenter.x() + 20., self.myCenter.y() + 10.)
+    self.mySketch.move(self.myEllipticArc.center(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), newPosition)
+    self.checkPointCoordinates(self.myEllipticArc.firstFocus(), focus)
+    self.assertNotEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_focus_ellipse_fixed_focus(self):
+    """ Test 10. Movement of a focus point of ellipse with fixed focus (nothing should be changed)
+    """
+    focus = [self.myEllipticArc.firstFocus().x(), self.myEllipticArc.firstFocus().y()]
+    self.fixPoint(self.myEllipticArc.firstFocus())
+
+    newPosition = GeomAPI_Pnt2d(focus[0] + 10., focus[1] + 10.)
+    self.mySketch.move(self.myEllipticArc.firstFocus(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.firstFocus(), focus)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_ellipse_fixed_focus(self):
+    """ Test 11. Movement of ellipse with fixed focus
+    """
+    focus = [self.myEllipticArc.firstFocus().x(), self.myEllipticArc.firstFocus().y()]
+    self.fixPoint(self.myEllipticArc.firstFocus())
+
+    newPosition = GeomAPI_Pnt2d(80., 90.)
+    self.mySketch.move(self.myEllipticArc.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipticArc)
+    self.checkPointCoordinates(self.myEllipticArc.firstFocus(), focus)
+    self.assertNotEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_fixed_ellipse(self):
+    """ Test 12. Trying to move fully fixed ellipse
+    """
+    self.mySketch.setFixed(self.myEllipticArc.results()[-1])
+    self.myDOF -= 7
+    model.do()
+    self.checkDOF()
+
+    newPosition = [110., 80.]
+    self.mySketch.move(self.myEllipticArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myEllipticArc.majorAxisPositive(), self.myAxisPoint)
+    self.checkPointCoordinates(self.myEllipticArc.startPoint(), self.myStartPoint)
+    self.checkPointCoordinates(self.myEllipticArc.endPoint(), self.myEndPoint)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+
+  def test_move_start_point_free_ellipse(self):
+    """ Test 13. Trying to move start point of elliptic arc
+    """
+    newPosition = [self.myStartPoint.x() + 10., self.myStartPoint.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.startPoint(), newPosition)
+
+  def test_move_end_point_free_ellipse(self):
+    """ Test 14. Trying to move end point of elliptic arc
+    """
+    newPosition = [self.myEndPoint.x() - 10., self.myEndPoint.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.endPoint(), newPosition)
+
+  def test_move_start_point_fixed_ellipse(self):
+    """ Test 15. Trying to move start point of fully fixed ellipse
+    """
+    self.mySketch.setFixed(self.myEllipticArc.results()[-1])
+    self.myDOF -= 7
+    model.do()
+    self.checkDOF()
+
+    newPosition = [self.myStartPoint.x() + 10., self.myStartPoint.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myEllipticArc.majorAxisPositive(), self.myAxisPoint)
+    self.checkPointCoordinates(self.myEllipticArc.startPoint(), self.myStartPoint)
+    self.checkPointCoordinates(self.myEllipticArc.endPoint(), self.myEndPoint)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+
+  def test_move_end_point_fixed_ellipse(self):
+    """ Test 16. Trying to move end point of fully fixed ellipse
+    """
+    self.mySketch.setFixed(self.myEllipticArc.results()[-1])
+    self.myDOF -= 7
+    model.do()
+    self.checkDOF()
+
+    newPosition = [self.myEndPoint.x() - 10., self.myEndPoint.y() + 10.]
+    self.mySketch.move(self.myEllipticArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipticArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myEllipticArc.majorAxisPositive(), self.myAxisPoint)
+    self.checkPointCoordinates(self.myEllipticArc.startPoint(), self.myStartPoint)
+    self.checkPointCoordinates(self.myEllipticArc.endPoint(), self.myEndPoint)
+    self.assertAlmostEqual(self.myEllipticArc.majorRadius().value(), self.myMajorRadius)
+    self.assertAlmostEqual(self.myEllipticArc.minorRadius().value(), self.myMinorRadius)
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
index 9f251831d5b2354dad301854c7c6f96d5af0922d..b3400e70e822c20d0f326ab14451918e04fec697 100644 (file)
@@ -29,6 +29,7 @@ from GeomDataAPI import *
 
 from ConfigAPI import *
 Config_PropManager().registerProp("Visualization", "dimension_value_size", "Dimension value size", Config_Prop.IntSpin, "16")
+Config_PropManager().registerProp("Visualization", "sketch_dimension_color", "Dimension color", Config_Prop.Color, "64,128,255")
 
 model.begin()
 partSet = model.moduleDocument()
diff --git a/src/SketchPlugin/Test/TestRemainingDoF.py b/src/SketchPlugin/Test/TestRemainingDoF.py
new file mode 100644 (file)
index 0000000..539c2df
--- /dev/null
@@ -0,0 +1,65 @@
+# 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 salome.shaper import model
+
+from EventsAPI import *
+from ModelAPI import *
+
+class FreeShapesListener(EventsAPI.Events_Listener):
+    def __init__(self):
+        Events_Listener.__init__(self)
+        # register as a listener
+        Events_Loop.loop().registerListener(self, Events_Loop.eventByName("DoFObjects"))
+        self.myEventProcessed = False
+
+    def __del__(self):
+        Events_Loop.loop().removeListener(self)
+
+    def processEvent(self, theMessage):
+        message = messageToUpdatedMessage(theMessage)
+        objs = message.objects()
+        assert(len(objs) == 1)
+        assert(objectToFeature(objs[0]).getKind() == "SketchCircle")
+        self.myEventProcessed = True
+
+
+if __name__ == "__main__":
+    # create the listener
+    listener = FreeShapesListener()
+
+    model.begin()
+    partSet = model.moduleDocument()
+    Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+    SketchCircle_1 = Sketch_1.addCircle(-30, 0, 14)
+    SketchLine_1 = Sketch_1.addLine(-30, 0, 0, 0)
+    SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_1.startPoint())
+    SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+    SketchPoint_1 = SketchProjection_1.createdFeature()
+    SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchPoint_1.result())
+    SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+    SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+    model.end()
+
+    # send message to find the free shapes in the sketch
+    event = Events_Loop.eventByName("GetDoFObjects")
+    ModelAPI_EventCreator.get().sendUpdated(Sketch_1.feature(), event);
+    Events_Loop.loop().flush(event);
+
+    assert(listener.myEventProcessed)
index 41db2b754e19100799469df257e27cb95fc1ad04..04a861a8102c4799d043c03271f80d30a20b0d71 100644 (file)
@@ -51,6 +51,7 @@ After the plane for sketch is selected, the following property panel will be ope
 - **Show free points** check box - highlights free points in the current sketch if it is checked.
 - **Automatic constraints** - automatically create horizontal or vertical constraints if angle between created line and horizontal or vertical less then angular tolerance (defined in preferences).
 - **Change sketch plane** button - allows to change working plane of the current sketch.
+- **Show remaining DoFs** button - highlights all sketch edges which are not fully constrained.
 
 Now it is possible to:
 
@@ -141,6 +142,26 @@ The plug-in includes the following constraints:
 
 .. _sketch_operations:
 
+Overconstraned state
+--------------------
+
+Sketcher comes into overconstrained state when an extra constraint was defined. The following picture shows an example of the overconstrained state:
+
+.. image:: images/Overconstrained.png
+   :align: center
+
+.. centered::
+  Overconstrained Sketch
+
+When Sketcher becomes into the 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.
+
 Operations
 ----------
 Operations modify existing features of the sketch or create new ones by copying them.
diff --git a/src/SketchPlugin/doc/images/Overconstrained.png b/src/SketchPlugin/doc/images/Overconstrained.png
new file mode 100644 (file)
index 0000000..c1a8967
Binary files /dev/null and b/src/SketchPlugin/doc/images/Overconstrained.png differ
index 90316748c5f252135ade1e48ad1a6beadd50f2b8..51b57cf2e0ae44544b6622d6712fc71dca4edcbe 100644 (file)
Binary files a/src/SketchPlugin/doc/images/SketchPanel.png and b/src/SketchPlugin/doc/images/SketchPanel.png differ
index eef35764893f6b9a8407b37b0b0262a9f1d89fe4..0c77223de177eb7e0fabc366fd3c5e1002df68e6 100644 (file)
@@ -25,8 +25,7 @@
         <sketch-start-label id="External" geometrical_selection="true" title="Select a plane on which to create a sketch" tooltip="Select a plane on which to create a sketch">
           <validator id="GeomValidators_Face" parameters="plane"/>
         </sketch-start-label>
-        <!-- <label id="SolverDOF"/>  -->
-        <label id="SolverError" styleSheet="color : red; font : bold"/>
+        <undo_label id="SolverError" isHTML="true" />
         <validator id="SketchPlugin_SolverErrorValidator"/>
       </feature>
 
@@ -35,7 +34,7 @@
                 helpfile="pointFeature.html">
         <sketch-2dpoint_selector id="PointCoordinates" accept_expressions="0" title="Point" tooltip="Point coordinates"
                                  enable_value="enable_by_preferences"/>
-        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
       </feature>
 
       <!-- SketchLine -->
@@ -47,7 +46,7 @@
                                  enable_value="enable_by_preferences"/>
         <labelvalue id="LineLength" accept_expressions="0" label="Length" default="computed" icon="icons/Sketch/distance_value.png"
                      tooltip="Line length" obligatory="0" enable_value="false"/>
-        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
         <validator id="GeomValidators_Different" parameters="StartPoint,EndPoint"/>
       </feature>
     </group>
@@ -71,7 +70,7 @@
                     accept_expressions="0"
                     enable_value="enable_by_preferences">
         </labelvalue>
-        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
       </feature>
       <!-- SketchMacroCircle -->
       <feature id="SketchMacroCircle"
                    tooltip="Construction element"
                    label="Auxiliary"
                    default="false"
-                   obligatory="0"/>
+                   obligatory="0"
+                   change_visual_attributes="true"/>
       </feature>
 
       <!-- SketchArc -->
                    label="Auxiliary"
                    tooltip="Construction element"
                    default="false"
-                   obligatory="0"/>
+                   obligatory="0"
+                   change_visual_attributes="true"/>
       </feature>
 
       <!-- SketchMacroArc -->
                    label="Auxiliary"
                    tooltip="Construction element"
                    default="false"
-                   obligatory="0"/>
+                   obligatory="0"
+                   change_visual_attributes="true"/>
       </feature>
 
       <!--  SketchFillet  -->
                     accept_expressions="0"
                     enable_value="enable_by_preferences">
         </labelvalue>
-        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
       </feature>
       <!-- SketchMacroEllipse -->
       <feature id="SketchMacroEllipse"
                    tooltip="Construction element"
                    label="Auxiliary"
                    default="false"
-                   obligatory="0"/>
+                   obligatory="0"
+                   change_visual_attributes="true"/>
       </feature>
 
       <!-- SketchEllipticArc is a hidden feature. It is created inside SketchMacroEllipse. -->
                     accept_expressions="0"
                     enable_value="enable_by_preferences">
         </labelvalue>
-        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
       </feature>
       <!-- SketchMacroEllipticArc -->
       <feature id="SketchMacroEllipticArc"
                    tooltip="Construction element"
                    label="Auxiliary"
                    default="false"
-                   obligatory="0"/>
+                   obligatory="0"
+                   change_visual_attributes="true"/>
       </feature>
     </group>
 
               use_sketch_plane="false">
           <validator id="SketchPlugin_ProjectionValidator"/>
         </sketch_shape_selector>
-        <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"/>
+        <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"
+                   change_visual_attributes="true"/>
         <validator id="PartSet_ProjectionSelection"/>
       </feature>
 
               use_sketch_plane="false">
           <validator id="SketchPlugin_IntersectionValidator"/>
         </sketch_shape_selector>
-        <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"/>
+        <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"
+                   change_visual_attributes="true"/>
         <validator id="PartSet_IntersectionSelection"/>
       </feature>
     </group>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
           <validator id="PartSet_DifferentObjects"/>
           <validator id="GeomValidators_ShapeType" parameters="vertex,line"/>
-          <validator id="PartSet_DifferentPoints" parameters="ConstraintEntityB"/>
         </sketch_shape_selector>
         <sketch_shape_selector
           id="ConstraintEntityB"
           <validator id="SketchPlugin_DistanceAttr" parameters="ConstraintEntityA"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
           <validator id="GeomValidators_ShapeType" parameters="vertex,line"/>
-          <validator id="PartSet_DifferentPoints" parameters="ConstraintEntityA"/>
         </sketch_shape_selector>
         <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
 
         <doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed" min="0">
-          <validator id="GeomValidators_Positive"/>
+          <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
         </doublevalue_editor>
 
         <module_choice id="LocationType"
         <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
 
         <doublevalue_editor label="Value" tooltip="Distance" id="DistanceValue" default="computed" min="0">
-          <validator id="GeomValidators_Positive"/>
+          <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
         </doublevalue_editor>
 
         <module_choice id="LocationType"
         <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
 
         <doublevalue_editor label="Value" tooltip="Distance" id="DistanceValue" default="computed" min="0">
-          <validator id="GeomValidators_Positive"/>
+          <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
         </doublevalue_editor>
 
         <module_choice id="LocationType"
       <!--  SketchConstraintAngle  -->
       <feature id="SketchConstraintAngle" title="Angle" tooltip="Set fixed angle between two line segments" icon="icons/Sketch/angle_constr.png"
                helpfile="angleFeature.html">
-        <sketch_shape_selector id="ConstraintEntityA" label="Line 1" tooltip="Select a line" shape_types="edge" >
+        <sketch_feature_point_selector
+            id="ConstraintEntityA"
+            selection_attributes="ConstraintEntityA SelectedPointA"
+            label="Line 1"
+            tooltip="Select a line"
+            shape_types="edge"
+            use_external="true">
           <validator id="GeomValidators_ShapeType" parameters="line"/>
           <validator id="PartSet_DifferentObjects"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
-        </sketch_shape_selector>
-        <sketch_shape_selector id="ConstraintEntityB" label="Line 2" tooltip="Select a line" shape_types="edge" >
+        </sketch_feature_point_selector>
+        <sketch_feature_point_selector
+            id="ConstraintEntityB"
+            selection_attributes="ConstraintEntityB SelectedPointB"
+            label="Line 2"
+            tooltip="Select a line"
+            shape_types="edge"
+            use_external="true">
           <validator id="GeomValidators_ShapeType" parameters="line"/>
           <validator id="PartSet_DifferentObjects"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
-        </sketch_shape_selector>
+        </sketch_feature_point_selector>
         <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
         <doublevalue_editor label="Value" tooltip="Angle" id="AngleValue" default="computed" min="0" max="360" />
         <validator id="PartSet_AngleSelection"/>
index 90e3ca7fb10dc372efde8d1813980d3ee467b2b6..fafa0372ac5780f3b4d4905d4985d8a3f2498eca 100644 (file)
@@ -93,6 +93,7 @@ SET(SKETCHSOLVER_LIBRARIES
 
 SET(SKETCHSOLVER_TEXT_RESOURCES
     SketchSolver_msg_en.ts
+    SketchSolver_msg_fr.ts
 )
 
 INCLUDE_DIRECTORIES(
index 6e6a6642f44f92a1eb6fd814da61c010fe203f37..de38dfcdb087bc79945b049645e5c84998a34ac9 100644 (file)
@@ -54,5 +54,5 @@ void PlaneGCSSolver_ConstraintWrapper::setValue(const double& theValue)
 
 double PlaneGCSSolver_ConstraintWrapper::value() const
 {
-  return myValueParam->value();
+  return myValueParam ? myValueParam->value() : 0.0;
 }
index 416b338b05d4dadbedc3a8da7686886c34ece178..716022c9865700605a7f480187bc1fff6dfc4e76 100644 (file)
@@ -62,11 +62,11 @@ void PlaneGCSSolver_Solver::addConstraint(const ConstraintID& theMultiConstraint
     GCSConstraintPtr aConstraint = *anIt;
     aConstraint->setTag(anID);
     myEquationSystem->addConstraint(aConstraint.get());
-    myConstraints[theMultiConstraintID].insert(aConstraint);
 
     if (anID > CID_UNKNOWN)
       ++anID;
   }
+  myConstraints[theMultiConstraintID] = theConstraints;
 
   if (theMultiConstraintID >= CID_UNKNOWN)
     myDOF = -1;
@@ -77,7 +77,7 @@ void PlaneGCSSolver_Solver::removeConstraint(const ConstraintID& theID)
 {
   ConstraintMap::iterator aFound = myConstraints.find(theID);
   if (aFound != myConstraints.end()) {
-    for (std::set<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
+    for (std::list<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
          anIt != aFound->second.end(); ++anIt)
       myEquationSystem->clearByTag((*anIt)->getTag());
 
@@ -243,6 +243,99 @@ void PlaneGCSSolver_Solver::diagnose(const GCS::Algorithm& theAlgo)
   myDiagnoseBeforeSolve = false;
 }
 
+void PlaneGCSSolver_Solver::getFreeParameters(GCS::SET_pD& theFreeParams)
+{
+  if (myConstraints.empty())
+    theFreeParams.insert(myParameters.begin(), myParameters.end());
+  else {
+    GCS::VEC_pD aParametersCopy = myParameters;
+    ConstraintMap aConstraintCopy = myConstraints;
+
+    // clear the set of equations
+    clear();
+    // reset constraints
+    myParameters = aParametersCopy;
+    for (ConstraintMap::iterator anIt = aConstraintCopy.begin();
+         anIt != aConstraintCopy.end(); ++anIt)
+      addConstraint(anIt->first, anIt->second);
+
+    // parameters detection works for Dense QR only
+    GCS::QRAlgorithm aQRAlgo = myEquationSystem->qrAlgorithm;
+    myEquationSystem->qrAlgorithm = GCS::EigenDenseQR;
+    diagnose();
+    GCS::VEC_pD aFreeParams;
+    myEquationSystem->getDependentParams(aFreeParams);
+    theFreeParams.insert(aFreeParams.begin(), aFreeParams.end());
+    // revert QR decomposition algorithm
+    myEquationSystem->qrAlgorithm = aQRAlgo;
+  }
+
+  if (theFreeParams.empty())
+    return;
+
+  // find all equal parameters too
+  struct EqualParameters
+  {
+    typedef std::map<double*, std::list<GCS::SET_pD>::iterator> MapParamGroup;
+
+    std::list<GCS::SET_pD> myEqualParams;
+    MapParamGroup myGroups;
+
+    void add(double* theParam1, double* theParam2)
+    {
+      MapParamGroup::iterator aFound1 = myGroups.find(theParam1);
+      MapParamGroup::iterator aFound2 = myGroups.find(theParam2);
+
+      if (aFound1 == myGroups.end()) {
+        if (aFound2 == myGroups.end()) {
+          // create new group
+          myEqualParams.push_back(GCS::SET_pD());
+          std::list<GCS::SET_pD>::iterator aGroup = --myEqualParams.end();
+          aGroup->insert(theParam1);
+          aGroup->insert(theParam2);
+          myGroups[theParam1] = aGroup;
+          myGroups[theParam2] = aGroup;
+        }
+        else {
+          // add first parameter to the second group
+          aFound2->second->insert(theParam1);
+          myGroups[theParam1] = aFound2->second;
+        }
+      }
+      else {
+        if (aFound2 == myGroups.end()) {
+          // add second parameter to the first group
+          aFound1->second->insert(theParam2);
+          myGroups[theParam2] = aFound1->second;
+        }
+        else if (aFound1 != aFound2) {
+          // merge two groups
+          GCS::SET_pD aCopy = *(aFound2->second);
+          myEqualParams.erase(aFound2->second);
+          for (GCS::SET_pD::iterator anIt = aCopy.begin(); anIt != aCopy.end(); ++anIt)
+            myGroups[*anIt] = aFound1->second;
+          aFound1->second->insert(aCopy.begin(), aCopy.end());
+        }
+      }
+    }
+  } anEqualParams;
+
+  for (ConstraintMap::iterator anIt = myConstraints.begin(); anIt != myConstraints.end(); ++anIt)
+    for (std::list<GCSConstraintPtr>::iterator aCIt = anIt->second.begin();
+         aCIt != anIt->second.end(); ++aCIt) {
+      if ((*aCIt)->getTypeId() == GCS::Equal)
+        anEqualParams.add((*aCIt)->params()[0], (*aCIt)->params()[1]);
+    }
+
+  GCS::SET_pD aFreeParamsCopy = theFreeParams;
+  for (GCS::SET_pD::iterator anIt = aFreeParamsCopy.begin();
+       anIt != aFreeParamsCopy.end(); ++anIt) {
+    EqualParameters::MapParamGroup::iterator aFound = anEqualParams.myGroups.find(*anIt);
+    if (aFound != anEqualParams.myGroups.end())
+      theFreeParams.insert(aFound->second->begin(), aFound->second->end());
+  }
+}
+
 void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
 {
   bool hasOnlyMovement = true;
index 4fb2abce9eafd65f615cecdbf8d6941eb84a0430..96c198dbb0fb85d2969485ae8c2381c520a310d6 100644 (file)
@@ -79,6 +79,9 @@ public:
   /// \brief Check conflicting/redundant constraints and DoF
   void diagnose(const GCS::Algorithm& theAlgo = GCS::DogLeg);
 
+  /// \brief Return the list of modifiable parameters
+  void getFreeParameters(GCS::SET_pD& theFreeParams);
+
   /// \brief Degrees of freedom
   int dof();
 
@@ -91,7 +94,7 @@ private:
   void removeFictiveConstraint();
 
 private:
-  typedef std::map<ConstraintID, std::set<GCSConstraintPtr> > ConstraintMap;
+  typedef std::map<ConstraintID, std::list<GCSConstraintPtr> > ConstraintMap;
 
   GCS::VEC_pD                  myParameters;     ///< list of unknowns
   ConstraintMap                myConstraints;    ///< list of constraints
index 4f546aacce57e886154834202d6e9f626bccaec8..a5788f23a82f8e37224d769a52f4c91cf07bc89e 100644 (file)
@@ -654,3 +654,24 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeome
   }
   return PlaneGCSSolver_Solver::STATUS_OK;
 }
+
+
+void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
+{
+  std::set<double*> aFreeParams;
+  mySketchSolver->getFreeParameters(aFreeParams);
+  if (aFreeParams.empty())
+    return;
+
+  for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+       aFIt != myFeatureMap.end(); ++aFIt) {
+    if (!aFIt->second)
+      continue;
+    GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
+    for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
+      if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
+        theFeatures.insert(aFIt->first);
+        break;
+      }
+  }
+}
index eafa686c47620bee46177f3dd8d7568fbf534955..8d452a85749a10032aa4098f74b26b0ce91fe9e7 100644 (file)
@@ -95,6 +95,9 @@ public:
   ///        Reversed arcs should have the last parameter lesser than the first parameter.
   virtual void adjustParametrizationOfArcs();
 
+  /// \brief Return list of features which are not fully constrained
+  virtual void getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const;
+
 private:
   /// \brief Convert feature using specified builder.
   EntityWrapperPtr createFeature(const FeaturePtr&             theFeature,
index 0850933a000bdfb5e2847c328412462f2e5c2c2b..29568114d22fe8d033ab6e7054ccdb5142fa6fcf 100644 (file)
@@ -25,6 +25,7 @@
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <PlaneGCSSolver_Storage.h>
 #include <PlaneGCSSolver_Tools.h>
+#include <PlaneGCSSolver_UpdateCoincidence.h>
 
 #include <SketchPlugin_ConstraintDistanceHorizontal.h>
 #include <SketchPlugin_ConstraintDistanceVertical.h>
@@ -71,6 +72,86 @@ static void adjustOddPoint(const EntityWrapperPtr& theDistPoint,
   *(theOddPoint->y) = aProjectedPnt->y();
 }
 
+static FeaturePtr getFeature(AttributeRefAttrPtr theRefAttr)
+{
+  ObjectPtr anObj;
+  if (theRefAttr->isObject())
+    anObj = theRefAttr->object();
+  else
+    anObj = theRefAttr->attr()->owner();
+  return ModelAPI_Feature::feature(anObj);
+}
+
+static void calculateDistanceDirection(const ConstraintPtr& theConstraint,
+                                       const StoragePtr& theStorage,
+                                       double& theDirX, double& theDirY)
+{
+  std::shared_ptr<GeomDataAPI_Dir> aDistDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      theConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID()));
+  if (aDistDir && aDistDir->isInitialized()) {
+    theDirX = aDistDir->x();
+    theDirY = aDistDir->y();
+    if (fabs(theDirX) > tolerance || fabs(theDirY) > tolerance)
+      return;
+  }
+
+  AttributeRefAttrPtr aRefAttrA = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+  AttributeRefAttrPtr aRefAttrB = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+
+  EntityWrapperPtr aEntityA = theStorage->entity(aRefAttrA);
+  EntityWrapperPtr aEntityB = theStorage->entity(aRefAttrB);
+
+  GCSPointPtr aPoint;
+  if (aEntityA->type() != ENTITY_LINE && aEntityB->type() != ENTITY_LINE) {
+    aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aEntityA)->point();
+    theDirX = 1.0;
+    theDirY = 0.0;
+
+    EdgeWrapperPtr anEdgeA = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+        theStorage->entity(getFeature(aRefAttrA)));
+    EdgeWrapperPtr anEdgeB = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+        theStorage->entity(getFeature(aRefAttrB)));
+
+    if (anEdgeA && anEdgeB) {
+      GCS::DeriVector2 aDirA = anEdgeA->entity()->CalculateNormal(*aPoint);
+      GCS::DeriVector2 aDirB = anEdgeB->entity()->CalculateNormal(*aPoint);
+      double x = -aDirA.x + aDirB.x;
+      double y = -aDirA.y + aDirB.y;
+      double norm = sqrt(x*x + y*y);
+      if (norm > tolerance) {
+        theDirX = x / norm;
+        theDirY = y / norm;
+      }
+    }
+  }
+}
+
+static void moveEntity(const ConstraintPtr& theConstraint,
+                       const StoragePtr& theStorage,
+                       const double theDX, const double theDY)
+{
+  static const double THE_SHIFT = 1.e-4;
+
+  AttributeRefAttrPtr aRefAttrA = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+  AttributeRefAttrPtr aRefAttrB = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+
+  EntityWrapperPtr aEntityA = theStorage->entity(aRefAttrA);
+  EntityWrapperPtr aEntityB = theStorage->entity(aRefAttrB);
+
+  PointWrapperPtr aPointA = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aEntityA);
+  PointWrapperPtr aPointB = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aEntityB);
+
+  if (aPointA) {
+    *aPointA->point()->x -= THE_SHIFT * theDX;
+    *aPointA->point()->y -= THE_SHIFT * theDY;
+  }
+  else if (aPointB) {
+    *aPointB->point()->x += THE_SHIFT * theDX;
+    *aPointB->point()->y += THE_SHIFT * theDY;
+  }
+}
+
+
 
 void SketchSolver_ConstraintDistance::getAttributes(
     EntityWrapperPtr& theValue,
@@ -82,21 +163,30 @@ void SketchSolver_ConstraintDistance::getAttributes(
     return;
   }
 
+  ScalarWrapperPtr aValue = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theValue);
+  bool isCoincidence = fabs(aValue->value()) < tolerance;
+
   if (theAttributes[1]) {
     if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
       myType = CONSTRAINT_HORIZONTAL_DISTANCE;
     else if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
       myType = CONSTRAINT_VERTICAL_DISTANCE;
     else
-      myType = CONSTRAINT_PT_PT_DISTANCE;
+      myType = isCoincidence ? CONSTRAINT_PT_PT_COINCIDENT : CONSTRAINT_PT_PT_DISTANCE;
   } else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
-    myType = CONSTRAINT_PT_LINE_DISTANCE;
+    myType = isCoincidence ? CONSTRAINT_PT_ON_CURVE : CONSTRAINT_PT_LINE_DISTANCE;
   else
     theAttributes.clear();
 
+  if (myType == CONSTRAINT_HORIZONTAL_DISTANCE || myType == CONSTRAINT_VERTICAL_DISTANCE)
+    mySignValue = aValue->value() < 0.0 ? -1.0 : 1.0;
+
   myPrevValue = 0.0;
 
-  myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
+  if (isCoincidence)
+    myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
+  else
+    myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
 }
 
 void SketchSolver_ConstraintDistance::adjustConstraint()
@@ -127,7 +217,41 @@ void SketchSolver_ConstraintDistance::update()
   ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint);
   myPrevValue = aConstraint->value();
 
-  SketchSolver_Constraint::update();
+  bool isDistanceAlognDir =
+    myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+    myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID();
+
+  AttributeDoublePtr aCurValue = myBaseConstraint->real(SketchPlugin_Constraint::VALUE());
+  bool isZeroSwitch = fabs(myPrevValue) < tolerance && fabs(aCurValue->value()) > tolerance;
+  bool isNonZeroSwitch = fabs(myPrevValue) > tolerance && fabs(aCurValue->value()) < tolerance;
+
+  if (!isDistanceAlognDir && (isZeroSwitch || isNonZeroSwitch)) {
+    // the value is changed from non-zero to zero or vice versa
+    remove();
+    process();
+
+    // move entities to avoid conflicting constraints
+    if (isZeroSwitch) {
+      double aDirX, aDirY;
+      // calculate the direction basing on the distanced objects
+      calculateDistanceDirection(myBaseConstraint, myStorage, aDirX, aDirY);
+      moveEntity(myBaseConstraint, myStorage, aDirX, aDirY);
+
+      if (myOddPoint) {
+        removeConstraintsKeepingSign();
+        addConstraintsToKeepSign();
+      }
+    }
+  }
+  else {
+    SketchSolver_Constraint::update();
+    if (isDistanceAlognDir && mySignValue * aConstraint->value() < 0.0) {
+      if (isZeroSwitch)
+        aConstraint->setValue(-aConstraint->value());
+      else
+        mySignValue *= -1.0;
+    }
+  }
 }
 
 bool SketchSolver_ConstraintDistance::remove()
index e6e3a002ce3f500f4e53583791224a85a4616f0b..f93711e819c9b075d53e350a1ed7cf4783e2d0a1 100644 (file)
@@ -33,16 +33,18 @@ class SketchSolver_Error
   /// The value parameter for the constraint
   inline static const std::string& CONSTRAINTS()
   {
-    static const std::string MY_ERROR_VALUE("The constraint is conflicting with others. "
-      "To fix this, you can either undo your operation or remove a conflicting constraint.");
+    static const std::string MY_ERROR_VALUE("<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>");
     return MY_ERROR_VALUE;
   }
   /// Cyclic dependency of copied features with their originals
   inline static const std::string& INFINITE_LOOP()
   {
     static const std::string MY_ERROR_VALUE(
-      "There is a circular reference between copied sketch entities and their originals. "
-      "To fix this, you can either undo your operation or remove wrong constraint.");
+      "<b>There is a circular reference between copied sketch entities and their originals. "
+      "To fix this, you can either <font color='red'>undo (Ctrl+Z)</font> your operation or "
+      "<font color='red'>remove</font> wrong constraint.</b>");
     return MY_ERROR_VALUE;
   }
   /// Constraints should use objects instead of features as attributes
index ab9b38fc2df6789e841b275e22e425f2805d9e19..96c0a29687a66e1008520dd4d398e5244df9ce18 100644 (file)
@@ -496,3 +496,8 @@ bool SketchSolver_Group::areConstraintsValid() const
       return false;
   return true;
 }
+
+void SketchSolver_Group::underconstrainedFeatures(std::set<ObjectPtr>& theFeatures) const
+{
+  myStorage->getUnderconstrainedGeometry(theFeatures);
+}
index ed938f5d0c45f9c9749cf88d06a04650f49457f3..45407ddb8f47884f6dbc4efb5a4ede2d0a567a25 100644 (file)
@@ -115,6 +115,9 @@ class SketchSolver_Group
    */
   bool resolveConstraints();
 
+  /// \brief Find the list of features, which are not fully constrained.
+  void underconstrainedFeatures(std::set<ObjectPtr>& theFeatures) const;
+
   /// \brief Block or unblock events sent by features in this group
   void blockEvents(bool isBlocked);
 
index 00be4b13ef380f8f4151421c488062db0d608331..a9d47533e95b12fb5cb18ad2dc632add3e8c13a5 100644 (file)
@@ -114,6 +114,7 @@ SketchSolver_Manager::SketchSolver_Manager()
   ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
   ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_GET_DOF_OBJECTS));
 }
 
 SketchSolver_Manager::~SketchSolver_Manager()
@@ -223,6 +224,35 @@ void SketchSolver_Manager::processEvent(
     }
     myIsComputed = false;
   }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_GET_DOF_OBJECTS)) {
+    std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+      std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    std::set<ObjectPtr> aObjects = anUpdateMsg->objects();
+    if (aObjects.size() == 1) {
+      std::set<ObjectPtr>::const_iterator aIt;
+      for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
+        CompositeFeaturePtr aFeature =
+            std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aIt);
+        if (aFeature) {
+          SketchGroupPtr aGroup = findGroup(aFeature);
+
+          std::set<ObjectPtr> aFreeFeatures;
+          aGroup->underconstrainedFeatures(aFreeFeatures);
+
+          std::list<ObjectPtr> aFeatures;
+          std::set<ObjectPtr>::const_iterator aIt;
+          for (aIt = aFreeFeatures.cbegin(); aIt != aFreeFeatures.cend(); ++aIt) {
+            aFeatures.push_back(*aIt);
+          }
+
+          // send features to GUI
+          static const Events_ID anEvent = Events_Loop::eventByName(EVENT_DOF_OBJECTS);
+          ModelAPI_EventCreator::get()->sendUpdated(aFeatures, anEvent);
+          Events_Loop::loop()->flush(anEvent);
+        }
+      }
+    }
+  }
 
   // resolve constraints if needed
   bool needToUpdate = needToResolve && resolveConstraints();
@@ -352,7 +382,7 @@ bool SketchSolver_Manager::moveAttribute(
 //  Purpose:  search groups of entities interacting with given feature
 // ============================================================================
 SketchGroupPtr SketchSolver_Manager::findGroup(
-    std::shared_ptr<SketchPlugin_Feature> theFeature)
+  std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
   if (!isFeatureValid(theFeature))
     return SketchGroupPtr(); // do not process wrong features
@@ -368,17 +398,21 @@ SketchGroupPtr SketchSolver_Manager::findGroup(
       break;
     }
   }
+  return findGroup(aSketch);
+}
 
-  if (!aSketch)
+SketchGroupPtr SketchSolver_Manager::findGroup(CompositeFeaturePtr theSketch)
+{
+  if (!theSketch)
     return SketchGroupPtr(); // not a sketch's feature
 
   std::list<SketchGroupPtr>::const_iterator aGroupIt;
   for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt)
-    if ((*aGroupIt)->getWorkplane() == aSketch)
+    if ((*aGroupIt)->getWorkplane() == theSketch)
       return *aGroupIt;
 
   // group for the sketch does not created yet
-  SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch));
+  SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(theSketch));
   myGroups.push_back(aNewGroup);
   return aNewGroup;
 }
index ce83c3d9b9355c01143917f250c8c47e0200b1aa..78ddaefbb26c2d99811bb51d0462d4564519ace8 100644 (file)
@@ -112,6 +112,11 @@ private:
    *  \return Pointer to corresponding group or NULL if the group cannot be created.
    */
   SketchGroupPtr findGroup(std::shared_ptr<SketchPlugin_Feature> theFeature);
+  /** \brief Searches group related to specified composite feature
+   *  \param[in]  theSketch  sketch to be found
+   *  \return Pointer to corresponding group or NULL if the group cannot be created.
+   */
+  SketchGroupPtr findGroup(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
 
   /// \brief Stop sending the Update event until all features updated
   /// \return \c true, if the last flushed event is Update
index 0757abfb7f2abf3f060ff3559a7fec4f09f70831..8ef8aeb39c3415324f1622776661d9d45b2246e9 100644 (file)
@@ -128,6 +128,9 @@ public:
   /// \brief Return list of conflicting constraints
   std::set<ObjectPtr> getConflictingConstraints(SolverPtr theSolver) const;
 
+  /// \brief Return list of features which are not fully constrained
+  virtual void getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const = 0;
+
   /// \brief Verify, the sketch contains degenerated geometry
   ///        after resolving the set of constraints
   /// \return STATUS_OK if the geometry is valid, STATUS_DEGENERATED otherwise.
diff --git a/src/SketchSolver/SketchSolver_msg_fr.ts b/src/SketchSolver/SketchSolver_msg_fr.ts
new file mode 100644 (file)
index 0000000..a69ecbe
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+  <context>
+    <name>Sketch</name>
+    <message>
+      <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>
+    <message>
+      <source>There is a circular reference between copied sketch entities and their originals. To fix this, you can either undo your operation or remove wrong constraint.</source>
+      <translation>Il existe une référence circulaire entre les entités d&apos;esquisse copiées et leurs originaux. Pour résoudre ce problème, vous pouvez annuler votre opération ou supprimer une contrainte incorrecte.</translation>
+    </message>
+    <message>
+      <source>Caution: SolveSpace crashed! Constraints are wrong</source>
+      <translation>Attention : Plantage de SolveSpace ! Les contraintes sont fausses</translation>
+    </message>
+    <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&apos;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>
+  </context>
+</TS>
index f5bcf8e3de258adabb2791c2ae02b9090f5b3ed4..1696fc7e1aadd317fff8be6e6faf734f362e17d8 100644 (file)
@@ -145,15 +145,24 @@ bool SketcherPrs_Angle::readyToDisplay(ModelAPI_Feature* theConstraint,
       new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
   }
 
-  gp_Pnt2d aFirstPoint = anAng->firstPoint()->impl<gp_Pnt2d>();
+  gp_Pnt2d aCenterPoint = anAng->center()->impl<gp_Pnt2d>();
+  gp_Pnt2d aFirstPoint, aSecondPoint;
+  if (anAng->angleRadian() > 0.0) {
+    aFirstPoint = anAng->firstPoint()->impl<gp_Pnt2d>();
+    aSecondPoint = anAng->secondPoint()->impl<gp_Pnt2d>();
+  }
+  else {
+    aFirstPoint = anAng->secondPoint()->impl<gp_Pnt2d>();
+    aSecondPoint = anAng->firstPoint()->impl<gp_Pnt2d>();
+  }
+
+
   std::shared_ptr<GeomAPI_Pnt> aPoint = thePlane->to3D(aFirstPoint.X(), aFirstPoint.Y());
   theFirstPoint = aPoint->impl<gp_Pnt>();
 
-  gp_Pnt2d aCenterPoint = anAng->center()->impl<gp_Pnt2d>();
   aPoint = thePlane->to3D(aCenterPoint.X(), aCenterPoint.Y());
   theCenterPoint = aPoint->impl<gp_Pnt>();
 
-  gp_Pnt2d aSecondPoint = anAng->secondPoint()->impl<gp_Pnt2d>();
   aPoint = thePlane->to3D(aSecondPoint.X(), aSecondPoint.Y());
   theSecondPoint = aPoint->impl<gp_Pnt>();
 
@@ -167,6 +176,9 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP
 {
   if (!plane().get())
     return;
+
+  DataPtr aData = myConstraint->data();
+
   gp_Pnt aFirstPoint, aSecondPoint, aCenterPoint;
   bool aReadyToDisplay = readyToDisplay(myConstraint, plane(),
                                         aFirstPoint, aSecondPoint, aCenterPoint);
@@ -175,7 +187,6 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP
     mySecondPoint = aSecondPoint;
     myCenterPoint = aCenterPoint;
 
-    DataPtr aData = myConstraint->data();
     AttributeDoublePtr anAttributeValue =
       aData->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID());
     myValue.init(anAttributeValue);
@@ -188,7 +199,6 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP
     myFlyOutPoint = aFlyoutPnt->impl<gp_Pnt>();
   }
 
-  DataPtr aData = myConstraint->data();
   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());
@@ -197,7 +207,7 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP
   switch (anAngleType) {
     case SketcherPrs_Tools::ANGLE_DIRECT: {
 #ifndef COMPILATION_CORRECTION
-      SetArrowsVisibility(AIS_TOAV_Second);
+      SetArrowsVisibility(AIS_TOAV_Both);
 #endif
       SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint);
 #ifndef COMPILATION_CORRECTION
@@ -219,7 +229,7 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP
     break;
     case SketcherPrs_Tools::ANGLE_BACKWARD: {
 #ifndef COMPILATION_CORRECTION
-      SetArrowsVisibility(AIS_TOAV_Second);
+      SetArrowsVisibility(AIS_TOAV_Both);
 #endif
       SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint);
       bool isReversedPlanes = isAnglePlaneReversedToSketchPlane();
index d4178917e8194b586d8d92e2403940328d23ba04..b15f0d05f0459ece2a964e17187769c4d103cbcb 100644 (file)
@@ -137,6 +137,20 @@ bool SketcherPrs_LengthDimension::IsReadyToDisplay(ModelAPI_Feature* theConstrai
   return readyToDisplay(theConstraint, thePlane, aPnt1, aPnt2);
 }
 
+static bool isEqualPoints(ModelAPI_Feature* theConstraint,
+                          const gp_Pnt& thePoint1,
+                          const gp_Pnt& thePoint2)
+{
+  bool isEqual = false;
+  if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
+    isEqual = Abs(thePoint1.X() - thePoint2.X()) < Precision::Confusion();
+  else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+    isEqual = Abs(thePoint1.Y() - thePoint2.Y()) < Precision::Confusion();
+  else
+    isEqual = thePoint1.SquareDistance(thePoint2) < Precision::SquareConfusion();
+  return isEqual;
+}
+
 void SketcherPrs_LengthDimension::Compute(
   const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
   const Handle(Prs3d_Presentation)& thePresentation,
@@ -147,6 +161,28 @@ void SketcherPrs_LengthDimension::Compute(
   gp_Pnt aPnt1, aPnt2;
   bool aReadyToDisplay = readyToDisplay(myConstraint, plane(), aPnt1, aPnt2);
   if (aReadyToDisplay) {
+    if (isEqualPoints(myConstraint, aPnt1, aPnt2)) {
+      // adjust points to draw the dimension presentation
+      std::shared_ptr<GeomDataAPI_Dir> aDirAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+          myConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID()));
+      double x = 0.0, y = 0.0;
+      if (aDirAttr && aDirAttr->isInitialized()) {
+        x = aDirAttr->x();
+        y = aDirAttr->y();
+        if (x == 0.0 && y == 0.0)
+          x = 1.0;
+      }
+      else if (myConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+        y = 1.0;
+      else
+        x = 1.0;
+      GeomPointPtr aCoord = plane()->to3D(x, y);
+
+      gp_XYZ aDir(aCoord->x(), aCoord->y(), aCoord->z());
+      aPnt1.ChangeCoord().Add(aDir * (-Precision::Confusion()));
+      aPnt2.ChangeCoord().Add(aDir * Precision::Confusion());
+    }
+
     myFirstPoint = aPnt1;
     mySecondPoint = aPnt2;
 
@@ -267,14 +303,14 @@ bool SketcherPrs_LengthDimension::readyToDisplay(ModelAPI_Feature* theConstraint
     if (!aPnt_A || !aPnt_B) // Objects not found
       return false;
 
-    if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+    /*if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
       if (fabs(aPnt_A->x() - aPnt_B->x()) < Precision::Confusion())
         return false;
     }
     else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
       if (fabs(aPnt_A->y() - aPnt_B->y()) < Precision::Confusion())
         return false;
-    }
+    }*/
 
     // Get points from these object
     std::shared_ptr<GeomAPI_Pnt> aPoint1 = thePlane->to3D(aPnt_A->x(), aPnt_A->y());
index 5f79c5fbaec5d90b5dca3abe513ef441be0c4bf3..e10434cf9e3f024f5ee28610480786d44dc8e377 100644 (file)
@@ -185,7 +185,7 @@ Handle(Image_AlienPixMap) SketcherPrs_SymbolPrs::icon()
       aSizedMap->InitTrash(aPixMap->Format(), aWidth, aHeigh);
       for (Standard_Size i = 0; i < aWidth; i++) {
         for (Standard_Size j = 0; j < aHeigh; j++) {
-          aSizedMap->SetPixelColor(i, j, aPixMap->PixelColor(i / aRatio, j / aRatio));
+          aSizedMap->SetPixelColor(int(i), int(j), aPixMap->PixelColor(i / aRatio, j / aRatio));
         }
       }
       aPixMap = aSizedMap;
index 4e9522fd1f94caec8056f5c4faf59cbd7d613d58..8b32e6944878444f03ae9722d5a7931c91f30645 100644 (file)
@@ -94,8 +94,12 @@ std::shared_ptr<GeomAPI_Shape> getShape(ObjectPtr theObject)
 std::shared_ptr<GeomAPI_Pnt2d> getPoint(ModelAPI_Feature* theFeature,
                                         const std::string& theAttribute)
 {
-  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr(
+  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(theAttribute));
+  if (!aPointAttr.get() || !aPointAttr->isInitialized()) {
+    aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr(
                theFeature, theAttribute, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+  }
   if (aPointAttr.get() != NULL)
     return aPointAttr->pnt();
   return std::shared_ptr<GeomAPI_Pnt2d>();
index cf51cc8b29ba01c777d4a5db8cf68cf33d18d8f7..9281220639283a9a36a46a9fd8cf6adc5bac2d4a 100644 (file)
@@ -36,7 +36,6 @@ SET(PROJECT_HEADERS
     XGUI_ActiveControlSelector.h
     XGUI_ColorDialog.h
     XGUI_ContextMenuMgr.h
-    XGUI_CustomPrs.h
     XGUI_DataModel.h
     XGUI_DeflectionDialog.h
     XGUI_Displayer.h
@@ -104,7 +103,6 @@ SET(PROJECT_SOURCES
     XGUI_ActiveControlMgr.cpp
     XGUI_ColorDialog.cpp
     XGUI_ContextMenuMgr.cpp
-    XGUI_CustomPrs.cpp
     XGUI_DataModel.cpp
     XGUI_DeflectionDialog.cpp
     XGUI_Displayer.cpp
@@ -145,7 +143,7 @@ SET(PREFERENCES_XML
 )
 
 SET(TEXT_RESOURCES
-#    XGUI_msg_fr.ts
+    XGUI_msg_fr.ts
 )
 
 SET(PROJECT_LIBRARIES
@@ -179,14 +177,16 @@ QT_ADD_RESOURCES(PROJECT_COMPILED_RESOURCES ${PROJECT_RESOURCES})
 
 
 IF (${UPDATE_TRANSLATION})
-    SET(PROJECT_FILES ${PROJECT_SOURCES} ${ROJECT_HEADERS} )
+    SET(PROJECT_FILES ${PROJECT_SOURCES} ${PROJECT_HEADERS} )
     QT5_CREATE_TRANSLATION(QM_RESOURCES
                            ${PROJECT_FILES}
                            ${TEXT_RESOURCES}
-                           OPTIONS -extensions cpp -no-recursive
+                           OPTIONS -extensions cpp -no-recursive -locations none
                           )
 ELSE(${UPDATE_TRANSLATION})
-    QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    IF(${MAKE_TRANSLATION})
+        QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    ENDIF(${MAKE_TRANSLATION})
 ENDIF(${UPDATE_TRANSLATION})
 
 
@@ -199,6 +199,7 @@ ADD_DEFINITIONS( -DXGUI_EXPORTS ${OpenCASCADE_DEFINITIONS} -D_CRT_SECURE_NO_WARN
 SET(PROJECT_INCLUDES
     ${PROJECT_SOURCE_DIR}/src/Events
     ${PROJECT_SOURCE_DIR}/src/Config
+    ${PROJECT_SOURCE_DIR}/src/ExchangePlugin
     ${PROJECT_SOURCE_DIR}/src/ModelAPI
     ${PROJECT_SOURCE_DIR}/src/GeomAPI
     ${PROJECT_SOURCE_DIR}/src/ModuleBase
index 00cf24153ffbe8d7edd5e460e3d74bbe0ab5b0de..a174bea87b737f8ae17402cf8e0e725739ea0687 100644 (file)
@@ -55,7 +55,7 @@
 
 #include <ModuleBase_IModule.h>
 #include <ModuleBase_Tools.h>
-#include <ModuleBase_OperationAction.h>
+#include <ModuleBase_Operation.h>
 #include <ModuleBase_ViewerPrs.h>
 
 #include <QAction>
@@ -96,10 +96,14 @@ void XGUI_ContextMenuMgr::createActions()
                                            aDesktop, this, SLOT(onRename()));
   addAction("RENAME_CMD", aAction);
 
-  aAction = ModuleBase_Tools::createAction(QIcon(":pictures/move.png"),
+  aAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_to_end.png"),
                                            XGUI_Workshop::MOVE_TO_END_COMMAND, this);
   addAction("MOVE_CMD", aAction);
 
+  aAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_to_end_split.png"),
+    XGUI_Workshop::MOVE_TO_END_SPLIT_COMMAND, this);
+  addAction("MOVE_SPLIT_CMD", aAction);
+
   aAction = ModuleBase_Tools::createAction(QIcon(":pictures/clean_history.png"),
                                            tr("Clean history"), aDesktop);
   addAction("CLEAN_HISTORY_CMD", aAction);
@@ -326,8 +330,10 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
           if (!(hasParameter || hasFeature))
             action("SHOW_ONLY_CMD")->setEnabled(true);
         }
-        else if (hasFeature && myWorkshop->canMoveFeature())
+        else if (hasFeature && myWorkshop->canMoveFeature()) {
           action("MOVE_CMD")->setEnabled(true);
+          action("MOVE_SPLIT_CMD")->setEnabled(true);
+        }
 
         if( aMgr->activeDocument() == aObject->document() )
         {
@@ -347,8 +353,10 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
         action("SHADING_CMD")->setEnabled(true);
         action("WIREFRAME_CMD")->setEnabled(true);
       }
-      if (hasFeature && myWorkshop->canMoveFeature())
+      if (hasFeature && myWorkshop->canMoveFeature()) {
         action("MOVE_CMD")->setEnabled(true);
+        action("MOVE_SPLIT_CMD")->setEnabled(true);
+      }
     } // end multi-selection
 
     // Check folder management commands state if only features are selected
@@ -662,6 +670,7 @@ void XGUI_ContextMenuMgr::buildObjBrowserMenu()
   aList.append(action("RENAME_CMD"));
   aList.append(action("SHOW_RESULTS_CMD"));
   aList.append(action("MOVE_CMD"));
+  aList.append(action("MOVE_SPLIT_CMD"));
   aList.append(mySeparator1);
   aList.append(action("INSERT_FOLDER_CMD"));
   aList.append(action("ADD_TO_FOLDER_BEFORE_CMD"));
@@ -770,6 +779,7 @@ void XGUI_ContextMenuMgr::addObjBrowserMenu(QMenu* theMenu) const
       aActions.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
       aActions.append(mySeparator3);
       aActions.append(action("MOVE_CMD"));
+      aActions.append(action("MOVE_SPLIT_CMD"));
       aActions.append(action("COLOR_CMD"));
       aActions.append(action("DEFLECTION_CMD"));
       aActions.append(action("TRANSPARENCY_CMD"));
diff --git a/src/XGUI/XGUI_CustomPrs.cpp b/src/XGUI/XGUI_CustomPrs.cpp
deleted file mode 100644 (file)
index f3bd683..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-// 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 <XGUI_CustomPrs.h>
-#include <XGUI_Workshop.h>
-#include <XGUI_Displayer.h>
-
-#include <ModuleBase_IModule.h>
-
-#include <ModelAPI_AttributeIntArray.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_Session.h>
-#include <ModelAPI_ResultBody.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_ShapeExplorer.h>
-
-#include <Config_PropManager.h>
-
-#include <Events_InfoMessage.h>
-
-#include <vector>
-#include <QColor>
-
-double getDeflection(const ResultPtr& theResult)
-{
-  double aDeflection = -1;
-  // get deflection from the attribute of the result
-  if (theResult.get() != NULL &&
-      theResult->data()->attribute(ModelAPI_Result::DEFLECTION_ID()).get() != NULL) {
-    AttributeDoublePtr aDoubleAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID());
-    if (aDoubleAttr.get() && aDoubleAttr->isInitialized()) {
-      double aValue = aDoubleAttr->value();
-      if (aValue > 0) /// zero value should not be used as a deflection(previous studies)
-        aDeflection = aDoubleAttr->value();
-    }
-  }
-  return aDeflection;
-}
-
-void getColor(const ResultPtr& theResult, std::vector<int>& theColor)
-{
-  theColor.clear();
-  // get color from the attribute of the result
-  if (theResult.get() != NULL &&
-      theResult->data()->attribute(ModelAPI_Result::COLOR_ID()).get() != NULL) {
-    AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
-    if (aColorAttr.get() && aColorAttr->size()) {
-      theColor.push_back(aColorAttr->value(0));
-      theColor.push_back(aColorAttr->value(1));
-      theColor.push_back(aColorAttr->value(2));
-    }
-  }
-}
-
-void XGUI_CustomPrs::getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
-                                     std::vector<int>& theColor)
-{
-  theColor.clear();
-  // get default color from the preferences manager for the given result
-  if (theColor.empty()) {
-    std::string aSection, aName, aDefault;
-    theObject->colorConfigInfo(aSection, aName, aDefault);
-    if (!aSection.empty() && !aName.empty()) {
-      theColor = Config_PropManager::color(aSection, aName);
-    }
-  }
-  if (!isEmptyColorValid && theColor.empty()) {
-    // all AIS objects, where the color is not set, are in black.
-    // The color should be defined in XML or set in the attribute
-    theColor = Config_PropManager::color("Visualization", "object_default_color");
-    Events_InfoMessage("XGUI_CustomPrs",
-      "A default color is not defined in the preferences for this kind of result").send();
-  }
-}
-
-double XGUI_CustomPrs::getDefaultDeflection(const ObjectPtr& theObject)
-{
-  double aDeflection = -1;
-  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-  if (aResult.get()) {
-    bool isConstruction = false;
-
-    std::string aResultGroup = aResult->groupName();
-    if (aResultGroup == ModelAPI_ResultConstruction::group())
-      isConstruction = true;
-    else if (aResultGroup == ModelAPI_ResultBody::group()) {
-      GeomShapePtr aGeomShape = aResult->shape();
-      if (aGeomShape.get()) {
-        // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
-        // correction of deviation for them should not influence to the application performance
-        GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE);
-        isConstruction = !anExp.more();
-      }
-    }
-    if (isConstruction)
-      aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
-    else
-      aDeflection = Config_PropManager::real("Visualization", "body_deflection");
-  }
-  return aDeflection;
-}
-
-double getTransparency(const ResultPtr& theResult)
-{
-  double aTransparency = -1;
-  // get transparency from the attribute of the result
-  if (theResult.get() != NULL &&
-      theResult->data()->attribute(ModelAPI_Result::TRANSPARENCY_ID()).get() != NULL) {
-    AttributeDoublePtr aDoubleAttr = theResult->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
-    if (aDoubleAttr.get() && aDoubleAttr->isInitialized()) {
-      aTransparency = aDoubleAttr->value();
-    }
-  }
-  return aTransparency;
-}
-
-double getDefaultTransparency(const ResultPtr& theResult)
-{
-  return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
-}
-
-XGUI_CustomPrs::XGUI_CustomPrs(XGUI_Workshop* theWorkshop)
-: myWorkshop(theWorkshop)
-{
-}
-
-void XGUI_CustomPrs::getResultColor(const ResultPtr& theResult, std::vector<int>& theColor)
-{
-  getColor(theResult, theColor);
-  if (theColor.empty())
-    getDefaultColor(theResult, false, theColor);
-}
-
-double XGUI_CustomPrs::getResultDeflection(const ResultPtr& theResult)
-{
-  double aDeflection = getDeflection(theResult);
-  if (aDeflection < 0)
-    aDeflection = getDefaultDeflection(theResult);
-  return aDeflection;
-}
-
-double XGUI_CustomPrs::getResultTransparency(const ResultPtr& theResult)
-{
-  double aTransparency = getTransparency(theResult);
-  if (aTransparency < 0)
-    aTransparency = getDefaultTransparency(theResult);
-  return aTransparency;
-}
-
-bool XGUI_CustomPrs::customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
-                                           std::shared_ptr<GeomAPI_ICustomPrs> theCustomPrs)
-{
-  bool aCustomized = false;
-  if (theResult.get()) {
-    std::vector<int> aColor;
-    getResultColor(theResult, aColor);
-
-    SessionPtr aMgr = ModelAPI_Session::get();
-    if (aMgr->activeDocument() != theResult->document()) {
-      QColor aQColor(aColor[0], aColor[1], aColor[2]);
-      QColor aNewColor =
-        QColor::fromHsvF(aQColor.hueF(), aQColor.saturationF()/3., aQColor.valueF());
-      aColor[0] = aNewColor.red();
-      aColor[1] = aNewColor.green();
-      aColor[2] = aNewColor.blue();
-    }
-    aCustomized = !aColor.empty() && thePrs->setColor(aColor[0], aColor[1], aColor[2]);
-
-    aCustomized = thePrs->setDeflection(getResultDeflection(theResult)) | aCustomized;
-
-    aCustomized = thePrs->setTransparency(getResultTransparency(theResult)) | aCustomized;
-  }
-  ModuleBase_IModule* aModule = myWorkshop->module();
-  aCustomized = aModule->customisePresentation(theResult, thePrs, theCustomPrs) || aCustomized;
-  return aCustomized;
-}
diff --git a/src/XGUI/XGUI_CustomPrs.h b/src/XGUI/XGUI_CustomPrs.h
deleted file mode 100644 (file)
index 62d18d3..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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 XGUI_CustomPrs_H
-#define XGUI_CustomPrs_H
-
-#include "XGUI.h"
-#include <GeomAPI_ICustomPrs.h>
-#include <GeomAPI_AISObject.h>
-#include <ModelAPI_Result.h>
-
-class XGUI_Workshop;
-
-/**
-* Interface of a class which can provide specific customization of
-* object presentation
-*/ 
-class XGUI_CustomPrs : public GeomAPI_ICustomPrs
-{
-public:
-  /// Constructor
-  /// \param theWorkshop the current workshop instance
-  XGUI_EXPORT XGUI_CustomPrs(XGUI_Workshop* theWorkshop);
-
-  XGUI_EXPORT virtual ~XGUI_CustomPrs() {};
-
-  /// Modifies the given presentation in the custom way.
-  virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
-                                     std::shared_ptr<GeomAPI_ICustomPrs> theCustomPrs);
-
-  /// Returns color of a result object
-  /// \param theResult a result object
-  /// \param theColor a color in form of RGB vector
-  static void getResultColor(const ResultPtr& theResult, std::vector<int>& theColor);
-
-  /// Returns deflection of a result object
-  /// \param theResult a result object
-  /// \return theDeflection a real value
-  static double getResultDeflection(const ResultPtr& theResult);
-
-  /// Returns transparency of a result object
-  /// \param theResult a result object
-  /// \return theTransparency a real value
-  static double getResultTransparency(const ResultPtr& theResult);
-
-  /// Returns the default object color. It obtains colorConfigInfo of the object
-  /// and find it in preferences. If there are no this color in preference and an empty
-  /// color is interpreted as invalid, it shows error message
-  /// \param theObject an investigated object
-  /// \param isEmptyColorValid boolean state about interpretation of empty color
-  /// \param theColor the result color
-  static void XGUI_EXPORT getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
-                                          std::vector<int>& theColor);
-
-  /// Returns the default deflection value. The value is obtained from the application preferences
-  /// \param theObject an investigated object
-  /// \return deflection value
-  static double XGUI_EXPORT getDefaultDeflection(const ObjectPtr& theObject);
-
-protected:
-  XGUI_Workshop* myWorkshop; ///< the current workshop
-};
-
-#endif
index ccad93e0e2325f4d0a776c4c8a9044ebb5b3af85..a84c76a0868c9d8729ffc11d2acb07552c053c09 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "XGUI_Displayer.h"
 
-#include "XGUI_CustomPrs.h"
 #include "XGUI_FacesPanel.h"
 #include "XGUI_Selection.h"
 #include "XGUI_SelectionActivate.h"
@@ -42,7 +41,6 @@
 #include <ModuleBase_BRepOwner.h>
 #include <ModuleBase_IModule.h>
 #include <ModuleBase_Preferences.h>
-#include <ModuleBase_ResultPrs.h>
 #include <ModuleBase_Tools.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_IViewer.h>
@@ -123,9 +121,8 @@ QString qIntListInfo(const QIntList& theValues, const QString& theSeparator = QS
 //**************************************************************
 XGUI_Displayer::XGUI_Displayer(XGUI_Workshop* theWorkshop)
 : myWorkshop(theWorkshop), myNeedUpdate(false),
-  myViewerBlockedRecursiveCount(0), myIsFirstAISContextUse(true)
+  myViewerBlockedRecursiveCount(0), myContextId(0)
 {
-  myCustomPrs = std::shared_ptr<GeomAPI_ICustomPrs>(new XGUI_CustomPrs(theWorkshop));
 }
 
 //**************************************************************
@@ -157,25 +154,10 @@ bool XGUI_Displayer::display(ObjectPtr theObject, bool theUpdateViewer)
       }
       anAIS = aPrs->getAISObject(anAIS);
     } else {
-      Handle(AIS_InteractiveObject) anAISPrs =
-        myWorkshop->module()->createPresentation(theObject);
-      if (anAISPrs.IsNull()) {
-        ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-        if (aResult.get() != NULL) {
-          std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
-          if (aShapePtr.get() != NULL) {
-             anAISPrs = new ModuleBase_ResultPrs(aResult);
-          }
-        }
-      }
-      Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(anAISPrs);
-      if (!aShapePrs.IsNull())
-        ModuleBase_Tools::setPointBallHighlighting((AIS_Shape*)aShapePrs.get());
-      anAIS = AISObjectPtr(new GeomAPI_AISObject());
-      anAIS->setImpl(new Handle(AIS_InteractiveObject)(anAISPrs));
+      anAIS = myWorkshop->module()->createPresentation(theObject);
       isShading = true;
     }
-    if (anAIS)
+    if (anAIS.get())
       aDisplayed = display(theObject, anAIS, isShading, theUpdateViewer);
   }
   return aDisplayed;
@@ -215,7 +197,7 @@ bool XGUI_Displayer::display(ObjectPtr theObject, AISObjectPtr theAIS,
   if (!anAISIO.IsNull()) {
     appendResultObject(theObject, theAIS);
 
-    bool isCustomized = customizeObject(theObject);
+    //bool isCustomized = customizeObject(theObject);
 
     int aDispMode = isShading? Shading : Wireframe;
     if (isShading)
@@ -278,11 +260,15 @@ bool XGUI_Displayer::erase(ObjectPtr theObject, const bool theUpdateViewer)
 bool XGUI_Displayer::redisplay(ObjectPtr theObject, bool theUpdateViewer)
 {
   bool aRedisplayed = false;
+  Handle(AIS_InteractiveContext) aContext = AISContext();
+  if (aContext.IsNull())
+    return aRedisplayed;
+
   if (!isVisible(theObject))
     return aRedisplayed;
 
   AISObjectPtr aAISObj = getAISObject(theObject);
-  Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+  Handle(AIS_InteractiveObject) aAISIO;
 
   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
   if (aPrs) {
@@ -302,64 +288,55 @@ bool XGUI_Displayer::redisplay(ObjectPtr theObject, bool theUpdateViewer)
     }
     aAISIO = aAIS_Obj->impl<Handle(AIS_InteractiveObject)>();
   }
+  else {
+    aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+  }
 
-  Handle(AIS_InteractiveContext) aContext = AISContext();
-  if (!aContext.IsNull() && !aAISIO.IsNull()) {
-    // Check that the visualized shape is the same and the redisplay is not necessary
-    // Redisplay of AIS object leads to this object selection compute and the selection
-    // in the browser is lost
-    // this check is not necessary anymore because the selection store/restore is realized
-    // before and after the values modification.
-    // Moreother, this check avoids customize and redisplay presentation if the presentable
-    // parameter is changed.
-    bool isEqualShapes = false;
+  if (!aAISIO.IsNull()) {
     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-    if (aResult.get() != NULL) {
-      Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(aAISIO);
-      if (!aShapePrs.IsNull()) {
-        std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
-        if (aShapePtr.get()) {
-          const TopoDS_Shape& aOldShape = aShapePrs->Shape();
-          if (!aOldShape.IsNull())
-            isEqualShapes = aOldShape.IsEqual(aShapePtr->impl<TopoDS_Shape>());
-        }
+    if (aResult.get()) {
+      // Set color
+      std::vector<int> aColor;
+      ModelAPI_Tools::getColor(aResult, aColor);
+      if (aColor.size() > 0) {
+        Quantity_Color
+          aCol(aColor[0] / 255., aColor[1] / 255., aColor[2] / 255., Quantity_TOC_RGB);
+        aAISIO->SetColor(aCol);
       }
+      // Set deflection
+      double aDeflection = ModelAPI_Tools::getDeflection(aResult);
+      if ((aDeflection >= 0) && (aDeflection != aAISObj->getDeflection()))
+        aAISObj->setDeflection(aDeflection);
+
+      // Set transparency
+      double aTransparency = ModelAPI_Tools::getTransparency(aResult);
+      if ((aTransparency >= 0) && (aTransparency != aAISObj->getTransparency()))
+        aAISObj->setTransparency(aTransparency);
     }
-    // Customization of presentation
-    bool isCustomized = customizeObject(theObject);
-    #ifdef DEBUG_FEATURE_REDISPLAY
-      qDebug(QString("Redisplay: %1, isEqualShapes=%2, isCustomized=%3").
-        arg(!isEqualShapes || isCustomized).arg(isEqualShapes)
-        .arg(isCustomized).toStdString().c_str());
-    #endif
-    if (!isEqualShapes || isCustomized) {
-      /// if shapes are equal and presentation are customized, selection should be restored
-      bool aNeedToRestoreSelection = isEqualShapes && isCustomized;
-      if (aNeedToRestoreSelection)
-        myWorkshop->module()->storeSelection();
+    myWorkshop->module()->storeSelection();
 
 #ifdef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
-      myWorkshop->selector()->deselectPresentation(aAISIO);
+    myWorkshop->selector()->deselectPresentation(aAISIO);
 #endif
-      if (aContext->IsDisplayed(aAISIO))
-        aContext->Redisplay(aAISIO, false);
-      else
-        aContext->Display(aAISIO, false);
 
+    if (aContext->IsDisplayed(aAISIO))
+      aContext->Redisplay(aAISIO, false);
+    else {
+      aContext->Display(aAISIO, false);
+    }
       #ifdef TINSPECTOR
       if (getCallBack()) getCallBack()->Redisplay(aAISIO);
       #endif
 
-      if (aNeedToRestoreSelection)
-        myWorkshop->module()->restoreSelection();
+      //if (aNeedToRestoreSelection)
+    myWorkshop->module()->restoreSelection();
 
-      aRedisplayed = true;
-      #ifdef DEBUG_FEATURE_REDISPLAY
-        qDebug("  Redisplay happens");
-      #endif
-      if (theUpdateViewer)
-        updateViewer();
-    }
+    aRedisplayed = true;
+    #ifdef DEBUG_FEATURE_REDISPLAY
+      qDebug("  Redisplay happens");
+    #endif
+    if (theUpdateViewer)
+      updateViewer();
   }
   return aRedisplayed;
 }
@@ -640,16 +617,19 @@ void XGUI_Displayer::updateViewer() const
 Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const
 {
   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
-  if (!aContext.IsNull() && myIsFirstAISContextUse/*&& !aContext->HasOpenedContext()*/) {
-    XGUI_Displayer* aDisplayer = (XGUI_Displayer*)this;
-    aDisplayer->myIsFirstAISContextUse = false;
+  if (!aContext.IsNull() && (myContextId != aContext.get())) {
+    myContextId = aContext.get();
     if (!myWorkshop->selectionActivate()->isTrihedronActive())
       selectionActivate()->deactivateTrihedron(true);
     aContext->DefaultDrawer()->VIsoAspect()->SetNumber(0);
     aContext->DefaultDrawer()->UIsoAspect()->SetNumber(0);
 
-    ModuleBase_IViewer::DefaultHighlightDrawer = aContext->HighlightStyle();
+    //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();
     //Handle(Prs3d_Drawer) aSelStyle = aContext->SelectionStyle();
     //double aDeflection =
     //  QString(ModelAPI_ResultConstruction::DEFAULT_DEFLECTION().c_str()).toDouble();
@@ -663,6 +643,37 @@ Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const
   return aContext;
 }
 
+//**************************************************************
+void XGUI_Displayer::setSelectionColor(const std::vector<int>& theColor)
+{
+  Handle(AIS_InteractiveContext) aContext = AISContext();
+  if (!aContext.IsNull()) {
+    Quantity_Color aQColor(theColor[0] / 255.,
+                           theColor[1] / 255.,
+                           theColor[2] / 255., Quantity_TOC_RGB);
+    aContext->SelectionStyle()->SetColor(aQColor);
+    aContext->SelectionStyle()->PointAspect()->SetColor(aQColor);
+    aContext->SelectionStyle()->LineAspect()->SetColor(aQColor);
+    aContext->HighlightStyle(Prs3d_TypeOfHighlight_LocalSelected)->SetColor(aQColor);
+  }
+}
+
+
+//**************************************************************
+std::vector<int> XGUI_Displayer::selectionColor() const
+{
+  std::vector<int> aColor;
+  Handle(AIS_InteractiveContext) aContext = AISContext();
+  if (!aContext.IsNull()) {
+    Quantity_Color aQColor = aContext->SelectionStyle()->Color();
+    aColor.push_back((int)(aQColor.Red() * 255));
+    aColor.push_back((int)(aQColor.Green() * 255));
+    aColor.push_back((int)(aQColor.Blue() * 255));
+  }
+  return aColor;
+}
+
+
 //**************************************************************
 Handle(SelectMgr_AndFilter) XGUI_Displayer::GetFilter()
 {
@@ -886,37 +897,37 @@ bool XGUI_Displayer::canBeShaded(ObjectPtr theObject) const
 }
 
 //**************************************************************
-bool XGUI_Displayer::customizeObject(ObjectPtr theObject)
-{
-  AISObjectPtr anAISObj = getAISObject(theObject);
-  // correct the result's color it it has the attribute
-  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-
-  // Customization of presentation
-  GeomCustomPrsPtr aCustomPrs;
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
-  if (aFeature.get() != NULL) {
-    GeomCustomPrsPtr aCustPrs = std::dynamic_pointer_cast<GeomAPI_ICustomPrs>(aFeature);
-    if (aCustPrs.get() != NULL)
-      aCustomPrs = aCustPrs;
-  }
-  if (aCustomPrs.get() == NULL) {
-    GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
-    // we ignore presentable not customized objects
-    if (aPrs.get() == NULL)
-      aCustomPrs = myCustomPrs;
-  }
-  bool isCustomized = aCustomPrs.get() &&
-                      aCustomPrs->customisePresentation(aResult, anAISObj, myCustomPrs);
-  isCustomized = myWorkshop->module()->afterCustomisePresentation(aResult, anAISObj, myCustomPrs)
-                 || isCustomized;
-
-  // update presentation state if faces panel is active
-  if (anAISObj.get() && myWorkshop->facesPanel())
-    isCustomized = myWorkshop->facesPanel()->customizeObject(theObject, anAISObj) || isCustomized;
-
-  return isCustomized;
-}
+//bool XGUI_Displayer::customizeObject(ObjectPtr theObject)
+//{
+//  AISObjectPtr anAISObj = getAISObject(theObject);
+//  // correct the result's color it it has the attribute
+//  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+//
+//  // Customization of presentation
+//  GeomCustomPrsPtr aCustomPrs;
+//  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+//  if (aFeature.get() != NULL) {
+//    GeomCustomPrsPtr aCustPrs = std::dynamic_pointer_cast<GeomAPI_ICustomPrs>(aFeature);
+//    if (aCustPrs.get() != NULL)
+//      aCustomPrs = aCustPrs;
+//  }
+//  if (aCustomPrs.get() == NULL) {
+//    GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
+//    // we ignore presentable not customized objects
+//    if (aPrs.get() == NULL)
+//      aCustomPrs = myCustomPrs;
+//  }
+//  bool isCustomized = aCustomPrs.get() &&
+//                      aCustomPrs->customisePresentation(aResult, anAISObj, myCustomPrs);
+//  isCustomized = myWorkshop->module()->afterCustomisePresentation(aResult, anAISObj, myCustomPrs)
+//                 || isCustomized;
+//
+//  // update presentation state if faces panel is active
+//  if (anAISObj.get() && myWorkshop->facesPanel())
+//    isCustomized = myWorkshop->facesPanel()->customizeObject(theObject, anAISObj) || isCustomized;
+//
+//  return isCustomized;
+//}
 
 //**************************************************************
 QColor XGUI_Displayer::setObjectColor(ObjectPtr theObject,
index 45ea2eecbc7ba1f6dcafc3a6055b9537f84bca61..938019db81bd118f053a96e2c4a5242ad6762a8c 100644 (file)
@@ -23,7 +23,6 @@
 #include "XGUI.h"
 
 #include <GeomAPI_AISObject.h>
-#include <GeomAPI_ICustomPrs.h>
 #include <GeomAPI_Pln.h>
 
 #include <ModelAPI_Result.h>
@@ -378,6 +377,13 @@ public:
   /// Returns scale of active view
   double getViewScale() const;
 
+  /// Set color of selection
+  /// \param theColor R,G,B values of color
+  void setSelectionColor(const std::vector<int>& theColor);
+
+  /// Returns current selection color
+  std::vector<int> selectionColor() const;
+
 signals:
   /// Signal on object display
   /// \param theObject a data object
@@ -453,10 +459,6 @@ private:
 #endif
   Handle(SelectMgr_AndFilter) myAndFilter; ///< A container for selection filters
 
-  /// A default custom presentation, which is used if the displayed feature is not
-  /// a custom presentation
-  GeomCustomPrsPtr myCustomPrs;
-
   /// Definition of a type of map which defines correspondance between objects and presentations
 #ifdef OPTIMIZE_PRS
   XGUI_TwoSidePresentationMap myResult2AISObjectMap; ///< A map of displayed objects
@@ -468,7 +470,7 @@ private:
   /// Number of blocking of the viewer update. The viewer is updated only if it is zero
   int myViewerBlockedRecursiveCount;
 
-  bool myIsFirstAISContextUse; ///< Flag: first asking of AIS context: trihedron activation
+  mutable void* myContextId;
   mutable bool myNeedUpdate; ///< A flag that update was requested but not done
 };
 
index d92ae5669053b9799e40617da2307bf3e1d137fb..f79eb6dbafb25c03de80c90fc8dbd9a68df0a804 100644 (file)
 #include "XGUI_FacesPanel.h"
 #include "XGUI_ObjectsBrowser.h"
 #include "XGUI_SelectionMgr.h"
+#include "XGUI_Selection.h"
 #include "XGUI_Tools.h"
 #include "XGUI_Workshop.h"
+#include "XGUI_Displayer.h"
+#include "XGUI_ViewerProxy.h"
 
 #include <ModuleBase_IModule.h>
 #include <ModuleBase_ISelection.h>
 #include <Config_PropManager.h>
 #include <Events_Loop.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAPI_Shape.h>
 
 #include <ModelAPI_Events.h>
+#include <ModelAPI_ResultGroup.h>
+#include <ModelAPI_AttributeSelectionList.h>
 
 #include <QAction>
 #include <QCheckBox>
@@ -49,7 +55,7 @@
 static const int LayoutMargin = 3;
 
 //********************************************************************
-XGUI_FacesPanel::XGUI_FacesPanel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop)
+XGUI_FacesPanel::XGUI_FacesPanel(QWidget* theParent, XGUI_Workshop* theWorkshop)
   : QDockWidget(theParent), myIsActive(false), myWorkshop(theWorkshop)
 {
   setWindowTitle(tr("Hide Faces"));
@@ -80,20 +86,34 @@ void XGUI_FacesPanel::reset(const bool isToFlushRedisplay)
   if (myLastItemIndex == 0) // do nothing because there was no activity in the pane after reset
     return;
 
-  // clear internal containers
-  myListView->getControl()->clear();
-  myItems.clear();
+  std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
+  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+  QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> >::const_iterator aIt;
+  for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
+    getObjectsMapFromPrs(aIt.value(), anObjectToShapes, anObjectToPrs);
+  }
 
-  // restore previous view of presentations
-  bool isModified = redisplayObjects(myItemObjects);
-  std::set<std::shared_ptr<ModelAPI_Object> > aHiddenObjects = myHiddenObjects;
-  isModified = displayHiddenObjects(aHiddenObjects, myHiddenObjects) || isModified;
-  if (isModified)// && isToFlushRedisplay) // flush signal immediatelly until container is filled
+  std::set<ObjectPtr> aObjects;
+  TopoDS_ListOfShape anEmpty;
+  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::const_iterator aPrsIt;
+  for (aPrsIt = anObjectToPrs.cbegin(); aPrsIt != anObjectToPrs.cend(); aPrsIt++) {
+    aObjects.insert(aPrsIt->first);
+    aPrsIt->second->setSubShapeHidden(anEmpty);
+  }
+  std::set<std::shared_ptr<ModelAPI_Object> >::const_iterator aGrpIt;
+  for (aGrpIt = myHiddenGroups.cbegin(); aGrpIt != myHiddenGroups.cend(); aGrpIt++)
+    (*aGrpIt)->setDisplayed(true);
+  myHiddenGroups.clear();
+
+  if (redisplayObjects(aObjects))
     flushRedisplay();
 
+  // clear internal containers
+  myListView->getControl()->clear();
+  myItems.clear();
   updateProcessedObjects(myItems, myItemObjects);
-  myHiddenObjects.clear();
   myLastItemIndex = 0; // it should be after redisplay as flag used in customize
+  myHiddenObjects.clear();
 }
 
 //********************************************************************
@@ -114,7 +134,8 @@ void XGUI_FacesPanel::selectionFilters(SelectMgr_ListOfFilter& theSelectionFilte
   ModuleBase_IModule* aModule = myWorkshop->module();
   QIntList aModuleSelectionFilters = myWorkshop->module()->selectionFilters();
 
-  theSelectionFilters.Append(aModule->selectionFilter(SF_GlobalFilter));
+  // The global filter makes problem for groups selection when any operation is launched
+  // theSelectionFilters.Append(aModule->selectionFilter(SF_GlobalFilter));
   theSelectionFilters.Append(aModule->selectionFilter(SF_FilterInfinite));
   theSelectionFilters.Append(aModule->selectionFilter(SF_ResultGroupNameFilter));
 }
@@ -146,7 +167,7 @@ void XGUI_FacesPanel::setActivePanel(const bool theIsActive)
     // selection should be cleared after emit of signal to do not process selection change
     // event by the previous selector
     // the selection is cleared by activating selection control
-    XGUI_Tools::workshop(myWorkshop)->selector()->clearSelection();
+    myWorkshop->selector()->clearSelection();
   }
   else
     emit deactivated();
@@ -158,6 +179,14 @@ bool XGUI_FacesPanel::useTransparency() const
   return myHiddenOrTransparent->isChecked();
 }
 
+//********************************************************************
+double XGUI_FacesPanel::transparency() const
+{
+  return useTransparency() ?
+    Config_PropManager::real("Visualization", "hidden_face_transparency") : 1;
+}
+
+
 //********************************************************************
 void XGUI_FacesPanel::restoreObjects(const std::set<ObjectPtr>& theHiddenObjects)
 {
@@ -209,48 +238,138 @@ bool XGUI_FacesPanel::processAction(ModuleBase_ActionType theActionType)
   }
 }
 
+//********************************************************************
+void XGUI_FacesPanel::getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+  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;
+          }
+        }
+      }
+    }
+  }
+  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;
+    }
+  }
+}
+
 //********************************************************************
 void XGUI_FacesPanel::processSelection()
 {
-  QList<ModuleBase_ViewerPrsPtr> aSelected = myWorkshop->selection()->getSelected(
-                                                       ModuleBase_ISelection::Viewer);
+  QList<ModuleBase_ViewerPrsPtr> aSelected =
+    myWorkshop->selector()->selection()->getSelected(ModuleBase_ISelection::Viewer);
+
+  if (aSelected.size() == 0)
+    return;
+
   bool isModified = false;
   static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
 
-  std::map<ObjectPtr, NCollection_List<TopoDS_Shape> > anObjectToShapes;
+  std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
   std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+  std::set<int> aToRemove;
+
   for (int i = 0; i < aSelected.size(); i++) {
     ModuleBase_ViewerPrsPtr aPrs = aSelected[i];
     ObjectPtr anObject = aPrs->object();
     if (!anObject.get())
       continue;
-    if (ModuleBase_Tools::getSelectedShape(aPrs).ShapeType() != TopAbs_FACE)
-      continue;
 
-    Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
-      aPrs->interactive());
-    if (aResultPrs.IsNull())
-      continue;
-    QString aItemName = XGUI_Tools::generateName(aPrs);
+    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;
+      }
+    }
+    else {
+      GeomShapePtr aShapePtr = aPrs->shape();
+      if (!aShapePtr.get() || !aShapePtr->isFace())
+        continue;
+    }
+
+    QString aItemName = aResGroup.get()?
+      aResGroup->data()->name().c_str() : XGUI_Tools::generateName(aPrs);
     if (myListView->hasItem(aItemName))
-      return;
+      continue;
+
+    getObjectsMapFromPrs(aPrs, anObjectToShapes, anObjectToPrs);
+    if (aResGroup.get() && aResGroup->isDisplayed()) {
+      aResGroup->setDisplayed(false);
+      myHiddenGroups.insert(aResGroup);
+    }
+
+    // The code is dedicated to remove already selected items if they are selected twice
+    // It can happen in case of groups selection
+    QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator aIt;
+    for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
+      ModuleBase_ViewerPrsPtr aPrs = aIt.value();
+      ObjectPtr aObject = aPrs->object();
+      ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(aObject);
+      if (aResGroup.get())
+        continue;
+      if (anObjectToShapes.find(aObject) != anObjectToShapes.end()) {
+        TopoDS_ListOfShape aShapes = anObjectToShapes[aObject];
+        GeomShapePtr aShapePtr = aPrs->shape();
+        if (aShapes.Contains(aShapePtr->impl<TopoDS_Shape>())) {
+          aToRemove.insert(aIt.key());
+        }
+      }
+    }
 
     myItems.insert(myLastItemIndex, aPrs);
     myListView->addItem(aItemName, myLastItemIndex);
     myLastItemIndex++;
     isModified = true;
-
-    if (anObjectToShapes.find(anObject) != anObjectToShapes.end())
-      anObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(aPrs));
-    else {
-      NCollection_List<TopoDS_Shape> aListOfShapes;
-      aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(aPrs));
-      anObjectToShapes[anObject] = aListOfShapes;
-      anObjectToPrs[anObject] = aResultPrs;
-    }
   }
-  for (std::map<ObjectPtr, NCollection_List<TopoDS_Shape> >::const_iterator
-    anIt = anObjectToShapes.begin(); anIt != anObjectToShapes.end(); anIt++) {
+
+  // Hide fully hidden shapes
+  std::map<ObjectPtr, TopoDS_ListOfShape>::const_iterator anIt;
+  for (anIt = anObjectToShapes.begin(); anIt != anObjectToShapes.end(); anIt++) {
     ObjectPtr anObject = anIt->first;
     if (!anObject.get() || anObjectToPrs.find(anObject) == anObjectToPrs.end())
       continue;
@@ -263,11 +382,35 @@ void XGUI_FacesPanel::processSelection()
     }
     ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
   }
+
+  // Process selected presentations
+  double aTransp = transparency();
+  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::iterator aPrsIt;
+  for (aPrsIt = anObjectToPrs.begin(); aPrsIt != anObjectToPrs.end(); aPrsIt++) {
+    ObjectPtr anObject = aPrsIt->first;
+    Handle(ModuleBase_ResultPrs) aPrs = aPrsIt->second;
+    TopoDS_ListOfShape aAlreadyHidden = aPrs->hiddenSubShapes();
+    TopoDS_ListOfShape aListOfShapes = anObjectToShapes[anObject];
+    TopoDS_ListOfShape::Iterator aShapesIt(aListOfShapes);
+    for (; aShapesIt.More(); aShapesIt.Next()) {
+      if (!aAlreadyHidden.Contains(aShapesIt.Value()))
+        aAlreadyHidden.Append(aShapesIt.Value());
+    }
+    aPrs->setSubShapeHidden(aAlreadyHidden);
+    aPrs->setHiddenSubShapeTransparency(aTransp);
+  }
+
+  // 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);
+  }
   if (isModified) {
     updateProcessedObjects(myItems, myItemObjects);
     flushRedisplay();
   }
-  onTransparencyChanged();
 }
 
 //********************************************************************
@@ -282,32 +425,50 @@ bool XGUI_FacesPanel::processDelete()
     return false;
 
   bool isModified = false;
-  std::set<ObjectPtr> aRestoredObjects;
-  for (std::set<int>::const_iterator anIt = aSelectedIds.begin(); anIt != aSelectedIds.end();
-       anIt++) {
+  std::set<ModuleBase_ViewerPrsPtr> aRestored;
+  std::set<int>::const_iterator anIt;
+  for (anIt = aSelectedIds.begin(); anIt != aSelectedIds.end(); anIt++) {
     ModuleBase_ViewerPrsPtr aPrs = myItems[*anIt];
-    if (aRestoredObjects.find(aPrs->object()) == aRestoredObjects.end())
-      aRestoredObjects.insert(aPrs->object());
-    myItems.remove(*anIt);
-    isModified = true;
+    if (aRestored.find(aPrs) == aRestored.end()) {
+      aRestored.insert(aPrs);
+      myItems.remove(*anIt);
+      isModified = true;
+    }
   }
-  if (isModified) {
-    bool isRedisplayed = redisplayObjects(aRestoredObjects);
-    isRedisplayed = displayHiddenObjects(aRestoredObjects, myHiddenObjects)
-                    || isRedisplayed;
-    if (isRedisplayed) {
-      flushRedisplay();
-      myWorkshop->viewer()->update();
+  std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
+  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+
+  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);
+      if (aGrpIt != myHiddenGroups.end()) {
+        aResGroup->setDisplayed(true);
+        myHiddenGroups.erase(aGrpIt);
+      }
     }
-    // should be after flush of redisplay to have items object to be updated
-    updateProcessedObjects(myItems, myItemObjects);
+  }
 
+  std::set<ObjectPtr> aRestoredObjects;
+  std::map<ObjectPtr, TopoDS_ListOfShape>::const_iterator aShapesIt;
+  for (aShapesIt = anObjectToShapes.begin(); aShapesIt != anObjectToShapes.end(); aShapesIt++) {
+    TopoDS_ListOfShape aShapes = aShapesIt->second;
+    aRestoredObjects.insert(aShapesIt->first);
+    Handle(ModuleBase_ResultPrs) aPrs = anObjectToPrs[aShapesIt->first];
+    TopoDS_ListOfShape aHiddenShapes = aPrs->hiddenSubShapes();
+    TopoDS_ListOfShape::Iterator aSubShapesIt(aShapes);
+    for (; aSubShapesIt.More(); aSubShapesIt.Next()) {
+      if (aHiddenShapes.Contains(aSubShapesIt.Value()))
+        aHiddenShapes.Remove(aSubShapesIt.Value());
+    }
+    aPrs->setSubShapeHidden(aHiddenShapes);
   }
+  if (redisplayObjects(aRestoredObjects))
+    flushRedisplay();
 
   myListView->removeSelectedItems();
-  // Restore selection
-  myListView->restoreSelection(anIndices);
-  //appendSelectionInHistory();
   return true;
 }
 
@@ -332,79 +493,6 @@ bool XGUI_FacesPanel::redisplayObjects(
   return isModified;
 }
 
-//********************************************************************
-bool XGUI_FacesPanel::displayHiddenObjects(
-  const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects,
-  std::set<std::shared_ptr<ModelAPI_Object> >& theHiddenObjects)
-{
-  if (theObjects.empty())
-    return false;
-
-  bool isModified = false;
-  static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-
-  for (std::set<ObjectPtr>::const_iterator anIt = theObjects.begin(); anIt != theObjects.end();
-       anIt++)
-  {
-    ObjectPtr anObject = *anIt;
-    // if the object was hidden by this panel
-    if (anObject->isDisplayed() || theHiddenObjects.find(anObject) == theHiddenObjects.end())
-      continue;
-    theHiddenObjects.erase(anObject);
-    anObject->setDisplayed(true); // it means that the object is hidden by hide all faces
-    ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
-    isModified = true;
-  }
-  return isModified;
-}
-
-//********************************************************************
-bool XGUI_FacesPanel::hideEmptyObjects()
-{
-  bool isModified = false;
-  static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-  std::map<ObjectPtr, NCollection_List<TopoDS_Shape> > anObjectToShapes;
-  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
-
-  for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = myItems.begin();
-       anIt != myItems.end(); anIt++) {
-    ModuleBase_ViewerPrsPtr aPrs = anIt.value();
-    ObjectPtr anObject = aPrs->object();
-    if (!anObject.get() || !anObject->isDisplayed())
-      continue;
-
-    Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
-      aPrs->interactive());
-    if (aResultPrs.IsNull())
-      continue;
-
-    if (anObjectToShapes.find(anObject) != anObjectToShapes.end())
-      anObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(aPrs));
-    else {
-      NCollection_List<TopoDS_Shape> aListOfShapes;
-      aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(aPrs));
-      anObjectToShapes[anObject] = aListOfShapes;
-      anObjectToPrs[anObject] = aResultPrs;
-    }
-  }
-  for (std::map<ObjectPtr, NCollection_List<TopoDS_Shape> >::const_iterator
-    anIt = anObjectToShapes.begin(); anIt != anObjectToShapes.end(); anIt++) {
-    ObjectPtr anObject = anIt->first;
-    if (!anObject.get() || anObjectToPrs.find(anObject) == anObjectToPrs.end())
-      continue;
-    Handle(ModuleBase_ResultPrs) aResultPrs = anObjectToPrs.at(anObject);
-
-    if (!aResultPrs->hasSubShapeVisible(anIt->second)) {
-      // erase object because it is entirely hidden
-      anObject->setDisplayed(false);
-      myHiddenObjects.insert(anObject);
-      ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
-      isModified = true;
-    }
-  }
-  return isModified;
-}
-
 //********************************************************************
 void XGUI_FacesPanel::updateProcessedObjects(QMap<int, ModuleBase_ViewerPrsPtr> theItems,
                                              std::set<ObjectPtr>& theObjects)
@@ -414,9 +502,23 @@ void XGUI_FacesPanel::updateProcessedObjects(QMap<int, ModuleBase_ViewerPrsPtr>
        anIt != theItems.end(); anIt++) {
     ModuleBase_ViewerPrsPtr aPrs = anIt.value();
     ObjectPtr anObject = aPrs.get() ? aPrs->object() : ObjectPtr();
-    if (anObject.get() && theObjects.find(anObject) != theObjects.end())
-      continue;
-    theObjects.insert(anObject);
+    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);
+      }
+    }
   }
 }
 
@@ -427,46 +529,6 @@ void XGUI_FacesPanel::closeEvent(QCloseEvent* theEvent)
   emit closed();
 }
 
-//********************************************************************
-bool XGUI_FacesPanel::customizeObject(const ObjectPtr& theObject,
-                                      const AISObjectPtr& thePresentation)
-{
-  if (myLastItemIndex == 0) // do nothing because there was no activity in the pane after reset
-    return false;
-
-  if (thePresentation.get() == NULL)
-    return false;
-
-  if (myItemObjects.find(theObject) == myItemObjects.end()) // not found
-    return false;
-
-  // if the object is displayed, the hidden faces are collected and set to the presentation
-  bool isModified = false;
-  NCollection_List<TopoDS_Shape> aHiddenSubShapes;
-  for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = myItems.begin();
-    anIt != myItems.end(); anIt++) {
-    ModuleBase_ViewerPrsPtr aPrs = anIt.value();
-    if (aPrs.get() && aPrs->object() != theObject)
-      continue;
-    TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
-    if (!aHiddenSubShapes.Contains(aShape))
-      aHiddenSubShapes.Append(aShape);
-  }
-
-  Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
-    thePresentation->impl<Handle(AIS_InteractiveObject)>());
-  if (aResultPrs.IsNull())
-    return false;
-
-  isModified = aResultPrs->setSubShapeHidden(aHiddenSubShapes);
-
-  double aTransparency = !useTransparency() ? 1
-    : Config_PropManager::real("Visualization", "hidden_face_transparency");
-  isModified = aResultPrs->setHiddenSubShapeTransparency(aTransparency) || isModified;
-
-  return isModified;
-}
-
 //********************************************************************
 void XGUI_FacesPanel::onDeleteItem()
 {
@@ -476,16 +538,21 @@ void XGUI_FacesPanel::onDeleteItem()
 //********************************************************************
 void XGUI_FacesPanel::onTransparencyChanged()
 {
-  bool isModified = false;
-  if (useTransparency()) {
-    std::set<std::shared_ptr<ModelAPI_Object> > aHiddenObjects = myHiddenObjects;
-    isModified = displayHiddenObjects(aHiddenObjects, myHiddenObjects);
+  std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
+  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+  QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> >::const_iterator aIt;
+  for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
+    getObjectsMapFromPrs(aIt.value(), anObjectToShapes, anObjectToPrs);
   }
-  else
-    isModified = hideEmptyObjects();
 
-  isModified = redisplayObjects(myItemObjects) || isModified;
-  if (isModified)
+  double aTransp = Config_PropManager::real("Visualization", "hidden_face_transparency");
+  std::set<ObjectPtr> aObjects;
+  std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::const_iterator aPrsIt;
+  for (aPrsIt = anObjectToPrs.cbegin(); aPrsIt != anObjectToPrs.cend(); aPrsIt++) {
+    aObjects.insert(aPrsIt->first);
+    aPrsIt->second->setHiddenSubShapeTransparency(useTransparency()? aTransp : 1);
+  }
+  if (redisplayObjects(aObjects))
     flushRedisplay();
 }
 
@@ -501,7 +568,8 @@ void XGUI_FacesPanel::flushRedisplay() const
 {
   Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY));
   // Necessary for update visibility icons in ObjectBrowser
-  XGUI_ObjectsBrowser* anObjectBrowser = XGUI_Tools::workshop(myWorkshop)->objectBrowser();
+  XGUI_ObjectsBrowser* anObjectBrowser = myWorkshop->objectBrowser();
   if (anObjectBrowser)
     anObjectBrowser->updateAllIndexes();
+  myWorkshop->viewer()->update();
 }
index d4a0b04dae171cd5badcb5fba7e4715ee69f0c63..d442ee6b87f174b51cfc1a7e0f138f9f882fbfd8 100644 (file)
 #include <ModuleBase_ActionType.h>
 #include <ModuleBase_Definitions.h>
 #include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_ResultPrs.h>
 
 #include <SelectMgr_ListOfFilter.hxx>
+#include <TopoDS_Shape.hxx>
 
 #include <QDockWidget>
 #include <QObject>
@@ -40,7 +42,7 @@ class AIS_InteractiveObject;
 
 class GeomAPI_AISObject;
 
-class ModuleBase_IWorkshop;
+class XGUI_Workshop;
 class ModuleBase_ListView;
 
 class QAction;
@@ -69,7 +71,7 @@ class XGUI_EXPORT XGUI_FacesPanel : public QDockWidget
 public:
   /// Constructor
   /// \param theParent is a parent of the property panel
-  XGUI_FacesPanel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop);
+  XGUI_FacesPanel(QWidget* theParent, XGUI_Workshop* theWorkshop);
   ~XGUI_FacesPanel() {}
 
   /// Clear content of list widget
@@ -95,10 +97,6 @@ public:
   /// \param theIsActive state whether the panel should be activated or deactivated
   void setActivePanel(const bool theIsActive);
 
-  /// Returns true if transparency choice is checked
-  /// \return boolean value
-  bool useTransparency() const;
-
   /// Returns true if the object is in internal container of hidden objects by this panel
   /// \param theObject a checked object
   /// \return boolean value
@@ -124,16 +122,8 @@ public:
   /// \param theEvent an event
   virtual bool eventFilter(QObject* theObject, QEvent *theEvent);
 
-  /// Hide/show faces of the object if:
-  /// - face selector is active
-  /// - object is mentioned in the list of selected elements
-  /// If the object is displayed, all panel faces selected on it will be moved into presentation
-  /// or, if redisplayed, fuction return if the object should be redisplayed or not
-  /// \param theObject a customized object
-  /// \param thePresentation visualized presentation of the object
-  /// \return true if the presentation is customized
-  bool customizeObject(const std::shared_ptr<ModelAPI_Object>& theObject,
-    const std::shared_ptr<GeomAPI_AISObject>& thePresentation);
+  XGUI_Workshop* workshop() const { return myWorkshop; }
+
 
 protected:
   /// Reimplementation to emit a signal about the panel close
@@ -153,23 +143,28 @@ private:
   /// \return true if some of objects was redisplayed
   static bool redisplayObjects(const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects);
 
-  /// Display objects if the objects are in a container of hidden by this pane.
-  /// \param theObjects container of objects
-  /// \param theHiddenObjects hidden objects, if object is in the container, it should be removed
-  /// \return true if some of objects was redisplayed
-  static bool displayHiddenObjects(const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects,
-                                   std::set<std::shared_ptr<ModelAPI_Object> >& theHiddenObjects);
-
-  /// Iterates by items and hide objects where all sub-shapes are hidden
-  /// \return true if some of objects was redisplayed
-  bool hideEmptyObjects();
-
   /// 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);
 
+  /// 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
+  /// The function doesn't clear content of input maps.
+  /// \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,
+    std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectsToShapes,
+    std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs);
+
+  /// Returns true if transparency choice is checked
+  /// \return boolean value
+  bool useTransparency() const;
+
+  double transparency() const;
+
 protected slots:
   /// Deletes element in list of items
   void onDeleteItem();
@@ -188,14 +183,15 @@ private:
 protected:
   QCheckBox* myHiddenOrTransparent; ///< if checked - transparent, else hidden
   ModuleBase_ListView* myListView; ///< list control of processed faces
-  ModuleBase_IWorkshop* myWorkshop; ///< workshop
+  XGUI_Workshop* myWorkshop; ///< workshop
 
   bool myIsActive; ///< current state about the panel is active
   int myLastItemIndex; ///< last index to be used in the map of items for the next added item
 
-  QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> > myItems; ///< selected face items
+  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
 };
 
 #endif
\ No newline at end of file
index 6d615ac06dbe53dce38181ce38f964017dc631b9..95ae953a1bbe81cdc0dee04e8904c31ae4a4382d 100644 (file)
 //
 
 #include "XGUI_InspectionPanel.h"
+#include "XGUI_Workshop.h"
 #include "XGUI_SelectionMgr.h"
 #include "XGUI_Selection.h"
 #include "XGUI_Tools.h"
+#include "XGUI_ModuleConnector.h"
 
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_Tools.h>
+#include <ModuleBase_OperationDescription.h>
+#include <ModuleBase_WidgetFactory.h>
+#include <ModuleBase_IModule.h>
+#include <ModuleBase_PageWidget.h>
+
 #include <ModelAPI_ResultField.h>
 
 #include <ModelAPI_Result.h>
@@ -54,6 +61,7 @@
 #include <QTextBrowser>
 #include <QResizeEvent>
 #include <QSplitter>
+#include <QStackedWidget>
 
 #include <BRepBndLib.hxx>
 #include <TopoDS_Iterator.hxx>
@@ -61,6 +69,7 @@
 #include <TopTools_ListOfShape.hxx>
 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic
 
+
 // ================     Auxiliary functions     ================
 #define TITLE(val) ("<b>" + (val) + "</b>")
 
@@ -108,15 +117,18 @@ static void appendNamedValueToParameters(const QString& theName,
 
 // ================     XGUI_InspectionPanel    ================
 
-XGUI_InspectionPanel::XGUI_InspectionPanel(QWidget* theParent, XGUI_SelectionMgr* theMgr)
+XGUI_InspectionPanel::XGUI_InspectionPanel(QWidget* theParent, XGUI_Workshop* theWorkshop)
   : QDockWidget(theParent),
-  mySelectionMgr(theMgr)
+  myWorkshop(theWorkshop)
 {
   setWindowTitle(tr("Inspection Panel"));
   setObjectName(INSPECTION_PANEL);
   setStyleSheet("::title { position: relative; padding-left: 5px; text-align: left center }");
 
-  QSplitter* aSplitter = new QSplitter(Qt::Vertical, this);
+  myStackWgt = new QStackedWidget(this);
+
+  // Create shape selection page
+  QSplitter* aSplitter = new QSplitter(Qt::Vertical, myStackWgt);
 
   // Create an internal widget
   QWidget* aNameWgt = new QWidget(aSplitter);
@@ -184,9 +196,23 @@ XGUI_InspectionPanel::XGUI_InspectionPanel(QWidget* theParent, XGUI_SelectionMgr
   aSizes << 10 << 140 << 10;
   aSplitter->setSizes(aSizes);
 
-  setWidget(aSplitter);
+  myShapePanelId = myStackWgt->addWidget(aSplitter);
+
+  // Create feature selection page
+  QScrollArea* aScroll = new QScrollArea(myStackWgt);
+  aScroll->setWidgetResizable(true);
+  aScroll->setFrameStyle(QFrame::NoFrame);
+
+  myFeaturePane = new ModuleBase_PageWidget(aScroll);
+  myFeatureLayout = new QGridLayout(myFeaturePane);
+  myFeatureLayout->setContentsMargins(3, 3, 3, 3);
+  aScroll->setWidget(myFeaturePane);
+  //myFeaturePane->setEnabled(false);
 
-  connect(mySelectionMgr, SIGNAL(selectionChanged()), SLOT(onSelectionChanged()));
+  myFeaturePanelId = myStackWgt->addWidget(aScroll);
+
+  setWidget(myStackWgt);
+  connect(myWorkshop->selector(), SIGNAL(selectionChanged()), SLOT(onSelectionChanged()));
 }
 
 //********************************************************************
@@ -209,20 +235,21 @@ void XGUI_InspectionPanel::clearContent()
   }
   myTypeLbl->setText("");
   setParamsText("");
+
+  myFeaturePane->clearPage();
 }
 
 //********************************************************************
 void XGUI_InspectionPanel::onSelectionChanged()
 {
+  if (!isVisible())
+    return;
+
   clearContent();
-  XGUI_Selection* aSelection = mySelectionMgr->selection();
-  QList<ModuleBase_ViewerPrsPtr> aSelectedList =
-    aSelection->getSelected(ModuleBase_ISelection::Viewer);
 
-  QList<ModuleBase_ViewerPrsPtr> anOBSelected =
-    aSelection->getSelected(ModuleBase_ISelection::Browser);
-  if (!anOBSelected.isEmpty())
-    ModuleBase_ISelection::appendSelected(anOBSelected, aSelectedList);
+  XGUI_Selection* aSelection = myWorkshop->selector()->selection();
+  QList<ModuleBase_ViewerPrsPtr> aSelectedList =
+    aSelection->getSelected(myWorkshop->selector()->placeOfSelection());
 
   if (aSelectedList.count() > 0) {
     ModuleBase_ViewerPrsPtr aPrs = aSelectedList.first();
@@ -230,25 +257,33 @@ void XGUI_InspectionPanel::onSelectionChanged()
       std::dynamic_pointer_cast<ModelAPI_ResultField::ModelAPI_FieldStep>(aPrs->object());
     if (aStep)
       return;
-    TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
-    if (aShape.IsNull()) {
-      ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
-      if (aRes.get()) {
-        GeomShapePtr aShpPtr = aRes->shape();
-        if (aShpPtr.get()) {
-          aShape = aShpPtr->impl<TopoDS_Shape>();
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs->object());
+    if (aFeature.get()) {
+      myStackWgt->setCurrentIndex(myFeaturePanelId);
+      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 (aRes.get()) {
+          GeomShapePtr aShpPtr = aRes->shape();
+          if (aShpPtr.get()) {
+            aShape = aShpPtr->impl<TopoDS_Shape>();
+          }
         }
       }
+      if (aShape.IsNull())
+        return;
+      GeomShapePtr aShapePtr(new GeomAPI_Shape());
+      aShapePtr->setImpl(new TopoDS_Shape(aShape));
+
+      ModuleBase_ViewerPrsPtr aPrsCopy(new ModuleBase_ViewerPrs(aPrs->object(), aShapePtr));
+      setName(XGUI_Tools::generateName(aPrsCopy));
+      setShapeContent(aShape);
+      setShapeParams(aShape);
     }
-    if (aShape.IsNull())
-      return;
-    GeomShapePtr aShapePtr(new GeomAPI_Shape());
-    aShapePtr->setImpl(new TopoDS_Shape(aShape));
-
-    ModuleBase_ViewerPrsPtr aPrsCopy(new ModuleBase_ViewerPrs(aPrs->object(), aShapePtr));
-    setName(XGUI_Tools::generateName(aPrsCopy));
-    setShapeContent(aShape);
-    setShapeParams(aShape);
   }
 }
 
@@ -606,6 +641,7 @@ void XGUI_InspectionPanel::fillContainer(const GeomShapePtr& theShape)
   appendPointToParameters(tr("Maximal corner"), aMaxPoint, aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setPlaneType(const QString& theTitle,
                                         const std::shared_ptr<GeomAPI_Pln>& thePlane)
 {
@@ -616,6 +652,7 @@ void XGUI_InspectionPanel::setPlaneType(const QString& theTitle,
   setParamsText(aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setSphereType(const QString& theTitle,
                                          const std::shared_ptr<GeomAPI_Sphere>& theSphere)
 {
@@ -627,6 +664,7 @@ void XGUI_InspectionPanel::setSphereType(const QString& theTitle,
   setParamsText(aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setCylinderType(const QString& theTitle,
                                            const std::shared_ptr<GeomAPI_Cylinder>& theCyl)
 {
@@ -640,6 +678,7 @@ void XGUI_InspectionPanel::setCylinderType(const QString& theTitle,
   setParamsText(aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setConeType(const QString& theTitle,
                                        const std::shared_ptr<GeomAPI_Cone>& theCone)
 {
@@ -654,6 +693,7 @@ void XGUI_InspectionPanel::setConeType(const QString& theTitle,
   setParamsText(aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setTorusType(const QString& theTitle,
                                         const std::shared_ptr<GeomAPI_Torus>& theTorus)
 {
@@ -667,6 +707,7 @@ void XGUI_InspectionPanel::setTorusType(const QString& theTitle,
   setParamsText(aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setBoxType(const QString& theTitle,
                                       const std::shared_ptr<GeomAPI_Box>& theBox)
 {
@@ -680,6 +721,7 @@ void XGUI_InspectionPanel::setBoxType(const QString& theTitle,
   setParamsText(aParams);
 }
 
+//********************************************************************
 void XGUI_InspectionPanel::setRotatedBoxType(const QString& theTitle,
                                              const std::shared_ptr<GeomAPI_Box>& theBox)
 {
@@ -697,7 +739,43 @@ void XGUI_InspectionPanel::setRotatedBoxType(const QString& theTitle,
 }
 
 
+//********************************************************************
 void XGUI_InspectionPanel::setParamsText(const QString& theText)
 {
   myTypeParams->setText(theText);
 }
+
+//********************************************************************
+void XGUI_InspectionPanel::buildFeaturePane(const FeaturePtr& theFeature)
+{
+  std::string aXmlCfg, aDescription;
+  myWorkshop->module()->getXMLRepresentation(theFeature->getKind(), aXmlCfg, aDescription);
+  if (!aXmlCfg.empty()) {
+    QList<ModuleBase_ModelWidget*> aWidgets;
+    if (!myWorkshop->module()->createWidgets(theFeature, aXmlCfg.c_str(), aWidgets)) {
+      ModuleBase_WidgetFactory aFactory(aXmlCfg, myWorkshop->moduleConnector());
+      aFactory.createWidget(myFeaturePane);
+      aWidgets = aFactory.getModelWidgets();
+    }
+    foreach(ModuleBase_ModelWidget* aWgt, aWidgets) {
+      if (aWgt->isInformative()) {
+        aWgt->setFeature(theFeature, false, false);
+        aWgt->setReadOnly(true);
+        aWgt->setEditingMode(true);
+        aWgt->restoreValue();
+        aWgt->showInformativePage();
+      }
+      else {
+        aWgt->setFeature(theFeature, false, false);
+        aWgt->setEditingMode(true);
+        aWgt->hide();
+      }
+    }
+  }
+}
+
+void XGUI_InspectionPanel::showEvent(QShowEvent* theEvent)
+{
+  QDockWidget::showEvent(theEvent);
+  onSelectionChanged();
+}
index 3f980ea42071aecdc69ee4e293b909f51ef6fdae..9f60ff56ea7291d00c797ce36d7c137bf4920399 100644 (file)
 
 #include "XGUI.h"
 
+#include <ModelAPI_Feature.h>
+
 #include <QDockWidget>
 
 #include <memory>
 
-class XGUI_SelectionMgr;
+class XGUI_Workshop;
 class QLineEdit;
 class QTableWidget;
 class QLabel;
 class QTextBrowser;
 class QVBoxLayout;
 class QResizeEvent;
+class QStackedWidget;
+class QGridLayout;
 
 class TopoDS_Shape;
 
@@ -50,6 +54,7 @@ class GeomAPI_Cylinder;
 class GeomAPI_Cone;
 class GeomAPI_Torus;
 class GeomAPI_Box;
+class ModuleBase_PageWidget;
 
 /// Internal name of property panel widget
 const static char* INSPECTION_PANEL = "inspection_panel_dock";
@@ -78,11 +83,13 @@ public:
   /// Constructor
   /// \param theParent is a parent of the property panel
   /// \param theMgr operation manager
-  XGUI_InspectionPanel(QWidget* theParent, XGUI_SelectionMgr* theMgr);
+  XGUI_InspectionPanel(QWidget* theParent, XGUI_Workshop* theWorkshop);
 
   // Destructor
   virtual ~XGUI_InspectionPanel();
 
+protected:
+  virtual void showEvent(QShowEvent* theEvent);
 
 private slots:
   /// A slot to react on selection changed
@@ -172,20 +179,27 @@ private:
   /// \param theBox the box
   void setRotatedBoxType(const QString& theTitle, const std::shared_ptr<GeomAPI_Box>& theBox);
 
-
   /// Set text into parameters area
   /// \param theText the text
   void setParamsText(const QString& theText);
 
+  /// Fills Feature panel with controls specific to the given feature
+  /// \param theFeature the selected feature
+  void buildFeaturePane(const FeaturePtr& theFeature);
+
 private:
-  XGUI_SelectionMgr* mySelectionMgr; //> selection manager
-
-  QLineEdit* myNameEdt; //> Name field
-  QTableWidget* mySubShapesTab; //> table of sub-shapes
-  QLabel* myTypeLbl; //> label of a type
-  QTextBrowser* myTypeParams; //> parameters area
-  QVBoxLayout* myMainLayout; //> main layout
-  //QWidget* myMainWidget;  //> main widget
+  XGUI_Workshop* myWorkshop; //> selection manager
+
+  QLineEdit* myNameEdt; ///> Name field
+  QTableWidget* mySubShapesTab; ///> table of sub-shapes
+  QLabel* myTypeLbl; ///> label of a type
+  QTextBrowser* myTypeParams; ///> parameters area
+  QVBoxLayout* myMainLayout; ///> main layout
+  ModuleBase_PageWidget* myFeaturePane; ///> Content of feature property panel
+  QGridLayout* myFeatureLayout; ///> Layout of feature panel
+  QStackedWidget* myStackWgt; ///> base widget of the panel
+  int myShapePanelId;
+  int myFeaturePanelId;
 };
 
 #endif
\ No newline at end of file
index 61bc814f47c7db8fdfb36ce8cc1bc2104faf7868..b0ee40950c0511083162f829f87ded6aa77b1d55 100644 (file)
@@ -130,13 +130,7 @@ void XGUI_ModuleConnector::setSelected(const QList<ModuleBase_ViewerPrsPtr>& the
     myWorkshop->selector()->clearSelection();
     aBrowser->treeView()->clearSelection();
   } else {
-    aDisp->setSelected(theValues);
-    // Synchronise the selection with Object browser
-    QObjectPtrList anObjects;
-    foreach(ModuleBase_ViewerPrsPtr aVal, theValues) {
-      anObjects.append(aVal->object());
-    }
-    aBrowser->setObjectsSelected(anObjects);
+    myWorkshop->selector()->setSelected(theValues);
   }
 }
 
@@ -232,4 +226,38 @@ void XGUI_ModuleConnector::applyCurrentSelectionModes(const AISObjectPtr& theAIS
 {
   Handle(AIS_InteractiveObject) anIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
   myWorkshop->selectionActivate()->activate(anIO, false);
-}
\ No newline at end of file
+}
+
+
+void XGUI_ModuleConnector::undo()
+{
+  myWorkshop->onUndo();
+}
+
+void XGUI_ModuleConnector::setCancelEnabled(bool toEnable)
+{
+  XGUI_ActionsMgr* anActionsMgr = workshop()->actionsMgr();
+  QAction* aAbortAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::AbortAll);
+  QAction* aAbortAllAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
+  if (aAbortAction) {
+    aAbortAction->setEnabled(toEnable);
+  }
+  if (aAbortAllAction) {
+    aAbortAllAction->setEnabled(toEnable);
+  }
+}
+
+bool XGUI_ModuleConnector::isCancelEnabled() const
+{
+  XGUI_ActionsMgr* anActionsMgr = workshop()->actionsMgr();
+  QAction* aAbortAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::AbortAll);
+  QAction* aAbortAllAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
+  bool isEnabled = false;
+  if (aAbortAction) {
+    isEnabled = true;
+  }
+  if (aAbortAllAction) {
+    isEnabled &= true;
+  }
+  return isEnabled;
+}
index 41415fdf39be9daf4c70fd9d6eed77cd5c516dfb..ca31763a8c95b895eae38cc88635ed6e37173dfb 100644 (file)
@@ -136,6 +136,15 @@ Q_OBJECT
   //! \param theAIS the object which has to be activated
   virtual void applyCurrentSelectionModes(const AISObjectPtr& theAIS);
 
+  //! Undo last command
+  virtual void undo();
+
+  //! Set enabled state of cancel button in property panel
+  virtual void setCancelEnabled(bool toEnable);
+
+  //! Returns current state of cancel button
+  virtual bool isCancelEnabled() const;
+
 private:
   QObjectPtrList activeObjects(const QObjectPtrList& theObjList) const;
 
index f159dd4b5f4bc086dd509b611c3911148626e51b..68c1b535de7750db8d196df5116e098b665930aa 100644 (file)
@@ -628,8 +628,8 @@ void XGUI_OperationMgr::onOperationStopped()
     }
   }
   if (aResultOp) {
-    bool isModified = aCurrentOperation->isModified();
-    aResultOp->setIsModified(aResultOp->isModified() || isModified);
+    //bool isModified = aCurrentOperation->isModified();
+    //aResultOp->setIsModified(aResultOp->isModified() || isModified);
     resumeOperation(aResultOp);
     onValidateOperation();
   }
@@ -843,7 +843,7 @@ bool XGUI_OperationMgr::onProcessDelete(QObject* theObject)
     /// processing delete by workshop
     XGUI_ObjectsBrowser* aBrowser = XGUI_Tools::workshop(myWorkshop)->objectBrowser();
     QWidget* aViewPort = myWorkshop->viewer()->activeViewPort();
-    bool isToDeleteObject = false;
+    bool isToDeleteObject = true;
     XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
     XGUI_ContextMenuMgr* aContextMenuMgr = aWorkshop->contextMenuMgr();
     if (theObject == aBrowser->treeView()) {
index 17d4f6d59b5f59f3289c0e3fd004a29de77fa5ae..b7c1a65bca80bb5cf842574e5010e8fdd1ba2125 100644 (file)
@@ -106,6 +106,7 @@ void XGUI_SelectionMgr::setSelectedOwners(const SelectMgr_IndexedMapOfOwner& the
 //**************************************************************
 void XGUI_SelectionMgr::onObjectBrowserSelection()
 {
+  myLastSelectionPlace = ModuleBase_ISelection::Browser;
   QList<ModuleBase_ViewerPrsPtr> aSelectedPrs =
     myWorkshop->selector()->selection()->getSelected(ModuleBase_ISelection::Browser);
   XGUI_Displayer* aDisplayer = myWorkshop->displayer();
@@ -138,6 +139,7 @@ void XGUI_SelectionMgr::onObjectBrowserSelection()
 //**************************************************************
 void XGUI_SelectionMgr::onViewerSelection()
 {
+  myLastSelectionPlace = ModuleBase_ISelection::Viewer;
   QList<ModuleBase_ViewerPrsPtr> aValues;
   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
   if (!aContext.IsNull())
index 1a4e519b3a2ad1a5e2a6323c724ba169b993a34b..6b7adae6b5361f65459c60fa0193211346d51628 100644 (file)
@@ -57,6 +57,10 @@ Q_OBJECT
     return mySelection;
   }
 
+  ModuleBase_ISelection::SelectionPlace placeOfSelection() const {
+    return myLastSelectionPlace;
+  }
+
   //! Connects the manager to all viewers accessible by Workshop
   void connectViewers();
 
@@ -111,6 +115,8 @@ private:
 
   /// Current selection object
   XGUI_Selection* mySelection;
+
+  ModuleBase_ISelection::SelectionPlace myLastSelectionPlace;
 };
 
 #endif
index cb66e1837fdaf24eb62da0d0f3ce818caf4f65e2..ae2bb898412f6d02e03a09813dec6e30b8ef9058 100644 (file)
@@ -250,40 +250,42 @@ QString generateName(const ModuleBase_ViewerPrsPtr& thePrs)
   if (aContext.get()) {
     GeomShapePtr aSubShape(new GeomAPI_Shape());
     TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(thePrs);
-    aSubShape->setImpl(new TopoDS_Shape(aShape));
-    if (!aSubShape->isEqual(aContext)) {
-      QString aTypeName;
-      switch (aShape.ShapeType()) {
-      case TopAbs_COMPOUND:
-        aTypeName = "compound";
-        break;
-      case TopAbs_COMPSOLID:
-        aTypeName = "compsolid";
-        break;
-      case TopAbs_SOLID:
-        aTypeName = "solid";
-        break;
-      case TopAbs_SHELL:
-        aTypeName = "shell";
-        break;
-      case TopAbs_FACE:
-        aTypeName = "face";
-        break;
-      case TopAbs_WIRE:
-        aTypeName = "wire";
-        break;
-      case TopAbs_EDGE:
-        aTypeName = "edge";
-        break;
-      case TopAbs_VERTEX:
-        aTypeName = "vertex";
-        break;
-      case TopAbs_SHAPE:
-        aTypeName = "shape";
-        break;
+    if (!aShape.IsNull()) {
+      aSubShape->setImpl(new TopoDS_Shape(aShape));
+      if (!aSubShape->isEqual(aContext)) {
+        QString aTypeName;
+        switch (aShape.ShapeType()) {
+        case TopAbs_COMPOUND:
+          aTypeName = "compound";
+          break;
+        case TopAbs_COMPSOLID:
+          aTypeName = "compsolid";
+          break;
+        case TopAbs_SOLID:
+          aTypeName = "solid";
+          break;
+        case TopAbs_SHELL:
+          aTypeName = "shell";
+          break;
+        case TopAbs_FACE:
+          aTypeName = "face";
+          break;
+        case TopAbs_WIRE:
+          aTypeName = "wire";
+          break;
+        case TopAbs_EDGE:
+          aTypeName = "edge";
+          break;
+        case TopAbs_VERTEX:
+          aTypeName = "vertex";
+          break;
+        case TopAbs_SHAPE:
+          aTypeName = "shape";
+          break;
+        }
+        int aId = GeomAlgoAPI_CompoundBuilder::id(aContext, aSubShape);
+        aName += QString("/%1_%2").arg(aTypeName).arg(aId);
       }
-      int aId = GeomAlgoAPI_CompoundBuilder::id(aContext, aSubShape);
-      aName += QString("/%1_%2").arg(aTypeName).arg(aId);
     }
   }
   return aName;
index f97e58aa6254e88dbb5d7538b812a2ee41cc5775..5ed8b452746280f8ad6c2b3f5301cc0e4d51ba3a 100644 (file)
@@ -45,7 +45,6 @@
 #include "XGUI_Tools.h"
 #include "XGUI_ViewerProxy.h"
 #include "XGUI_WorkshopListener.h"
-#include <XGUI_CustomPrs.h>
 #include <XGUI_HistoryMenu.h>
 #include <XGUI_QtEvents.h>
 #include <XGUI_DataModel.h>
@@ -67,6 +66,7 @@
 #include <ModelAPI_AttributeDocRef.h>
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_Feature.h>
 #include <Events_InfoMessage.h>
 #include <Events_LongOp.h>
 
+#include <ExchangePlugin_ExportPart.h>
+#include <ExchangePlugin_ImportPart.h>
+
 #include <GeomAPI_Pnt.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <ModuleBase_IModule.h>
 #include <ModuleBase_IViewer.h>
 #include <ModuleBase_Tools.h>
 #include <ModuleBase_WidgetFactory.h>
 #include <ModuleBase_OperationFeature.h>
-#include <ModuleBase_OperationAction.h>
 #include <ModuleBase_PagedContainer.h>
 #include <ModuleBase_WidgetValidated.h>
 #include <ModuleBase_ModelWidget.h>
@@ -168,6 +171,7 @@ static Handle(VInspector_CallBack) MyVCallBack;
 //#define DEBUG_WITH_MESSAGE_REPORT
 
 QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end");
+QString XGUI_Workshop::MOVE_TO_END_SPLIT_COMMAND = QObject::tr("Move to the end and split");
 
 //#define DEBUG_DELETE
 //#define DEBUG_FEATURE_NAME
@@ -183,6 +187,8 @@ static QString MyFilter2(QObject::tr("CAD Builder files (*.cadbld)"));
 static QString MyExtension(".cadbld");
 #endif
 
+static QString MyImportPartFilter(QObject::tr("Part files (*.shaperpart);;All files (*.*)"));
+
 
 //******************************************************
 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
@@ -274,21 +280,8 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
   connect(myEventsListener, SIGNAL(errorOccurred(std::shared_ptr<Events_InfoMessage>)),
           myErrorDlg, SLOT(addError(std::shared_ptr<Events_InfoMessage>)));
 
-  //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color",
-  //                                 Config_Prop::Color, "225,225,225");
-
-  Config_PropManager::registerProp("Visualization", "result_body_color", "Result color",
-                                   Config_Prop::Color, ModelAPI_ResultBody::DEFAULT_COLOR());
-  Config_PropManager::registerProp("Visualization", "result_group_color", "Group color",
-                                   Config_Prop::Color, ModelAPI_ResultGroup::DEFAULT_COLOR());
-  Config_PropManager::registerProp("Visualization", "result_construction_color",
-                                   "Construction color",
-                                   Config_Prop::Color,
-                                   ModelAPI_ResultConstruction::DEFAULT_COLOR());
-  Config_PropManager::registerProp("Visualization", "result_part_color", "Part color",
-                                   Config_Prop::Color, ModelAPI_ResultPart::DEFAULT_COLOR());
-  Config_PropManager::registerProp("Visualization", "result_field_color", "Field color",
-                                   Config_Prop::Color, ModelAPI_ResultField::DEFAULT_COLOR());
+  Config_PropManager::registerProp("Visualization", "selection_color", "Selection color",
+    Config_Prop::Color, "255,255,255");
 
   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "face-selection", true))
     myViewerSelMode.append(TopAbs_FACE);
@@ -346,6 +339,15 @@ void XGUI_Workshop::startApplication()
   // Calling of  loadCustomProps before activating module is required
   // by Config_PropManger to restore user-defined path to plugins
   ModuleBase_Preferences::loadCustomProps();
+  std::vector<int> aColor;
+  try {
+    aColor = Config_PropManager::color("Visualization", "selection_color");
+  }
+  catch (...) {
+  }
+  if (aColor.size() == 3)
+    myDisplayer->setSelectionColor(aColor);
+
   createModule();
 
 #ifndef HAVE_SALOME
@@ -470,6 +472,19 @@ void XGUI_Workshop::initMenu()
   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen()));
   salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
 
+  aAction = salomeConnector()->addDesktopCommand("EXPORT_PART_CMD", tr("Export part..."),
+                                          tr("Export a part of the current document into a file"),
+                                          QIcon(), QKeySequence(),
+                                          false, "MEN_DESK_FILE");
+  connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportPart()));
+
+  aAction = salomeConnector()->addDesktopCommand("IMPORT_PART_CMD", tr("Import part..."),
+                                          tr("Import structure of a part"),
+                                          QIcon(), QKeySequence(),
+                                          false, "MEN_DESK_FILE");
+  connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportPart()));
+  salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
+
 #else
   // File commands group
   AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage();
@@ -676,12 +691,11 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation)
   if (!aFOperation)
     return;
 
-  showPanel(myPropertyPanel);
   myPropertyPanel->cleanContent();
 
   QList<ModuleBase_ModelWidget*> aWidgets;
-  if (!module()->createWidgets(theOperation, aWidgets)) {
-    QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
+  QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
+  if (!module()->createWidgets(aFOperation->feature(), aXmlRepr, aWidgets)) {
     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector);
     aFactory.createWidget(myPropertyPanel->contentWidget());
     aWidgets = aFactory.getModelWidgets();
@@ -762,6 +776,12 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation)
 #endif
 
   myErrorMgr->setPropertyPanel(myPropertyPanel);
+  if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) {
+    theOperation->setHideFacesVisible(myFacesPanel->isVisible());
+    if (aFeatureInfo.get() && aFeatureInfo->isHideFacesPanel() && !myFacesPanel->isVisible())
+      myFacesPanel->show();
+  }
+  showPanel(myPropertyPanel);
 }
 
 //******************************************************
@@ -843,6 +863,11 @@ void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
     }
   }
   activateObjectsSelection(anObjects);
+
+  if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) {
+    if (!theOperation->isHideFacesVisible())
+      myFacesPanel->hide();
+  }
 }
 
 //******************************************************
@@ -1019,6 +1044,8 @@ void XGUI_Workshop::onNew()
   QMdiSubWindow* aWnd = myMainWindow->viewer()->createView();
   aWnd->showMaximized();
   updateCommandStatus();
+  PyConsole_Console* aConsole = myMainWindow->pythonConsole();
+  connect(aConsole, SIGNAL(scriptLoaded()), SLOT(updateCommandStatus()));
 #endif
   myContextMenuMgr->connectViewer();
   QApplication::restoreOverrideCursor();
@@ -1052,8 +1079,7 @@ void XGUI_Workshop::onPreferences()
   ModuleBase_Preferences::editPreferences(aModif);
   if (aModif.size() > 0) {
     QString aSection;
-    foreach (ModuleBase_Pref aPref, aModif)
-    {
+    foreach (ModuleBase_Pref aPref, aModif) {
       aSection = aPref.first;
       if (aSection == ModuleBase_Preferences::VIEWER_SECTION) {
         myMainWindow->viewer()->updateFromResources();
@@ -1061,6 +1087,15 @@ void XGUI_Workshop::onPreferences()
         myMainWindow->menuObject()->updateFromResources();
       }
     }
+    std::vector<int> aColor;
+    try {
+      aColor = Config_PropManager::color("Visualization", "selection_color");
+    }
+    catch (...) {
+    }
+    if (aColor.size() == 3)
+      displayer()->setSelectionColor(aColor);
+
     displayer()->redisplayObjects();
   }
 }
@@ -1184,7 +1219,8 @@ void XGUI_Workshop::processUndoRedo(const ModuleBase_ActionType theActionType, i
     else
       aMgr->redo();
 
-    if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND)
+    if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND ||
+        QString((*aIt).c_str()) == MOVE_TO_END_SPLIT_COMMAND)
       myObjectBrowser->rebuildDataTree();
   }
   operationMgr()->updateApplyOfOperations();
@@ -1243,6 +1279,26 @@ void XGUI_Workshop::onWidgetObjectUpdated()
   myDisplayer->updateViewer();
 }
 
+//******************************************************
+void XGUI_Workshop::onImportPart()
+{
+  if (abortAllOperations()) {
+    ModuleBase_OperationFeature* anImportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
+        module()->createOperation(ExchangePlugin_ImportPart::ID()));
+    operationMgr()->startOperation(anImportPartOp);
+  }
+}
+
+//******************************************************
+void XGUI_Workshop::onExportPart()
+{
+  if (abortAllOperations()) {
+    ModuleBase_OperationFeature* anExportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
+        module()->createOperation(ExchangePlugin_ExportPart::ID()));
+    operationMgr()->startOperation(anExportPartOp);
+  }
+}
+
 //******************************************************
 ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
 {
@@ -1443,14 +1499,14 @@ void XGUI_Workshop::createDockWidgets()
 
   hidePanel(myPropertyPanel);  ///<! Invisible by default
 
-  myFacesPanel = new XGUI_FacesPanel(aDesktop, myModuleConnector);
+  myFacesPanel = new XGUI_FacesPanel(aDesktop, this);
   myActiveControlMgr->addSelector(new XGUI_FacesPanelSelector(myFacesPanel));
   myFacesPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
                                 Qt::RightDockWidgetArea |
                                 Qt::BottomDockWidgetArea);
   connect(myFacesPanel, SIGNAL(closed()), myFacesPanel, SLOT(onClosed()));
 
-  myInspectionPanel = new XGUI_InspectionPanel(aDesktop, mySelector);
+  myInspectionPanel = new XGUI_InspectionPanel(aDesktop, this);
   myInspectionPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
     Qt::RightDockWidgetArea);
   aDesktop->addDockWidget(Qt::RightDockWidgetArea, myInspectionPanel);
@@ -1526,7 +1582,7 @@ void XGUI_Workshop::showPanel(QDockWidget* theDockWidget)
   // in order to operation manager could process key events of the panel.
   // otherwise they are ignored. It happens only if the same(activateWindow) is
   // not happened by property panel activation(e.g. resume operation of Sketch)
-  ModuleBase_Tools::setFocus(theDockWidget, "XGUI_Workshop::showPanel()");
+  //ModuleBase_Tools::setFocus(theDockWidget, "XGUI_Workshop::showPanel()");
 }
 
 //******************************************************
@@ -1585,8 +1641,8 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
     deleteObjects();
   else if (theId == "CLEAN_HISTORY_CMD")
     cleanHistory();
-  else if (theId == "MOVE_CMD")
-    moveObjects();
+  else if (theId == "MOVE_CMD" || theId == "MOVE_SPLIT_CMD")
+    moveObjects(theId == "MOVE_SPLIT_CMD");
   else if (theId == "COLOR_CMD")
     changeColor(aObjects);
   else if (theId == "DEFLECTION_CMD")
@@ -1798,6 +1854,7 @@ void XGUI_Workshop::deleteObjects()
   // allow the module to delete objects, do nothing if it has succeed
   if (aModule->deleteObjects()) {
     updateCommandStatus();
+    myDisplayer->updateViewer();
     return;
   }
 
@@ -1843,7 +1900,7 @@ void XGUI_Workshop::deleteObjects()
   bool aDone = false;
   QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1";
   aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
-  ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
+  ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module());
 
   operationMgr()->startOperation(anOpAction);
 
@@ -2000,7 +2057,7 @@ void XGUI_Workshop::cleanHistory()
     // 1. start operation
     aDescription += "by deleting of " +
       aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
-    ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
+    ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module());
     operationMgr()->startOperation(anOpAction);
 
     // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree
@@ -2043,7 +2100,7 @@ bool compareFeature(const FeaturePtr& theF1, const FeaturePtr& theF2) {
   DocumentPtr aDoc = theF1->document();
   return aDoc->index(theF1) < aDoc->index(theF2);
 }
-void XGUI_Workshop::moveObjects()
+void XGUI_Workshop::moveObjects(const bool theSplit)
 {
   if (!abortAllOperations())
     return;
@@ -2060,7 +2117,7 @@ void XGUI_Workshop::moveObjects()
   if (!XGUI_Tools::canRemoveOrRename(desktop(), aFeatures))
     return;
 
-  QString anActionId = "MOVE_CMD";
+  QString anActionId = theSplit ? "MOVE_CMD" : "MOVE_SPLIT_CMD";
   QString aDescription = contextMenuMgr()->action(anActionId)->text();
   aMgr->startOperation(aDescription.toStdString());
 
@@ -2076,11 +2133,12 @@ void XGUI_Workshop::moveObjects()
     if (!aFeature.get() || !myModule->canApplyAction(aFeature, anActionId))
       continue;
 
-    anActiveDocument->moveFeature(aFeature, aCurrentFeature);
+    anActiveDocument->moveFeature(aFeature, aCurrentFeature, theSplit);
     aCurrentFeature = anActiveDocument->currentFeature(true);
   }
   aMgr->finishOperation();
   updateCommandStatus();
+  myViewerProxy->update();
 }
 
 //**************************************************************
@@ -2280,9 +2338,28 @@ void setColor(ResultPtr theResult, const std::vector<int>& theColor)
     aColorAttr->setValue(1, theColor[1]);
     aColorAttr->setValue(2, theColor[2]);
   }
-  static const Events_ID kRedisplayEvent =
-    Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-  ModelAPI_EventCreator::get()->sendUpdated(theResult, kRedisplayEvent);
+}
+
+//**************************************************************
+void getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
+  std::vector<int>& theColor)
+{
+  theColor.clear();
+  // get default color from the preferences manager for the given result
+  if (theColor.empty()) {
+    std::string aSection, aName, aDefault;
+    theObject->colorConfigInfo(aSection, aName, aDefault);
+    if (!aSection.empty() && !aName.empty()) {
+      theColor = Config_PropManager::color(aSection, aName);
+    }
+  }
+  if (!isEmptyColorValid && theColor.empty()) {
+    // all AIS objects, where the color is not set, are in black.
+    // The color should be defined in XML or set in the attribute
+    theColor = Config_PropManager::color("Visualization", "object_default_color");
+    Events_InfoMessage("XGUI_CustomPrs",
+      "A default color is not defined in the preferences for this kind of result").send();
+  }
 }
 
 //**************************************************************
@@ -2296,7 +2373,9 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects)
   foreach(ObjectPtr anObject, theObjects) {
     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
     if (aResult.get()) {
-      XGUI_CustomPrs::getResultColor(aResult, aColor);
+      ModelAPI_Tools::getColor(aResult, aColor);
+      if (aColor.empty())
+        getDefaultColor(aResult, false, aColor);
     }
     else {
       // TODO: remove the obtaining a color from the AIS object
@@ -2348,8 +2427,10 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects)
       setColor(aResult, !isRandomColor ? aColorResult : aDlg->getRandomColor());
     }
   }
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
   aMgr->finishOperation();
   updateCommandStatus();
+  myViewerProxy->update();
 }
 
 //**************************************************************
@@ -2359,11 +2440,9 @@ void setDeflection(ResultPtr theResult, const double theDeflection)
     return;
 
   AttributeDoublePtr aDeflectionAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID());
-  if (aDeflectionAttr.get() != NULL)
+  if (aDeflectionAttr.get() != NULL) {
     aDeflectionAttr->setValue(theDeflection);
-  static const Events_ID kRedisplayEvent =
-    Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-  ModelAPI_EventCreator::get()->sendUpdated(theResult, kRedisplayEvent);
+  }
 }
 
 //**************************************************************
@@ -2373,11 +2452,9 @@ void setTransparency(ResultPtr theResult, double theTransparency)
     return;
 
   AttributeDoublePtr anAttribute = theResult->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
-  if (anAttribute.get() != NULL)
+  if (anAttribute.get() != NULL) {
     anAttribute->setValue(theTransparency);
-  static const Events_ID kRedisplayEvent =
-    Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-  ModelAPI_EventCreator::get()->sendUpdated(theResult, kRedisplayEvent);
+  }
 }
 
 //**************************************************************
@@ -2390,7 +2467,8 @@ void setTransparency(double theTransparency, const QObjectPtrList& theObjects)
       if (aBodyResult.get() != NULL) { // change property for all sub-solids
         std::list<ResultPtr> allRes;
         ModelAPI_Tools::allSubs(aBodyResult, allRes);
-        for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
+        std::list<ResultPtr>::iterator aRes;
+        for(aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
           setTransparency(*aRes, theTransparency);
         }
       }
@@ -2399,6 +2477,34 @@ void setTransparency(double theTransparency, const QObjectPtrList& theObjects)
   }
 }
 
+//**************************************************************
+double getDefaultDeflection(const ObjectPtr& theObject)
+{
+  double aDeflection = -1;
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (aResult.get()) {
+    bool isConstruction = false;
+
+    std::string aResultGroup = aResult->groupName();
+    if (aResultGroup == ModelAPI_ResultConstruction::group())
+      isConstruction = true;
+    else if (aResultGroup == ModelAPI_ResultBody::group()) {
+      GeomShapePtr aGeomShape = aResult->shape();
+      if (aGeomShape.get()) {
+        // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
+        // correction of deviation for them should not influence to the application performance
+        GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE);
+        isConstruction = !anExp.more();
+      }
+    }
+    if (isConstruction)
+      aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
+    else
+      aDeflection = Config_PropManager::real("Visualization", "body_deflection");
+  }
+  return aDeflection;
+}
+
 //**************************************************************
 void XGUI_Workshop::changeDeflection(const QObjectPtrList& theObjects)
 {
@@ -2409,7 +2515,9 @@ void XGUI_Workshop::changeDeflection(const QObjectPtrList& theObjects)
   foreach(ObjectPtr anObject, theObjects) {
     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
     if (aResult.get()) {
-      aDeflection = XGUI_CustomPrs::getResultDeflection(aResult);
+      aDeflection = ModelAPI_Tools::getDeflection(aResult);
+      if (aDeflection < 0)
+        aDeflection = getDefaultDeflection(aResult);
     }
     else {
       // TODO: remove the obtaining a property from the AIS object
@@ -2458,10 +2566,17 @@ void XGUI_Workshop::changeDeflection(const QObjectPtrList& theObjects)
       setDeflection(aResult, aDeflection);
     }
   }
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
   aMgr->finishOperation();
   updateCommandStatus();
 }
 
+//**************************************************************
+double getDefaultTransparency(const ResultPtr& theResult)
+{
+  return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
+}
+
 //**************************************************************
 void XGUI_Workshop::changeTransparency(const QObjectPtrList& theObjects)
 {
@@ -2472,7 +2587,9 @@ void XGUI_Workshop::changeTransparency(const QObjectPtrList& theObjects)
   foreach(ObjectPtr anObject, theObjects) {
     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
     if (aResult.get()) {
-      aCurrentValue = XGUI_CustomPrs::getResultTransparency(aResult);
+      aCurrentValue = ModelAPI_Tools::getTransparency(aResult);
+      if (aCurrentValue < 0)
+        aCurrentValue = getDefaultTransparency(aResult);
     }
     if (aCurrentValue > 0)
       break;
@@ -2519,7 +2636,11 @@ void XGUI_Workshop::onTransparencyValueChanged()
 
   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
   setTransparency(aTransparencyWidget->getValue(), anObjects);
-  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+  static const Events_ID kRedisplayEvent =
+    Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  Events_Loop::loop()->flush(kRedisplayEvent);
+
+  myViewerProxy->update();
 }
 
 
@@ -2804,6 +2925,8 @@ void XGUI_Workshop::synchronizeGroupInViewer(const DocumentPtr& theDoc,
   int aSize = theDoc->numInternalFeatures();
   for (int i = 0; i < aSize; i++) {
     aFeature = theDoc->internalFeature(i);
+    if (!aFeature.get())
+      continue;
     const std::list<ResultPtr>& aResults = aFeature->results();
     std::list<ResultPtr>::const_iterator aIt;
     aFeature->setDisplayed(false);
index 8f524f3cb5d92244bc573f7356c612d00d989f52..37ae6a8a2be07ea5265ba5463d38f4670c141f45 100644 (file)
@@ -186,7 +186,7 @@ Q_OBJECT
   bool canMoveFeature();
 
   /// Move selected features to be after the current feature
-  void moveObjects();
+  void moveObjects(const bool theSplit);
 
   /// Returns true if the object can be shaded. If the object is a compsolid result, the method
   /// checks subobjects of the result
@@ -316,6 +316,9 @@ Q_OBJECT
   /// A constant string used for "Move to end" command definition
   /// It is used for specific processing of Undo/Redo for this command.
   static QString MOVE_TO_END_COMMAND;
+  /// A constant string used for "Move to end and split" command definition
+  /// It is used for specific processing of Undo/Redo for this command.
+  static QString MOVE_TO_END_SPLIT_COMMAND;
 
   /// Closes all in the current session and load the directory
   /// \param theDirectory a path to directory
@@ -395,6 +398,12 @@ signals:
   /// Create a new document
   void onNew();
 
+  /// Import part structure from a file
+  void onImportPart();
+
+  /// Export features to a file
+  void onExportPart();
+
 #ifndef HAVE_SALOME
   /// Exit application
   void onExit();
index e420a5aec4814eb9666bf2eb4eb07e7780967bf5..6ec62aba90d20ed11338b7a168406cf857fea6d3 100644 (file)
@@ -103,6 +103,7 @@ void XGUI_WorkshopListener::initializeEventListening()
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES));
   aLoop->registerListener(this, Events_LongOp::eventID());
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_PLUGIN_LOADED));
 
@@ -149,8 +150,32 @@ void XGUI_WorkshopListener::processEvent(const std::shared_ptr<Events_Message>&
   // Redisplay feature
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
-        std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+      std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
     onFeatureRedisplayMsg(aUpdMsg);
+  }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_VISUAL_ATTRIBUTES)) {
+    std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
+      std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    std::set<ObjectPtr> aObjList = aUpdMsg->objects();
+    std::set<ObjectPtr>::const_iterator aIt;
+    std::list<ResultPtr>::const_iterator aResIt;
+    XGUI_Displayer* aDisplayer = workshop()->displayer();
+    AISObjectPtr aAIS;
+    for (aIt = aObjList.begin(); aIt != aObjList.end(); ++aIt) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aIt);
+      if (aFeature) {
+        aAIS = aDisplayer->getAISObject(aFeature);
+        if (aAIS.get())
+          workshop()->module()->customizePresentation(aFeature, aAIS);
+
+        std::list<ResultPtr> aResults = aFeature->results();
+        for (aResIt = aResults.begin(); aResIt != aResults.end(); ++aResIt) {
+          aAIS = aDisplayer->getAISObject(*aResIt);
+          if (aAIS.get())
+            workshop()->module()->customizePresentation(*aResIt, aAIS);
+        }
+      }
+    }
   } else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_EMPTY_AIS_PRESENTATION)) {
     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
@@ -354,7 +379,7 @@ void XGUI_WorkshopListener::
   //if (aHiddenObjects.size() > 0)
   //  myWorkshop->module()->processHiddenObject(aHiddenObjects);
 
-  bool isCustomized = customizeCurrentObject(anObjects, aRedisplayed);
+  bool isCustomized = customizeFeature(anObjects, aRedisplayed);
   if (aRedisplayed || isCustomized) {
     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_EMPTY_AIS_PRESENTATION));
 
@@ -423,7 +448,7 @@ void XGUI_WorkshopListener::
     }
   }
 
-  bool isCustomized = customizeCurrentObject(anObjects, aDisplayed);
+  bool isCustomized = customizeFeature(anObjects, aDisplayed);
 
   //if (myObjectBrowser)
   //  myObjectBrowser->processEvent(theMsg);
@@ -501,7 +526,7 @@ bool XGUI_WorkshopListener::displayObject(ObjectPtr theObj)
   return aDisplayer->display(theObj, false);
 }
 
-bool XGUI_WorkshopListener::customizeCurrentObject(const std::set<ObjectPtr>& theObjects,
+bool XGUI_WorkshopListener::customizeFeature(const std::set<ObjectPtr>& theObjects,
                                                    bool theForceRedisplay)
 {
   XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr();
@@ -521,11 +546,11 @@ bool XGUI_WorkshopListener::customizeCurrentObject(const std::set<ObjectPtr>& th
     // the feature is hidden, but arguments of the feature are modified
     // e.g. extrusion is hidden(h=0) but sketch is chosen
     if (theForceRedisplay || theObjects.find(aCurrentFeature) != theObjects.end()) {
-      aCustomized = myWorkshop->module()->customizeObject(aCurrentFeature,
+      aCustomized = myWorkshop->module()->customizeFeature(aCurrentFeature,
                                  ModuleBase_IModule::CustomizeArguments, false) || aCustomized;
-      aCustomized = myWorkshop->module()->customizeObject(aCurrentFeature,
+      aCustomized = myWorkshop->module()->customizeFeature(aCurrentFeature,
                                    ModuleBase_IModule::CustomizeResults, false) || aCustomized;
-      aCustomized = myWorkshop->module()->customizeObject(aCurrentFeature,
+      aCustomized = myWorkshop->module()->customizeFeature(aCurrentFeature,
                         ModuleBase_IModule::CustomizeHighlightedObjects, false) || aCustomized;
     }
   }
index f6ab5a6ef8f312622b9c918756cb2551cf59aa32..e2d548c461b34c71b38f90d7d37cd05044f7dc11 100644 (file)
@@ -97,7 +97,7 @@ protected:
   ///                   if forced redisplay is false
   /// \param theForceRedisplay a flag to customize object even always
   /// \return true if the object is modified
-  bool customizeCurrentObject(const std::set<ObjectPtr>& theObjects, bool theForceRedisplay);
+  bool customizeFeature(const std::set<ObjectPtr>& theObjects, bool theForceRedisplay);
 
   /// Returns the workshop
   XGUI_Workshop* workshop() const;
diff --git a/src/XGUI/XGUI_msg_fr.ts b/src/XGUI/XGUI_msg_fr.ts
new file mode 100644 (file)
index 0000000..ebe3b88
--- /dev/null
@@ -0,0 +1,665 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+    <name>QObject</name>
+    <message>
+        <source>Warning</source>
+        <translation>Attention</translation>
+    </message>
+    <message>
+        <source>Name %2 already exists in %1.</source>
+        <translation>Le nom %2 existe déjà dans %1.</translation>
+    </message>
+    <message>
+        <source>Move to the end</source>
+        <translation>Aller à la fin</translation>
+    </message>
+    <message>
+        <source>Move to the end and split</source>
+        <translation>Aller à la fin et diviser</translation>
+    </message>
+    <message>
+        <source>SHAPER files (*.shaper *.cadbld)</source>
+        <translation>Fichiers SHAPER (*.shaper *.cadbld)</translation>
+    </message>
+    <message>
+        <source>SHAPER files (*.shaper)</source>
+        <translation>Fichiers SHAPER (*.shaper)</translation>
+    </message>
+    <message>
+        <source>CAD Builder files (*.cadbld);;All files (*.*)</source>
+        <translation>Fichiers CAD Builder (*.cadbld);;Tous les fichiers (*. *)</translation>
+    </message>
+    <message>
+        <source>CAD Builder files (*.cadbld)</source>
+        <translation>Fichiers CAD Builder (*.cadbld)</translation>
+    </message>
+    <message>
+        <source>Abort operation</source>
+        <translation>Abandonner l&apos;opération</translation>
+    </message>
+    <message>
+        <source>Validate operation</source>
+        <translation>Valider l&apos;opération</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ActionsMgr</name>
+    <message>
+        <source>Shortcut %1 is already defined. Ignore.</source>
+        <translation>Le raccourci %1 est déjà défini. Ignorer.</translation>
+    </message>
+    <message>
+        <source>Apply</source>
+        <translation>Appliquer</translation>
+    </message>
+    <message>
+        <source>Apply and continue</source>
+        <translation>Appliquer et continuer</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>Help</source>
+        <translation>Aide</translation>
+    </message>
+    <message>
+        <source>See preview</source>
+        <translation>Voir l&apos;aperçu</translation>
+    </message>
+    <message>
+        <source>Compute preview</source>
+        <translation>Calculer l&apos;aperçu avant impression</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ColorDialog</name>
+    <message>
+        <source>Color</source>
+        <translation>Couleur</translation>
+    </message>
+    <message>
+        <source>Random</source>
+        <translation>Aléatoire</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ContextMenuMgr</name>
+    <message>
+        <source>Delete</source>
+        <translation>Effacer</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Renommer</translation>
+    </message>
+    <message>
+        <source>Clean history</source>
+        <translation>Vider l’historique</translation>
+    </message>
+    <message>
+        <source>Color...</source>
+        <translation>Couleur...</translation>
+    </message>
+    <message>
+        <source>Deflection...</source>
+        <translation>Déviation...</translation>
+    </message>
+    <message>
+        <source>Transparency...</source>
+        <translation>Transparence...</translation>
+    </message>
+    <message>
+        <source>Show</source>
+        <translation>Afficher</translation>
+    </message>
+    <message>
+        <source>Show only</source>
+        <translation>Montrer seulement</translation>
+    </message>
+    <message>
+        <source>Hide</source>
+        <translation>Cacher</translation>
+    </message>
+    <message>
+        <source>Hide all</source>
+        <translation>Cacher tout</translation>
+    </message>
+    <message>
+        <source>Shading</source>
+        <translation>Ombrage</translation>
+    </message>
+    <message>
+        <source>Wireframe</source>
+        <translation>Fil de fer</translation>
+    </message>
+    <message>
+        <source>Vertices</source>
+        <translation>Sommets</translation>
+    </message>
+    <message>
+        <source>Edges</source>
+        <translation>Arêtes</translation>
+    </message>
+    <message>
+        <source>Faces</source>
+        <translation>Faces</translation>
+    </message>
+    <message>
+        <source>Results</source>
+        <translation>Résultats</translation>
+    </message>
+    <message>
+        <source>Select results</source>
+        <translation>Sélectionnez les résultats</translation>
+    </message>
+    <message>
+        <source>Select parent feature</source>
+        <translation>Sélectionner une entité parente</translation>
+    </message>
+    <message>
+        <source>TInspector</source>
+        <translation>TInspector</translation>
+    </message>
+    <message>
+        <source>Insert a folder before</source>
+        <translation>Insérer un dossier avant</translation>
+    </message>
+    <message>
+        <source>Move into the previous folder</source>
+        <translation>Déplacer dans le dossier précédent</translation>
+    </message>
+    <message>
+        <source>Move into the next folder</source>
+        <translation>Se déplacer dans le dossier suivant</translation>
+    </message>
+    <message>
+        <source>Move out before the folder</source>
+        <translation>Sortir avant le dossier</translation>
+    </message>
+    <message>
+        <source>Move out after the folder</source>
+        <translation>Sortir après le dossier</translation>
+    </message>
+    <message>
+        <source>Set view by inverted normal to face</source>
+        <translation>Définir la vue par normale inversée à la face</translation>
+    </message>
+    <message>
+        <source>Set view by normal to face</source>
+        <translation>Définir la vue par la normale à la face</translation>
+    </message>
+    <message>
+        <source>Selection mode</source>
+        <translation>Mode de sélection</translation>
+    </message>
+    <message>
+        <source>Windows</source>
+        <translation>Fenêtres</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_DataTree</name>
+    <message>
+        <source>History change</source>
+        <translation>Changement l&apos;historique</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_DeflectionDialog</name>
+    <message>
+        <source>Deflection</source>
+        <translation>Déviation</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ErrorDialog</name>
+    <message>
+        <source>Application errors</source>
+        <translation>Erreurs d&apos;application</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ErrorMgr</name>
+    <message>
+        <source>Errors:</source>
+        <translation>Erreurs:</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_FacesPanel</name>
+    <message>
+        <source>Hide Faces</source>
+        <translation>Masquer les faces</translation>
+    </message>
+    <message>
+        <source>Transparent</source>
+        <translation>Transparent</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_InspectionPanel</name>
+    <message>
+        <source>Inspection Panel</source>
+        <translation>Panneau d&apos;inspection</translation>
+    </message>
+    <message>
+        <source>Object</source>
+        <translation>Objet</translation>
+    </message>
+    <message>
+        <source>Sub-shapes</source>
+        <translation>Sous-formes</translation>
+    </message>
+    <message>
+        <source>Number</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>SHAPE</source>
+        <translation>FORME</translation>
+    </message>
+    <message>
+        <source>COMPOUND</source>
+        <translation>ASSEMBLAGE</translation>
+    </message>
+    <message>
+        <source>COMPSOLID</source>
+        <translation>COMPSOLIDE</translation>
+    </message>
+    <message>
+        <source>SOLID</source>
+        <translation>SOLIDE</translation>
+    </message>
+    <message>
+        <source>SHELL</source>
+        <translation>COQUE</translation>
+    </message>
+    <message>
+        <source>FACE</source>
+        <translation>FACE</translation>
+    </message>
+    <message>
+        <source>WIRE</source>
+        <translation>CONTOUR</translation>
+    </message>
+    <message>
+        <source>EDGE</source>
+        <translation>BORD</translation>
+    </message>
+    <message>
+        <source>VERTEX</source>
+        <translation>SOMMET</translation>
+    </message>
+    <message>
+        <source>Type:</source>
+        <translation>Type:</translation>
+    </message>
+    <message>
+        <source>Vertex</source>
+        <translation>Sommet</translation>
+    </message>
+    <message>
+        <source>Coordinates</source>
+        <translation>Coordonnées</translation>
+    </message>
+    <message>
+        <source>Degenerated</source>
+        <translation>Dégénéré</translation>
+    </message>
+    <message>
+        <source>Line segment</source>
+        <translation>Segment de ligne</translation>
+    </message>
+    <message>
+        <source>Center</source>
+        <translation>Centre</translation>
+    </message>
+    <message>
+        <source>Normal</source>
+        <translation>Normale</translation>
+    </message>
+    <message>
+        <source>Dimensions</source>
+        <translation>Dimensions</translation>
+    </message>
+    <message>
+        <source>Radius</source>
+        <translation>Rayon</translation>
+    </message>
+    <message>
+        <source>Major radius</source>
+        <translation>Rayon majeur</translation>
+    </message>
+    <message>
+        <source>Minor radius</source>
+        <translation>Rayon mineur</translation>
+    </message>
+    <message>
+        <source>Edge</source>
+        <translation>Bord</translation>
+    </message>
+    <message>
+        <source>Start point</source>
+        <translation>Point de départ</translation>
+    </message>
+    <message>
+        <source>End point</source>
+        <translation>Point final</translation>
+    </message>
+    <message>
+        <source>Closed</source>
+        <translation>Fermé</translation>
+    </message>
+    <message>
+        <source>Polygon</source>
+        <translation>Polygone</translation>
+    </message>
+    <message>
+        <source>Point</source>
+        <translation>Point</translation>
+    </message>
+    <message>
+        <source>Wire</source>
+        <translation>Contour</translation>
+    </message>
+    <message>
+        <source>Rectangle</source>
+        <translation>Rectangle</translation>
+    </message>
+    <message>
+        <source>Corner</source>
+        <translation>Coin</translation>
+    </message>
+    <message>
+        <source>Width</source>
+        <translation>Largeur</translation>
+    </message>
+    <message>
+        <source>Height</source>
+        <translation>Hauteur</translation>
+    </message>
+    <message>
+        <source>Plane</source>
+        <translation>Plan</translation>
+    </message>
+    <message>
+        <source>Sphere</source>
+        <translation>Sphère</translation>
+    </message>
+    <message>
+        <source>Cylinder</source>
+        <translation>Cylindre</translation>
+    </message>
+    <message>
+        <source>Cone</source>
+        <translation>Cône</translation>
+    </message>
+    <message>
+        <source>Torus</source>
+        <translation>Tore</translation>
+    </message>
+    <message>
+        <source>Face</source>
+        <translation>Face</translation>
+    </message>
+    <message>
+        <source>Box</source>
+        <translation>Boîte</translation>
+    </message>
+    <message>
+        <source>Rotated Box</source>
+        <translation>Boîte tournée</translation>
+    </message>
+    <message>
+        <source>Shell</source>
+        <translation>Coque</translation>
+    </message>
+    <message>
+        <source>Solid</source>
+        <translation>Solide</translation>
+    </message>
+    <message>
+        <source>Bounding box</source>
+        <translation>Boîte englobante</translation>
+    </message>
+    <message>
+        <source>Minimal corner</source>
+        <translation>Coin minimal</translation>
+    </message>
+    <message>
+        <source>Maximal corner</source>
+        <translation>Coin maximal</translation>
+    </message>
+    <message>
+        <source>Origin</source>
+        <translation>Origine</translation>
+    </message>
+    <message>
+        <source>Position</source>
+        <translation>Position</translation>
+    </message>
+    <message>
+        <source>Axis</source>
+        <translation>Axe</translation>
+    </message>
+    <message>
+        <source>Radius 1</source>
+        <translation>Rayon 1</translation>
+    </message>
+    <message>
+        <source>Radius 2</source>
+        <translation>Rayon 2</translation>
+    </message>
+    <message>
+        <source>Depth</source>
+        <translation>Profondeur</translation>
+    </message>
+    <message>
+        <source>Z axis</source>
+        <translation>Axe Z</translation>
+    </message>
+    <message>
+        <source>X axis</source>
+        <translation>Axe X</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ObjectsBrowser</name>
+    <message>
+        <source>Part set</source>
+        <translation>Ensemble</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_OperationMgr</name>
+    <message>
+        <source>All active operations will be aborted.</source>
+        <translation>Toutes les opérations actives seront annulées.</translation>
+    </message>
+    <message>
+        <source>Please validate all your active operations before saving.</source>
+        <translation>Veuillez valider toutes vos opérations actives avant de sauvegarder.</translation>
+    </message>
+    <message>
+        <source>%1 operation will be aborted.</source>
+        <translation>%1 opération sera abandonnée.</translation>
+    </message>
+    <message>
+        <source>Please validate your %1 before saving.</source>
+        <translation>Veuillez valider votre %1 avant de sauvegarder.</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_PropertyPanel</name>
+    <message>
+        <source>Property Panel</source>
+        <translation>Panneau de propriété</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_TransparencyWidget</name>
+    <message>
+        <source>Opaque</source>
+        <translation>Opaque</translation>
+    </message>
+    <message>
+        <source>Transparent</source>
+        <translation>Transparent</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_Workshop</name>
+    <message>
+        <source>Undo</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>Undo last command</source>
+        <translation>Annuler la dernière commande</translation>
+    </message>
+    <message>
+        <source>INF_DESK_TOOLBAR_STANDARD</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Redo</source>
+        <translation>Refaire</translation>
+    </message>
+    <message>
+        <source>Redo last command</source>
+        <translation>Refaire la dernière commande</translation>
+    </message>
+    <message>
+        <source>Export native...</source>
+        <translation>Exporter natif...</translation>
+    </message>
+    <message>
+        <source>Export the current document into a native file</source>
+        <translation>Exporter le document actuel dans un fichier natif</translation>
+    </message>
+    <message>
+        <source>Import native...</source>
+        <translation>Importer natif...</translation>
+    </message>
+    <message>
+        <source>Import native file</source>
+        <translation>Importer un fichier natif</translation>
+    </message>
+    <message>
+        <source>Save</source>
+        <translation>Enregistrer</translation>
+    </message>
+    <message>
+        <source>Save the document</source>
+        <translation>Enregistrer le document</translation>
+    </message>
+    <message>
+        <source>Save as...</source>
+        <translation>Enregistrer sous...</translation>
+    </message>
+    <message>
+        <source>Save the document into a file</source>
+        <translation>Enregistrer le document dans un fichier</translation>
+    </message>
+    <message>
+        <source>Open...</source>
+        <translation>Ouvrir...</translation>
+    </message>
+    <message>
+        <source>Open a new document</source>
+        <translation>Ouvrir un nouveau document</translation>
+    </message>
+    <message>
+        <source>Auto rebuild</source>
+        <translation>Reconstruction automatique</translation>
+    </message>
+    <message>
+        <source>Blocks immediate apply of modifications</source>
+        <translation>Bloque l&apos;application immédiate des modifications</translation>
+    </message>
+    <message>
+        <source>Preferences</source>
+        <translation>Préférences</translation>
+    </message>
+    <message>
+        <source>Edit preferences</source>
+        <translation>Modifier les préférences</translation>
+    </message>
+    <message>
+        <source>Exit</source>
+        <translation>Quitter</translation>
+    </message>
+    <message>
+        <source>Exit application</source>
+        <translation>Quitter l’application</translation>
+    </message>
+    <message>
+        <source>Save current file</source>
+        <translation>Enregistrer le fichier courant</translation>
+    </message>
+    <message>
+        <source>The document is modified, save before opening another?</source>
+        <translation>Le document est modifié, sauvegarder avant d&apos;en ouvrir un autre ?</translation>
+    </message>
+    <message>
+        <source>Open file</source>
+        <translation>Fichier ouvert</translation>
+    </message>
+    <message>
+        <source>Select name to save file...</source>
+        <translation>Sélectionnez le nom pour enregistrer le fichier...</translation>
+    </message>
+    <message>
+        <source>Show object</source>
+        <translation>Montrer l&apos;objet</translation>
+    </message>
+    <message>
+        <source>&apos;%1&apos;
+ are hidden by %2:
+Remove objects from the panel to be displayed?</source>
+        <translation>&apos;%1&apos;
+ est caché par %2 :
+Supprimer des objets du panneau à afficher ?</translation>
+    </message>
+    <message>
+        <source>Warning</source>
+        <translation>Attention</translation>
+    </message>
+    <message>
+        <source>Unable to open the file.</source>
+        <translation>Impossible d&apos;ouvrir le fichier.</translation>
+    </message>
+    <message>
+        <source>The document is modified, save before exit?</source>
+        <translation>Le document est modifié, enregistrer avant de quitter ?</translation>
+    </message>
+    <message>
+        <source>Information about module &quot;%1&quot; doesn&apos;t exist.</source>
+        <translation>Les informations sur le module &quot;%1&quot; n&apos;existent pas.</translation>
+    </message>
+    <message>
+        <source>Object browser</source>
+        <translation>Navigateur d&apos;objet</translation>
+    </message>
+    <message>
+        <source>All features are relevant, there is nothing to be deleted</source>
+        <translation>Toutes les fonctionnalités sont pertinentes, il n&apos;y a rien à supprimer</translation>
+    </message>
+    <message>
+        <source>Transparency</source>
+        <translation>Transparence</translation>
+    </message>
+    <message>
+        <source>Find results</source>
+        <translation>Trouver des résultats</translation>
+    </message>
+    <message>
+        <source>Results not found</source>
+        <translation>Résultats non trouvés</translation>
+    </message>
+</context>
+</TS>
index acb22325c73f3f8beae5b76342a4f898c265da88..9b958d9e758cde5347d49338cc273f11ccf7af60 100644 (file)
@@ -90,5 +90,7 @@
      <file>pictures/color.png</file>
      <file>pictures/normal-view-inversed.png</file>
      <file>pictures/normal-view.png</file>
+     <file>pictures/move_to_end.png</file>
+     <file>pictures/move_to_end_split.png</file>
  </qresource>
  </RCC>
diff --git a/src/XGUI/pictures/move_to_end.png b/src/XGUI/pictures/move_to_end.png
new file mode 100644 (file)
index 0000000..a80ce7f
Binary files /dev/null and b/src/XGUI/pictures/move_to_end.png differ
diff --git a/src/XGUI/pictures/move_to_end_split.png b/src/XGUI/pictures/move_to_end_split.png
new file mode 100644 (file)
index 0000000..bcc017d
Binary files /dev/null and b/src/XGUI/pictures/move_to_end_split.png differ
index 875d48f4313f8b5fbda096ee7689d698b145a765..6032634e2e9f883b013aa2ae7286ee555df53bd5 100644 (file)
@@ -23,6 +23,6 @@ if __name__ == "__main__":
   model.testNbSubResults(aPartFeature, [0])
   model.testNbSubShapes(aPartFeature, GeomAPI_Shape.SOLID, [32])
   model.testNbSubShapes(aPartFeature, GeomAPI_Shape.FACE, [875])
-  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.EDGE, [4665])
-  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.VERTEX, [9330])
-  model.testResultsVolumes(aPartFeature, [145241798.705457538])
+  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.EDGE, [4659])
+  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.VERTEX, [9318])
+  model.testResultsVolumes(aPartFeature, [145241798.70546785])
diff --git a/test.sh b/test.sh
index 92c0b48e9651a0b4d16e12a6f178499fbe08164a..7faf456b873ec3f33bcbb5ba2aafa9d7ed94797d 100755 (executable)
--- a/test.sh
+++ b/test.sh
@@ -7,6 +7,13 @@ cd ${BUILD_DIR}
 
 export DISPLAY="localhost:0.0"
 
+# check for __init__.py in the SHAPER's Python scripts directory
+# for correct parsing PYTHONPATH and use the actual version of SHAPER
+# instead of distributed with SALOME
+if [[ ! -f ${SHAPER_PYTHON_SCRIPTS_DIR}/salome/__init__.py ]]; then
+  touch ${SHAPER_PYTHON_SCRIPTS_DIR}/salome/__init__.py
+fi
+
 if [[ $# > 0 ]]; then
   ctest --no-compress-output -T Test "$@" -R $1
 else