Salome HOME
Merge remote-tracking branch 'origin/CEA_2019'
authorvsv <vsv@opencascade.com>
Mon, 7 Oct 2019 12:30:45 +0000 (15:30 +0300)
committervsv <vsv@opencascade.com>
Mon, 7 Oct 2019 12:30:45 +0000 (15:30 +0300)
# Conflicts:
# src/GeomAlgoAPI/CMakeLists.txt

356 files changed:
CMakeLists.txt
env.sh
lcov_reports.sh
src/BuildPlugin/BuildPlugin_Validators.cpp
src/BuildPlugin/BuildPlugin_msg_en.ts
src/BuildPlugin/BuildPlugin_msg_fr.ts [new file with mode: 0644]
src/BuildPlugin/CMakeLists.txt
src/BuildPlugin/polyline_widget.xml
src/CollectionAPI/CollectionAPI_Group.cpp
src/CollectionAPI/CollectionAPI_Group.h
src/CollectionPlugin/CMakeLists.txt
src/CollectionPlugin/CollectionPlugin_Group.cpp
src/CollectionPlugin/CollectionPlugin_GroupSubstraction.cpp
src/CollectionPlugin/CollectionPlugin_msg_en.ts
src/CollectionPlugin/CollectionPlugin_msg_fr.ts [new file with mode: 0644]
src/CollectionPlugin/Test/Test3031.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove21.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove22.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove23.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove24.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove25.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupSubstraction2.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupWholeResult1.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupWholeResult2.py [new file with mode: 0644]
src/CollectionPlugin/group_intersection_widget.xml
src/CollectionPlugin/group_substraction_widget.xml
src/ConnectorAPI/Test/TestExportToGEOMPartSet.py
src/ConnectorAPI/Test/TestExportToGEOMWholeFeature.py [new file with mode: 0644]
src/ConnectorAPI/Test/TestExportToGEOMWholeResult.py [new file with mode: 0644]
src/ConnectorAPI/Test/tests.set
src/ConnectorPlugin/CMakeLists.txt
src/ConnectorPlugin/ConnectorPlugin_msg_fr.ts [new file with mode: 0644]
src/ConnectorPlugin/plugin-Connector.xml
src/ConstructionPlugin/CMakeLists.txt
src/ConstructionPlugin/ConstructionPlugin_Plugin.cpp
src/ConstructionPlugin/ConstructionPlugin_Validators.cpp
src/ConstructionPlugin/ConstructionPlugin_msg_en.ts
src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts [new file with mode: 0644]
src/ExchangePlugin/CMakeLists.txt
src/ExchangePlugin/ExchangePlugin_ExportFeature.cpp
src/ExchangePlugin/ExchangePlugin_msg_en.ts
src/ExchangePlugin/ExchangePlugin_msg_fr.ts [new file with mode: 0644]
src/ExchangePlugin/plugin-Exchange.xml
src/FeaturesAPI/FeaturesAPI_Measurement.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Measurement.h
src/FeaturesPlugin/FeaturesPlugin_Partition.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/FeaturesPlugin_msg_en.ts
src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts [new file with mode: 0644]
src/FeaturesPlugin/Test/Test3014.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusionCut_ByFaces.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces01.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces02.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces03.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces04.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces05.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces06.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces07.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces08.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces09.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces10.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces11.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces12.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces13.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces14.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces15.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces16.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces17.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces18.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces19.py
src/FeaturesPlugin/extrusion_widget.xml
src/FeaturesPlugin/extrusioncut_widget.xml
src/FeaturesPlugin/extrusionfuse_widget.xml
src/FeaturesPlugin/intersection_widget.xml
src/FeaturesPlugin/measurement_widget.xml
src/FeaturesPlugin/plugin-Features.xml
src/FeaturesPlugin/revolution_widget.xml
src/FeaturesPlugin/revolutioncut_widget.xml
src/FeaturesPlugin/revolutionfuse_widget.xml
src/GeomAPI/GeomAPI.i
src/GeomAPI/GeomAPI_AISObject.cpp
src/GeomAPI/GeomAPI_Circ.cpp
src/GeomAPI/GeomAPI_Circ2d.cpp
src/GeomAPI/GeomAPI_Circ2d.h
src/GeomAPI/GeomAPI_Curve.cpp
src/GeomAPI/GeomAPI_Curve.h
src/GeomAPI/GeomAPI_Dir2d.h
src/GeomAPI/GeomAPI_Ellipse.cpp
src/GeomAPI/GeomAPI_Ellipse.h
src/GeomAPI/GeomAPI_Ellipse2d.cpp
src/GeomAPI/GeomAPI_Ellipse2d.h
src/GeomAPI/GeomAPI_Face.cpp
src/GeomAPI/GeomAPI_Lin2d.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h
src/GeomAlgoAPI/GeomAlgoAPI_Intersection.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Projection.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_XAOExport.cpp
src/GeomValidators/GeomValidators_ZeroOffset.cpp
src/Model/Model_AttributeIntArray.cpp
src/Model/Model_AttributeSelection.cpp
src/Model/Model_AttributeSelection.h
src/Model/Model_AttributeSelectionList.cpp
src/Model/Model_AttributeSelectionList.h
src/Model/Model_AttributeString.cpp
src/Model/Model_AttributeString.h
src/Model/Model_Data.cpp
src/Model/Model_Document.cpp
src/Model/Model_FeatureValidator.cpp
src/Model/Model_ResultGroup.cpp
src/Model/Model_ResultPart.cpp
src/Model/Model_Update.cpp
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_AttributeSelection.h
src/ModelAPI/ModelAPI_AttributeSelectionList.cpp
src/ModelAPI/ModelAPI_AttributeSelectionList.h
src/ModelAPI/ModelAPI_AttributeString.h
src/ModelAPI/Test/Test3020.py [new file with mode: 0644]
src/ModelAPI/Test/TestSelectionCircleCenter.py [new file with mode: 0644]
src/ModelAPI/Test/TestSelectionInPart.py [new file with mode: 0644]
src/ModelAPI/Test/TestSelectorShell.py
src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp
src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp
src/ModelHighAPI/ModelHighAPI.i
src/ModelHighAPI/ModelHighAPI_Dumper.cpp
src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp
src/ModelHighAPI/ModelHighAPI_Macro.h
src/ModelHighAPI/ModelHighAPI_RefAttr.cpp
src/ModelHighAPI/ModelHighAPI_Tools.cpp
src/ModuleBase/CMakeLists.txt
src/ModuleBase/ModuleBase_Dialog.cpp
src/ModuleBase/ModuleBase_IViewer.h
src/ModuleBase/ModuleBase_ModelWidget.cpp
src/ModuleBase/ModuleBase_Tools.cpp
src/ModuleBase/ModuleBase_WidgetExprEditor.cpp
src/ModuleBase/ModuleBase_WidgetFactory.cpp
src/ModuleBase/ModuleBase_WidgetLabel.cpp
src/ModuleBase/ModuleBase_WidgetLabelValue.cpp
src/ModuleBase/ModuleBase_WidgetLineEdit.cpp
src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp
src/ModuleBase/ModuleBase_WidgetPointInput.cpp
src/ModuleBase/ModuleBase_WidgetRadiobox.cpp
src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp
src/ModuleBase/ModuleBase_WidgetSelector.cpp
src/ModuleBase/ModuleBase_WidgetSelector.h
src/ModuleBase/ModuleBase_WidgetShapeSelector.cpp
src/ModuleBase/ModuleBase_WidgetSwitch.cpp
src/ModuleBase/ModuleBase_WidgetToolbox.cpp
src/ModuleBase/ModuleBase_msg_fr.ts [new file with mode: 0644]
src/ParametersPlugin/CMakeLists.txt
src/ParametersPlugin/ParametersPlugin_EvalListener.cpp
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_ExternalPointsMgr.cpp
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_OperationPrs.cpp
src/PartSet/PartSet_OverconstraintListener.cpp
src/PartSet/PartSet_PreviewPlanes.cpp
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherMgr.h
src/PartSet/PartSet_SketcherReentrantMgr.cpp
src/PartSet/PartSet_SketcherReentrantMgr.h
src/PartSet/PartSet_Validators.cpp
src/PartSet/PartSet_WidgetPoint2d.cpp
src/PartSet/PartSet_WidgetSketchCreator.cpp
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/sketcher/tools.py
src/SHAPERGUI/CMakeLists.txt
src/SHAPERGUI/SHAPERGUI_SalomeViewer.cpp
src/SHAPERGUI/SHAPERGUI_SalomeViewer.h
src/SHAPERGUI/SHAPERGUI_msg_fr.ts [new file with mode: 0644]
src/SHAPERGUI/resources/LightApp.xml.in
src/SketchAPI/CMakeLists.txt
src/SketchAPI/SketchAPI.i
src/SketchAPI/SketchAPI_Ellipse.cpp [new file with mode: 0644]
src/SketchAPI/SketchAPI_Ellipse.h [new file with mode: 0644]
src/SketchAPI/SketchAPI_EllipticArc.cpp [new file with mode: 0644]
src/SketchAPI/SketchAPI_EllipticArc.h [new file with mode: 0644]
src/SketchAPI/SketchAPI_MacroArc.cpp
src/SketchAPI/SketchAPI_MacroArc.h
src/SketchAPI/SketchAPI_MacroEllipse.cpp [new file with mode: 0644]
src/SketchAPI/SketchAPI_MacroEllipse.h [new file with mode: 0644]
src/SketchAPI/SketchAPI_MacroEllipticArc.cpp [new file with mode: 0644]
src/SketchAPI/SketchAPI_MacroEllipticArc.h [new file with mode: 0644]
src/SketchAPI/SketchAPI_Projection.cpp
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchAPI/SketchAPI_SketchEntity.cpp
src/SketchAPI/SketchAPI_swig.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Arc.cpp
src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Ellipse.cpp
src/SketchPlugin/SketchPlugin_Ellipse.h
src/SketchPlugin/SketchPlugin_EllipticArc.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_EllipticArc.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Line.cpp
src/SketchPlugin/SketchPlugin_Line.h
src/SketchPlugin/SketchPlugin_MacroArc.cpp
src/SketchPlugin/SketchPlugin_MacroArc.h
src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
src/SketchPlugin/SketchPlugin_MacroEllipse.h
src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroEllipticArc.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Point.cpp
src/SketchPlugin/SketchPlugin_Point.h
src/SketchPlugin/SketchPlugin_Projection.cpp
src/SketchPlugin/SketchPlugin_Projection.h
src/SketchPlugin/SketchPlugin_Sketch.cpp
src/SketchPlugin/SketchPlugin_Sketch.h
src/SketchPlugin/SketchPlugin_SketchEntity.h
src/SketchPlugin/SketchPlugin_Split.cpp
src/SketchPlugin/SketchPlugin_Split.h
src/SketchPlugin/SketchPlugin_Tools.cpp
src/SketchPlugin/SketchPlugin_Tools.h
src/SketchPlugin/SketchPlugin_Trim.cpp
src/SketchPlugin/SketchPlugin_Trim.h
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/SketchPlugin_msg_en.ts
src/SketchPlugin/SketchPlugin_msg_fr.ts [new file with mode: 0644]
src/SketchPlugin/Test/Test3019.py [new file with mode: 0644]
src/SketchPlugin/Test/TestChangeSketchPlane4.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintAngleEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintCoincidenceEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintCoincidenceEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintCollinearEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintDistanceEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintEqualEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintPerpendicularArcLine.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintPerpendicularEllipseLine.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintTangentEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintTangentEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateArcByTransversalLine.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateEllipseByCenterSemiaxisAndPassed.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateEllipseByExternal.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateEllipseByMajorAxisAndPassed.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateEllipticArcByExternal.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMoveEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestPresentation.py
src/SketchPlugin/Test/TestProjectionEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestProjectionEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestProjectionIntoResult.py
src/SketchPlugin/Test/TestRemoveEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestRemoveEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestSplitEllipse.py [new file with mode: 0644]
src/SketchPlugin/Test/TestTrimEllipse.py [new file with mode: 0644]
src/SketchPlugin/doc/SketchPlugin.rst
src/SketchPlugin/doc/TUI_ellipseFeature.rst [new file with mode: 0644]
src/SketchPlugin/doc/TUI_ellipticArcFeature.rst [new file with mode: 0644]
src/SketchPlugin/doc/arcEllipseFeature.rst [new file with mode: 0644]
src/SketchPlugin/doc/arcFeature.rst
src/SketchPlugin/doc/ellipseFeature.rst
src/SketchPlugin/doc/examples/arc.py
src/SketchPlugin/doc/examples/ellipse.py [new file with mode: 0644]
src/SketchPlugin/doc/examples/elliptic_arc.py [new file with mode: 0644]
src/SketchPlugin/doc/images/Arc_panel_3pt.png
src/SketchPlugin/doc/images/Arc_panel_base.png
src/SketchPlugin/doc/images/Arc_panel_perp.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Arc_panel_tang.png
src/SketchPlugin/doc/images/Arc_res.png
src/SketchPlugin/doc/images/Perpendicular_panel.png
src/SketchPlugin/doc/images/arc_perp_32x32.png [new file with mode: 0644]
src/SketchPlugin/doc/images/ellipse.png [new file with mode: 0644]
src/SketchPlugin/doc/images/ellipse_axes_32x32.png [new file with mode: 0644]
src/SketchPlugin/doc/images/ellipse_cent_rad_32x32.png [new file with mode: 0644]
src/SketchPlugin/doc/images/ellipse_panel_3pt.png [new file with mode: 0644]
src/SketchPlugin/doc/images/ellipse_panel_pt_rad.png [new file with mode: 0644]
src/SketchPlugin/doc/images/ellipse_result.png [new file with mode: 0644]
src/SketchPlugin/doc/images/elliptic_arc.png [new file with mode: 0644]
src/SketchPlugin/doc/images/elliptic_arc_panel.png [new file with mode: 0644]
src/SketchPlugin/doc/images/elliptic_arc_result.png [new file with mode: 0644]
src/SketchPlugin/doc/perpendicularFeature.rst
src/SketchPlugin/icons/arc_perp_32x32.png [new file with mode: 0644]
src/SketchPlugin/icons/ellipse.png
src/SketchPlugin/icons/ellipse_axes_32x32.png [new file with mode: 0644]
src/SketchPlugin/icons/ellipse_cent_rad_32x32.png [new file with mode: 0644]
src/SketchPlugin/icons/elliptic_arc.png [new file with mode: 0644]
src/SketchPlugin/icons/radius_major.png [new file with mode: 0644]
src/SketchPlugin/icons/radius_minor.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_BooleanWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_BooleanWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.cpp
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
src/SketchSolver/SketchSolver_ConstraintEqual.cpp
src/SketchSolver/SketchSolver_ConstraintEqual.h
src/SketchSolver/SketchSolver_ConstraintFixed.cpp
src/SketchSolver/SketchSolver_ConstraintMiddle.cpp
src/SketchSolver/SketchSolver_ConstraintMiddle.h
src/SketchSolver/SketchSolver_ConstraintMirror.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.h
src/SketchSolver/SketchSolver_ConstraintPerpendicular.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintPerpendicular.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintTangent.cpp
src/SketchSolver/SketchSolver_ConstraintTangent.h
src/SketchSolver/SketchSolver_Error.h
src/SketchSolver/SketchSolver_Group.cpp
src/SketchSolver/SketchSolver_Storage.h
src/SketchSolver/SketchSolver_msg_en.ts
src/SketchSolver/SketchSolver_msg_fr.ts [new file with mode: 0644]
src/SketcherPrs/SketcherPrs_LengthDimension.cpp
src/SketcherPrs/SketcherPrs_Perpendicular.cpp
src/SketcherPrs/SketcherPrs_PositionMgr.cpp
src/XGUI/CMakeLists.txt
src/XGUI/XGUI_ActionsMgr.cpp
src/XGUI/XGUI_ContextMenuMgr.cpp
src/XGUI/XGUI_Displayer.cpp
src/XGUI/XGUI_Displayer.h
src/XGUI/XGUI_ErrorMgr.cpp
src/XGUI/XGUI_InspectionPanel.cpp
src/XGUI/XGUI_MenuMgr.cpp
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_PropertyPanel.cpp
src/XGUI/XGUI_SelectionActivate.cpp
src/XGUI/XGUI_ViewerProxy.cpp
src/XGUI/XGUI_ViewerProxy.h
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_WorkshopListener.cpp
src/XGUI/XGUI_msg_fr.ts
test.models/stair_with_cycle.py [new file with mode: 0644]

index dfc3a0edbd7580f71b5eed7faa7b2a195bf5e74c..23c027052ffa1aa04261da269f0ac050205294f2 100644 (file)
@@ -120,6 +120,13 @@ 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 NO)
+
+IF(${MAKE_TRANSLATION})
+       ADD_DEFINITIONS( -DMAKE_TRANSLATION )
+ENDIF(${MAKE_TRANSLATION})
+
+
 ADD_SUBDIRECTORY (src/Config)
 ADD_SUBDIRECTORY (src/Events)
 ADD_SUBDIRECTORY (src/Selector)
diff --git a/env.sh b/env.sh
index 72508628da329541210088ee4871270f00d651c1..cb3501729532c69931f3e172e4d8e2def41b5c95 100644 (file)
--- a/env.sh
+++ b/env.sh
@@ -1,6 +1,6 @@
 #!/bin/bash -x
 
-export SALOME_DIR=/dn46/SALOME/series9x/current-2019-08-19
+export SALOME_DIR=/dn46/SALOME/series9x/current-2019-10-04
 
 # Path to sources
 export SOURCES_DIR=$(pwd)
index ebd0c76a13e29732ac949a37e7704c597cd92cd7..cd094cf1528fb31670e24af8f0b45dfd6e2d4ce3 100755 (executable)
@@ -65,9 +65,6 @@ for MASK in $ALL; do
     mv -f covElse_res covElse
   fi
 done
-# remove SketchPlugin's Ellipse feature (unsupported yet)
-lcov -r covElse SketchPlugin*Ellipse* --output-file covElse_res -q
-mv -f covElse_res covElse
 rm -rf lcov_htmlElse
 genhtml covElse --output-directory lcov_htmlElse -q
 
index 45d859844be13e4e08a845d0aec964426cbdbd38..65be3411933356f25d4724b941c2659b693436a4 100644 (file)
@@ -99,7 +99,7 @@ bool BuildPlugin_ValidatorBaseForBuild::isValid(const AttributePtr& theAttribute
       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
     if(aConstruction.get()) {
       if(aConstruction->isInfinite()) {
-        theError = "Inifinte objects not acceptable.";
+        theError = "Infinite objects not acceptable.";
         return false;
       }
 
index a29504da91722e719fee119cd8c6a4f9ad5ab1d5..25c950d5fc0577f5889ed970148d7862e5ddc47f 100644 (file)
@@ -39,8 +39,8 @@
   <context>
     <name>Edge:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
     <message>
-      <source>Inifinte objects not acceptable.</source>
-      <translation>Inifinte objects not acceptable.</translation>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Infinite objects not acceptable.</translation>
     </message>
   </context>
   <context>
   <context>
     <name>Face:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
     <message>
-      <source>Inifinte objects not acceptable.</source>
-      <translation>Inifinte objects not acceptable.</translation>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Infinite objects not acceptable.</translation>
     </message>
   </context>
   <context>
   <context>
     <name>Vertex:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
     <message>
-      <source>Inifinte objects not acceptable.</source>
-      <translation>Inifinte objects not acceptable.</translation>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Infinite objects not acceptable.</translation>
     </message>
   </context>
   <context>
   <context>
     <name>Wire:base_objects:BuildPlugin_ValidatorBaseForBuild</name>
     <message>
-      <source>Inifinte objects not acceptable.</source>
-      <translation>Inifinte objects not acceptable.</translation>
+      <source>Infinite objects not acceptable.</source>
+      <translation>Infinite objects not acceptable.</translation>
     </message>
   </context>
   <context>
diff --git a/src/BuildPlugin/BuildPlugin_msg_fr.ts b/src/BuildPlugin/BuildPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..33a975b
--- /dev/null
@@ -0,0 +1,1138 @@
+<?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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "first_point" is not initialized.</source>
+      <translation>AA</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..1d1bf847c3e963a26d1c39f3f9229e4d569aa4c6 100644 (file)
@@ -83,6 +83,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     BuildPlugin_msg_en.ts
+    BuildPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
index 2c283b8b1c309e415d3068b1610001d42f6b5698..a744731cde8f47150b53ea795e8a8f8293849a76 100644 (file)
@@ -6,6 +6,6 @@
                   concealment="true">
     <validator id="GeomValidators_DifferentShapes"/>
   </multi_selector>
-  <boolvalue id="closed" label="Closed" tooltip="Makes the polyline closed." default="false"/>
+  <boolvalue id="closed" label="Closed" tooltip="Closes the polyline." default="false"/>
   <validator id="GeomValidators_MinObjectsSelected" parameters="base_objects,2"/>
 </source>
index ee6594416638b53f776a2a959e0d37a3e40c3efc..fae2ae36a7e5be5b549c6d08706a0ebe16897111 100644 (file)
@@ -63,7 +63,10 @@ void CollectionAPI_Group::dump(ModelHighAPI_Dumper& theDumper) const
 
   AttributeSelectionListPtr anAttrList = aBase->selectionList(CollectionPlugin_Group::LIST_ID());
 
-  theDumper << aBase << " = model.addGroup(" << aDocName << ", " << anAttrList;
+  theDumper << aBase << " = model.addGroup(" << aDocName << ", ";
+  if (anAttrList->isWholeResultAllowed() && !anAttrList->selectionType().empty())
+    theDumper<<"\""<<anAttrList->selectionType()<<"\", ";
+  theDumper << anAttrList;
   if (anAttrList->isGeometricalSelection())
     theDumper <<", True";
   theDumper << ")" << std::endl;
@@ -79,3 +82,16 @@ GroupPtr addGroup(const std::shared_ptr<ModelAPI_Document>& thePart,
     aFeature->selectionList(CollectionPlugin_Group::LIST_ID())->setGeometricalSelection(true);
   return GroupPtr(new CollectionAPI_Group(aFeature, theGroupList));
 }
+
+//==================================================================================================
+GroupPtr addGroup(const std::shared_ptr<ModelAPI_Document>& thePart,
+  const std::string& theSelectionType,
+  const std::list<ModelHighAPI_Selection>& theGroupList,
+  const bool theShareSameTopology)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(CollectionAPI_Group::ID());
+  aFeature->selectionList(CollectionPlugin_Group::LIST_ID())->setSelectionType(theSelectionType);
+  if (theShareSameTopology)
+    aFeature->selectionList(CollectionPlugin_Group::LIST_ID())->setGeometricalSelection(true);
+  return GroupPtr(new CollectionAPI_Group(aFeature, theGroupList));
+}
index 284737e1c087a2bcff1da8a2c80e2552e3010470..3c535e5994469b2f927ed25c5d2eefb40e8dc968 100644 (file)
@@ -72,4 +72,12 @@ GroupPtr addGroup(const std::shared_ptr<ModelAPI_Document>& thePart,
                   const std::list<ModelHighAPI_Selection>& theGroupList,
                   const bool theShareSameTopology = false);
 
+/// \ingroup CPPHighAPI
+/// \brief Create Group with the additional selection type for case the whole result selected.
+COLLECTIONAPI_EXPORT
+GroupPtr addGroup(const std::shared_ptr<ModelAPI_Document>& thePart,
+  const std::string& theSelectionType,
+  const std::list<ModelHighAPI_Selection>& theGroupList,
+  const bool theShareSameTopology = false);
+
 #endif // CollectionAPI_Group_H_
index 251b91ffea8ef1c42fcb567da8d9a4604bab0b7f..65cac240e27667755d5258d1143d1ef9ce37975d 100644 (file)
@@ -68,6 +68,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     CollectionPlugin_msg_en.ts
+    CollectionPlugin_msg_fr.ts
 )
 
 # sources / moc wrappings
@@ -138,13 +139,22 @@ ADD_UNIT_TESTS(
                TestGroupMove18.py
                TestGroupMove19.py
                TestGroupMove20.py
+               TestGroupMove21.py
+               TestGroupMove22.py
+               TestGroupMove23.py
+               TestGroupMove24.py
+               TestGroupMove25.py
                TestGroupShareTopology.py
                TestGroupAddition.py
                TestGroupAddition_Error.py
                TestGroupIntersection.py
                TestGroupIntersection_Error.py
                TestGroupSubstraction.py
+               TestGroupSubstraction2.py
                TestGroupSubstraction_Error1.py
                TestGroupSubstraction_Error2.py
                Test2977.py
+               TestGroupWholeResult1.py
+               TestGroupWholeResult2.py
+               Test3031.py
 )
index cd5ef4108a6b27548f44d1dde74f2c319c8e0d81..82926ab21921946ac76ac567b84f900ec9eb16bb 100644 (file)
@@ -32,8 +32,9 @@ CollectionPlugin_Group::CollectionPlugin_Group()
 
 void CollectionPlugin_Group::initAttributes()
 {
-  data()->addAttribute(CollectionPlugin_Group::LIST_ID(),
-                       ModelAPI_AttributeSelectionList::typeId());
+  AttributeSelectionListPtr aList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(
+    data()->addAttribute(LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
+  aList->setWholeResultAllowed(true); // allow to select the whole result
 }
 
 void CollectionPlugin_Group::execute()
index 9d39711ae52442c9ca2c1c2dc6233f60335210e8..daa343e4187aadf8400a4f526add132f9e5ab73f 100644 (file)
@@ -30,7 +30,7 @@
 #include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 
-typedef std::set<GeomShapePtr, GeomAPI_Shape::ComparatorWithOri> SetOfShape;
+typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
 
 CollectionPlugin_GroupSubstraction::CollectionPlugin_GroupSubstraction()
 {
index 3c2d28234f0d7a1e12046faff1037271fad59caa..c34371bde45f06a26cd33ff51109d66cd1770358 100644 (file)
       <translation>Constructions not allowed for selection.</translation>
     </message>
   </context>
-  <context>
-    <name>Group:group_list:GeomValidators_BodyShapes</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation>Attribute "%1" does not supported by "GeomValidators_BodyShapes" validator.</translation>
-    </message>
-  </context>
   <context>
     <name>Group:Model_FeatureValidator</name>
     <message>
diff --git a/src/CollectionPlugin/CollectionPlugin_msg_fr.ts b/src/CollectionPlugin/CollectionPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..f409178
--- /dev/null
@@ -0,0 +1,263 @@
+<?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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "group_list" is not initialized.</source>
+      <translation>AA</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/Test3031.py b/src/CollectionPlugin/Test/Test3031.py
new file mode 100644 (file)
index 0000000..a96f09f
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Test of movement of the group of whole result with different results shape types: only one shape type must be in the moved group
+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"))
+SketchCircle_1 = Sketch_1.addCircle(17.20575221238938, 2.793141592920342, 8.375699762004958)
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_2.addLine(24.25155410709516, 6.639479956172791, 20.59251568321609, -12.31511385947313)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")])
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_1")])
+Group_1 = model.addGroup(Part_1_doc, "Edges", [model.selection("EDGE", "Edge_1_1")])
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("FACE", "Face_1_1"), model.selection("EDGE", "Edge_1_1")], 20190506)
+model.do()
+# move group after the partition
+Part_1_doc.moveFeature(Group_1.feature(), Partition_1.feature())
+model.end()
+
+# check that only two edges are in the group result, no face
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.EDGE, [2])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove21.py b/src/CollectionPlugin/Test/TestGroupMove21.py
new file mode 100644 (file)
index 0000000..4dda28f
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Test move the group in history for selection of a whole result
+
+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(35.07635467980296, 23.01108374384237, -25.74753694581282, 23.01108374384237)
+SketchLine_2 = Sketch_1.addLine(-25.74753694581282, 23.01108374384237, -25.74753694581282, -23.13546798029557)
+SketchLine_3 = Sketch_1.addLine(-25.74753694581282, -23.13546798029557, 35.07635467980296, -23.13546798029557)
+SketchLine_4 = Sketch_1.addLine(35.07635467980296, -23.13546798029557, 35.07635467980296, 23.01108374384237)
+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())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 80, 0)
+# selection of a whole result: 6 faces of a box
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [6])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"))
+SketchCircle_1 = Sketch_2.addCircle(-7.736745115674536, 52.14422040986419, 6.760003867274182)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in the group-results
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [8])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove22.py b/src/CollectionPlugin/Test/TestGroupMove22.py
new file mode 100644 (file)
index 0000000..40802c6
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Test move the group in history for selection of a whole result of a compsolid
+
+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(-25.00123152709361, 27.48891625615764, 27.86206896551725, 27.48891625615764)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(27.86206896551725, 27.48891625615764, -23.88177339901478, -20.02586206896552)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-23.88177339901478, -20.02586206896552, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(28.73275862068966, -20.02586206896552, 27.86206896551725, 27.48891625615764)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.endPoint())
+SketchLine_5 = Sketch_1.addLine(-25.00123152709361, 27.48891625615764, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_5.endPoint())
+model.do()
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_5f-SketchLine_2r-SketchLine_1r"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_5f-SketchLine_4f"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_3f-SketchLine_5r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+# selection of a whole result: 5x3-2 faces (2 faces are shared)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPSOLID", "Extrusion_1_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [13])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("COMPSOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_1/To_Face"))
+SketchCircle_1 = Sketch_2.addCircle(13.4282260278248, 11.79859034244854, 3.718064241992405)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in two solids: +4 faces (1 splitted planar, 3 faces of cylinder, divided by seam)
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [17])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove23.py b/src/CollectionPlugin/Test/TestGroupMove23.py
new file mode 100644 (file)
index 0000000..50d347f
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Test move the group in history for selection of a whole feature
+
+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(35.07635467980296, 23.01108374384237, -25.74753694581282, 23.01108374384237)
+SketchLine_2 = Sketch_1.addLine(-25.74753694581282, 23.01108374384237, -25.74753694581282, -23.13546798029557)
+SketchLine_3 = Sketch_1.addLine(-25.74753694581282, -23.13546798029557, 35.07635467980296, -23.13546798029557)
+SketchLine_4 = Sketch_1.addLine(35.07635467980296, -23.13546798029557, 35.07635467980296, 23.01108374384237)
+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())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 80, 0)
+# selection of a whole feature: 6 faces of a box
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [6])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"))
+SketchCircle_1 = Sketch_2.addCircle(-7.736745115674536, 52.14422040986419, 6.760003867274182)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in the group-results
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [8])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove24.py b/src/CollectionPlugin/Test/TestGroupMove24.py
new file mode 100644 (file)
index 0000000..8b37ce2
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Test move the group in history for selection of a whole feature that produces compsolid
+
+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(-25.00123152709361, 27.48891625615764, 27.86206896551725, 27.48891625615764)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(27.86206896551725, 27.48891625615764, -23.88177339901478, -20.02586206896552)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-23.88177339901478, -20.02586206896552, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(28.73275862068966, -20.02586206896552, 27.86206896551725, 27.48891625615764)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.endPoint())
+SketchLine_5 = Sketch_1.addLine(-25.00123152709361, 27.48891625615764, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_5.endPoint())
+model.do()
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_5f-SketchLine_2r-SketchLine_1r"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_5f-SketchLine_4f"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_3f-SketchLine_5r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+# selection of a whole result: 5x3-2 faces (2 faces are shared)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [13])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("COMPSOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_1/To_Face"))
+SketchCircle_1 = Sketch_2.addCircle(13.4282260278248, 11.79859034244854, 3.718064241992405)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in two solids: +4 faces (1 splitted planar, 3 faces of cylinder, divided by seam)
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [17])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove25.py b/src/CollectionPlugin/Test/TestGroupMove25.py
new file mode 100644 (file)
index 0000000..24255be
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# Test move the group in history for selection of a whole features
+# with many modifications of this feature, and joining them in one.
+
+from SketchAPI import *
+
+from salome.shaper import model
+from ModelAPI 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, 9.999999999999998, -40, 10)
+SketchLine_2 = Sketch_1.addLine(-40, 10, -40, -10)
+SketchLine_3 = Sketch_1.addLine(-40, -10, -20, -9.999999999999998)
+SketchLine_4 = Sketch_1.addLine(-20, -9.999999999999998, -20, 9.999999999999998)
+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())
+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_5 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_3.result(), SketchCircle_1.results()[1])
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), 20, True)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_4.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 30, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 15, 0)
+Group_1 = model.addGroup(Part_1_doc, "Vertices", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_2 = model.addGroup(Part_1_doc, "Vertices", [model.selection("COMPOUND", "all-in-Extrusion_2")])
+Group_3 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1"), model.selection("COMPOUND", "all-in-Extrusion_2")])
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [], model.selection(), 12, 0, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4"))
+SketchCircle_2 = Sketch_2.addCircle(-2.3396523840492e-15, 15, 7)
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_2.results()[1], 7)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4]"), False)
+SketchLine_5 = SketchProjection_2.createdFeature()
+SketchConstraintDistance_2 = Sketch_2.setDistance(SketchCircle_2.center(), SketchLine_5.result(), 10, True)
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1/To_Face]"), False)
+SketchLine_6 = SketchProjection_3.createdFeature()
+SketchConstraintDistance_3 = Sketch_2.setDistance(SketchCircle_2.center(), SketchLine_6.result(), 15, True)
+ExtrusionFuse_1.setNestedSketch(Sketch_2)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 50, 50, [model.selection("SOLID", "ExtrusionFuse_1_1"), model.selection("SOLID", "Extrusion_2_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionFuse_1_1/To_Face"))
+SketchProjection_4 = Sketch_3.addProjection(model.selection("VERTEX", "[ExtrusionFuse_1_1/Generated_Face&Sketch_2/SketchCircle_2_2][ExtrusionFuse_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_4.createdFeature()
+SketchCircle_3 = Sketch_3.addCircle(-2.3396523840492e-15, 15, 5)
+SketchConstraintCoincidence_6 = Sketch_3.setCoincident(SketchPoint_2.result(), SketchCircle_3.center())
+SketchConstraintRadius_3 = Sketch_3.setRadius(SketchCircle_3.results()[1], 5)
+ExtrusionCut_1.setNestedSketch(Sketch_3)
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("SOLID", "ExtrusionCut_1_2")], True, 20190506)
+model.do()
+# move groups after the final fuse
+Part_1_doc.moveFeature(Group_1.feature(), Fuse_1.feature())
+Part_1_doc.moveFeature(Group_2.feature(), Group_1.feature())
+Part_1_doc.moveFeature(Group_3.feature(), Group_2.feature())
+model.end()
+
+aFactory = ModelAPI_Session.get().validators()
+for group in [Group_1, Group_2, Group_3]:
+  selectionList = group.feature().selectionList("group_list")
+  assert(selectionList.size() == 1)
+  assert(aFactory.validate(group.feature()))
diff --git a/src/CollectionPlugin/Test/TestGroupSubstraction2.py b/src/CollectionPlugin/Test/TestGroupSubstraction2.py
new file mode 100644 (file)
index 0000000..fdaf523
--- /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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-30, -17.32050807568877, 30, -17.32050807568877)
+SketchLine_2 = Sketch_1.addLine(30, -17.32050807568877, 0, 34.64101615137755)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(0, 34.64101615137755, -30, -17.32050807568877)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_4 = Sketch_1.addLine(30, -17.32050807568877, 0, 0)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(0, 0, 0, 34.64101615137755)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(-30, -17.32050807568877, 0, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_6.endPoint())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_4.result(), SketchLine_5.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_4.result(), SketchLine_6.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 60)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), 10, 0)
+Group_1_objects = [model.selection("FACE", "Extrusion_1_1_3/Generated_Face&Sketch_1/SketchLine_6"), model.selection("FACE", "Extrusion_1_1_3/To_Face"), model.selection("FACE", "Extrusion_1_1_3/From_Face"), model.selection("FACE", "Extrusion_1_1_3/Generated_Face&Sketch_1/SketchLine_3"), model.selection("FACE", "Extrusion_1_1_3/Generated_Face&Sketch_1/SketchLine_5"), model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_6"), model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1"), model.selection("FACE", "Extrusion_1_1_1/From_Face"), model.selection("FACE", "Extrusion_1_1_1/To_Face"), model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4"), model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_4"), model.selection("FACE", "Extrusion_1_1_2/To_Face"), model.selection("FACE", "Extrusion_1_1_2/From_Face"), model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_2"), model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_5")]
+Group_1 = model.addGroup(Part_1_doc, "Faces", Group_1_objects)
+Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_1_2")])
+GroupSubstraction_1 = model.addGroupSubstraction(Part_1_doc, [model.selection("COMPOUND", "Group_1")], [model.selection("COMPOUND", "Group_2")])
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(GroupSubstraction_1, 1)
+model.testNbSubResults(GroupSubstraction_1, [0])
+model.testNbSubShapes(GroupSubstraction_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(GroupSubstraction_1, GeomAPI_Shape.FACE, [7])
+model.testNbSubShapes(GroupSubstraction_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(GroupSubstraction_1, GeomAPI_Shape.VERTEX, [48])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupWholeResult1.py b/src/CollectionPlugin/Test/TestGroupWholeResult1.py
new file mode 100644 (file)
index 0000000..bc1a800
--- /dev/null
@@ -0,0 +1,57 @@
+# 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 result 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(-16, -4, -4, 29)
+SketchLine_2 = Sketch_1.addLine(-4, 29, 21, -9)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(21, -9, -16, -4)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 10, 0)
+Group_1 = model.addGroup(Part_1_doc, "EDGE", [model.selection("SOLID", "Extrusion_1_1")])
+model.end()
+
+# check the group result: it must be compound of 9 edges
+assert(Group_1.groupList().selectionType() == "EDGE")
+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.isEdge())
+  aNum = aNum + 1
+  anIter.next()
+
+assert(aNum == 9)
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupWholeResult2.py b/src/CollectionPlugin/Test/TestGroupWholeResult2.py
new file mode 100644 (file)
index 0000000..31114c3
--- /dev/null
@@ -0,0 +1,47 @@
+# 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 result (by feature) in group selection
+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)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Box_1")])
+Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Box_1_1/Top")])
+GroupSubstraction_1 = model.addGroupSubstraction(Part_1_doc, [model.selection("COMPOUND", "Group_1")], [model.selection("COMPOUND", "Group_2")])
+model.end()
+
+aResultShape = GroupSubstraction_1.feature().firstResult().shape()
+
+from GeomAPI import GeomAPI_ShapeIterator
+anIter = GeomAPI_ShapeIterator(aResultShape)
+aNum = 0
+while anIter.more():
+  aFace = anIter.current()
+  assert(aFace.isFace())
+  aNum = aNum + 1
+  anIter.next()
+
+assert(aNum == 4) # 6 from the whole result minus 2 from the second group (local selection)
+
+
+assert(model.checkPythonDump())
index 35cbf714f22d00691b172d211e3ff187bb304bb6..98f21d97e4c092f32d0039f3b6b28c84ce420253 100644 (file)
@@ -6,7 +6,8 @@
   <multi_selector id="group_list"
                   label="Base groups:"
                   tooltip="Select a set of groups"
-                  shape_types="objects">
+                  shape_types="objects"
+                  allow_objects="Group">
     <validator id="CollectionPlugin_OperationAttribute"/>
   </multi_selector>
 </source>
index ebd76f0ebdc57595c0590ad6f73f614165153874..924e4a63159d1037fdb0c3611c4b819a80c37ba0 100644 (file)
@@ -6,13 +6,15 @@
   <multi_selector id="group_list"
                   label="Main groups:"
                   tooltip="Select a set of groups"
-                  shape_types="objects">
+                  shape_types="objects"
+                  allow_objects="Group">
     <validator id="CollectionPlugin_OperationAttribute" parameters="tools_list"/>
   </multi_selector>
   <multi_selector id="tools_list"
                   label="Tool groups:"
                   tooltip="Select a set of groups"
-                  shape_types="objects">
+                  shape_types="objects"
+                  allow_objects="Group">
     <validator id="CollectionPlugin_OperationAttribute" parameters="group_list"/>
   </multi_selector>
 </source>
index a3d4d7223abd3f658284ab63d0c2cb11712d6766..63d409e3c86cff389af0277079634a95df500267 100644 (file)
@@ -114,7 +114,7 @@ model.begin()
 model.exportToGEOM(Part_1_doc)
 model.end()
 
-# check that in GEOM module there are reuslts:
+# check that in GEOM module there are results:
 # extrusion of the first part
 # extrusion with group of the second part
 # extrusion with filed of the third part
diff --git a/src/ConnectorAPI/Test/TestExportToGEOMWholeFeature.py b/src/ConnectorAPI/Test/TestExportToGEOMWholeFeature.py
new file mode 100644 (file)
index 0000000..53e2897
--- /dev/null
@@ -0,0 +1,130 @@
+# 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
+#
+import salome
+
+from SketchAPI import *
+from salome.shaper import model
+
+from salome.geom import geomBuilder
+
+import os
+import tempfile
+
+salome.salome_init(1)
+geompy = geomBuilder.New()
+
+## Get the last object published in the GEOM section of the object browser
+def getGEOMShape(index):
+  sb = salome.myStudy.NewBuilder()
+  comp = salome.myStudy.FindComponent("GEOM")
+  obj = None
+  if comp:
+    iterator = salome.myStudy.NewChildIterator( comp )
+    sobj = None
+    i = index + 1
+    while iterator.More() and i:
+      sobj = iterator.Value()
+      iterator.Next()
+      i = i - 1
+    if i == 0 and sobj:
+      obj = sobj.GetObject()
+  else:
+    raise Exception("GEOM component " + str(index) + " not found.")
+  return obj
+
+## Get the sub-object i of an object in the object browser
+# Numerotation starts at 1
+def getSubObject(obj, i):
+  ok, sub_sobj = salome.ObjectToSObject(obj).FindSubObject(i)
+  if not ok:
+    raise Exception("No child found at %i for %s"%(i, obj.GetName()))
+  sub_obj = sub_sobj.GetObject()
+  return sub_obj
+
+
+def testExportToGEOM():
+  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("YOZ"))
+  SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+  SketchPoint_1 = SketchProjection_1.createdFeature()
+  SketchCircle_1 = Sketch_1.addCircle(0, 0, 25)
+  SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+  SketchCircle_2 = Sketch_1.addCircle(20, -15, 20)
+  SketchCircle_3 = Sketch_1.addCircle(0, 25, 24.7213595499958)
+  SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchCircle_1.results()[1], SketchCircle_3.center())
+  SketchCircle_4 = Sketch_1.addCircle(-20, -15, 20)
+  SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchCircle_1.results()[1], SketchCircle_4.center())
+  SketchConstraintTangent_1 = Sketch_1.setTangent(SketchCircle_4.results()[1], SketchCircle_2.results()[1])
+  SketchConstraintTangent_2 = Sketch_1.setTangent(SketchCircle_3.results()[1], SketchCircle_2.results()[1])
+  SketchConstraintTangent_3 = Sketch_1.setTangent(SketchCircle_4.results()[1], SketchCircle_3.results()[1])
+  SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchCircle_2.center(), SketchCircle_1.results()[1])
+  SketchConstraintEqual_1 = Sketch_1.setEqual(SketchCircle_2.results()[1], SketchCircle_4.results()[1])
+  SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_2.results()[1], 20)
+  SketchConstraintRadius_2 = Sketch_1.setRadius(SketchCircle_1.results()[1], 25)
+  SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+  SketchLine_1 = SketchProjection_2.createdFeature()
+  SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.result(), SketchCircle_3.center())
+  model.do()
+  Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchCircle_4_2r-SketchCircle_4_2r-SketchCircle_3_2r"), model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchCircle_3_2r-SketchCircle_2_2r-SketchCircle_2_2r"), model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchCircle_2_2r-SketchCircle_4_2r")]
+  Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+  # select all results of an extrusion feature
+  Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPSOLID", "all-in-Extrusion_1")])
+  Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_2")])
+  GroupSubstraction_1 = model.addGroupSubstraction(Part_1_doc, [model.selection("COMPOUND", "Group_1")], [model.selection("COMPOUND", "Group_2")])
+  model.do()
+  model.exportToGEOM(Part_1_doc)
+  model.end()
+
+  # check that in GEOM module there are 3-SOLIDs-reuslts, with 2 groups each
+  shape1 = getGEOMShape(0)
+  assert(shape1)
+  assert(shape1.GetName() == "Extrusion_1_1")
+  assert(geompy.NumberOfSolids(shape1) == 1)
+  assert(salome.ObjectToSObject(shape1).FindSubObject(1)[1])
+  assert(salome.ObjectToSObject(shape1).FindSubObject(1)[1].GetName() == "Group_1")
+  assert(salome.ObjectToSObject(shape1).FindSubObject(2)[1])
+  assert(salome.ObjectToSObject(shape1).FindSubObject(2)[1].GetName() == "GroupSubstraction_1")
+
+  shape2 = getGEOMShape(1)
+  assert(shape2)
+  assert(shape2.GetName() == "Extrusion_1_2")
+  assert(geompy.NumberOfSolids(shape2) == 1)
+  assert(salome.ObjectToSObject(shape2).FindSubObject(1)[1])
+  assert(salome.ObjectToSObject(shape2).FindSubObject(1)[1].GetName() == "Group_1")
+  assert(salome.ObjectToSObject(shape2).FindSubObject(2)[1])
+  assert(salome.ObjectToSObject(shape2).FindSubObject(2)[1].GetName() == "Group_2")
+
+  shape3 = getGEOMShape(2)
+  assert(shape3)
+  assert(shape3.GetName() == "Extrusion_1_3")
+  assert(geompy.NumberOfSolids(shape3) == 1)
+  assert(salome.ObjectToSObject(shape3).FindSubObject(1)[1])
+  assert(salome.ObjectToSObject(shape3).FindSubObject(1)[1].GetName() == "Group_1")
+  assert(salome.ObjectToSObject(shape3).FindSubObject(2)[1])
+  assert(salome.ObjectToSObject(shape3).FindSubObject(2)[1].GetName() == "GroupSubstraction_1")
+
+  shape4 = getGEOMShape(3)
+  assert(not shape4)
+
+
+if __name__ == '__main__':
+  testExportToGEOM()
diff --git a/src/ConnectorAPI/Test/TestExportToGEOMWholeResult.py b/src/ConnectorAPI/Test/TestExportToGEOMWholeResult.py
new file mode 100644 (file)
index 0000000..009f1f1
--- /dev/null
@@ -0,0 +1,129 @@
+# 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
+#
+
+import salome
+from salome.shaper import model
+
+from salome.geom import geomBuilder
+
+import os
+import tempfile
+
+salome.salome_init(1)
+geompy = geomBuilder.New()
+
+## Get the last object published in the GEOM section of the object browser
+def getLastGEOMShape():
+  sb = salome.myStudy.NewBuilder()
+  comp = salome.myStudy.FindComponent("GEOM")
+  obj = None
+  if comp:
+    iterator = salome.myStudy.NewChildIterator( comp )
+    sobj = None
+    while iterator.More():
+      sobj = iterator.Value()
+      iterator.Next()
+    if sobj:
+      obj = sobj.GetObject()
+  else:
+    raise Exception("GEOM component not found.")
+  return obj
+
+## Get the sub-object i of an object in the object browser
+# Numerotation starts at 1
+def getSubObject(obj, i):
+  ok, sub_sobj = salome.ObjectToSObject(obj).FindSubObject(i)
+  if not ok:
+    raise Exception("No child found at %i for %s"%(i, obj.GetName()))
+  sub_obj = sub_sobj.GetObject()
+  return sub_obj
+
+def dumpShaper(fileName):
+  model.begin()
+  dump=model.moduleDocument().addFeature("Dump")
+  dump.string("file_path").setValue(fileName)
+  dump.string("file_format").setValue("py")
+  dump.boolean("topological_naming").setValue(True)
+  dump.boolean("geometric_selection").setValue(False)
+  dump.boolean("weak_naming").setValue(False)
+  model.do()
+  model.end()
+  pass
+
+# Create 2 boxes
+# Create a group of all edges of the first box (whole result)
+# Create a group of all faces of the whole partition result (whole result)
+# exportToGEOM
+# Check the result
+# Check the dump
+def testExportToGEOM():
+
+  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, 20, 20, 20)
+  Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), -10)
+  Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Box_2_1")])
+  Group_1 = model.addGroup(Part_1_doc, "EDGE", [model.selection("COMPSOLID", "Partition_1_1_1")])
+  Group_2 = model.addGroup(Part_1_doc, "FACE", [model.selection("COMPSOLID", "Partition_1_1")])
+  model.do()
+
+  model.exportToGEOM(Part_1_doc)
+  model.end()
+
+  # Check that the GEOM object has 1 compsolid and 2 solids
+  geomObject_1 = getLastGEOMShape()
+  assert geompy.NumberOfSubShapes(geomObject_1, geompy.ShapeType["COMPSOLID"]) == 1
+  assert geompy.NumberOfSolids(geomObject_1) == 2
+
+  # Check that the group has 12 edges
+  geomGroup_1 = getSubObject(geomObject_1, 1)
+  assert geompy.NumberOfEdges(geomGroup_1) == 12
+
+  # Check that the group has 6+6 faces
+  geomGroup_2 = getSubObject(geomObject_1, 2)
+  assert geompy.NumberOfFaces(geomGroup_2) == 12
+
+  # Dump the salome study (only CORBA modules, SHAPER dump is not in it)
+  tempdir = tempfile.gettempdir()
+  dumpFileGeomBase = "dump_test_geom"
+  dumpFileGeom = os.path.join(tempdir, "%s.py"%dumpFileGeomBase)
+  salome.myStudy.DumpStudy(tempdir, dumpFileGeomBase, True, False)
+
+  # Dump SHAPER
+  dumpFileShaper = os.path.join(tempdir, "dump_test_shaper.py")
+  dumpShaper(dumpFileShaper)
+
+  # Load SHAPER dump
+  exec(compile(open(dumpFileShaper).read(), dumpFileShaper, 'exec'))
+
+  # Load GEOM dump
+  exec(compile(open(dumpFileGeom).read(), dumpFileGeom, 'exec'))
+
+  # Clean files
+  files = [dumpFileGeom, dumpFileShaper]
+  for f in files:
+    os.remove(f)
+
+  pass
+
+if __name__ == '__main__':
+  testExportToGEOM()
index 4ac3002a0bbb4ab84c9b6485fc408de5297b748a..2c4eac5044f3ed5ead51b0787ca3e964d99de8ba 100644 (file)
@@ -21,5 +21,7 @@ SET(TEST_NAMES
   TestExportToGEOM
   TestExportToGEOMAllGroupsAndFields
   TestExportToGEOMPartSet
+  TestExportToGEOMWholeResult
+  TestExportToGEOMWholeFeature
   Test2882
 )
index 9e247c9d8b106c9b48a0a092a547168eb5a824c3..17a885057e9dfb3f69597e62025ea52b74b426b0 100644 (file)
@@ -28,8 +28,14 @@ SET(XML_RESOURCES
   plugin-Connector.xml
 )
 
-ADD_CUSTOM_TARGET(ConnectorPlugin SOURCES ${PYTHON_FILES} ${XML_RESOURCES})
+SET(TEXT_RESOURCES
+    ConnectorPlugin_msg_fr.ts
+)
+
+SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
+
+ADD_CUSTOM_TARGET(ConnectorPlugin SOURCES ${PYTHON_FILES} ${XML_RESOURCES} ${TEXT_RESOURCES})
 
 INSTALL(FILES ${PYTHON_FILES} DESTINATION ${SHAPER_INSTALL_PYTHON_FILES})
-INSTALL(FILES ${XML_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
+INSTALL(FILES ${XML_RESOURCES} ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Connector)
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 caac05b282201cccb10641ccd8214ebd522b2395..d0eb76878874fbf3892dbfc29e1db9a65084dba7 100644 (file)
@@ -4,7 +4,7 @@
       <feature
         id="ExportToGEOM"
         title="Export to GEOM"
-        tooltip="Export all bodies and groups into GEOM module"
+        tooltip="Export all results and groups into GEOM module"
         icon="icons/Connector/geom_export.png"
         helpfile="ConnectorPlugin/ConnectorPlugin.html"/>
     </group>
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
index 0b0dc4bb297c7c602e1d9093af5f0e8fde747a91..637e37b4e8de2f9edff675305ab4198034e474f2 100644 (file)
@@ -58,6 +58,8 @@ ConstructionPlugin_Plugin::ConstructionPlugin_Plugin()
                                    PLANE_SIZE, "0", "1000");
   Config_PropManager::registerProp(SKETCH_TAB_NAME, "planes_thickness", "Thickness",
     Config_Prop::IntSpin, SKETCH_WIDTH);
+  Config_PropManager::registerProp(SKETCH_TAB_NAME, "angular_tolerance", "Angular tolerance",
+    Config_Prop::DblSpin, "0.04");
   Config_PropManager::registerProp(SKETCH_TAB_NAME, "rotate_to_plane",
     "Rotate to plane when selected", Config_Prop::Boolean, "false");
 
index a26f2f519bb7066b6d1cfb31d80e376bfb18389d..d11d3c3f054927d03ebbf1243acf42e3a58140b4 100644 (file)
@@ -54,7 +54,7 @@ bool ConstructionPlugin_ValidatorPointLines::isValid(const AttributePtr& theAttr
   GeomShapePtr aLineShape1 = aLineAttribute1->value();
   ResultPtr aContext1 = aLineAttribute1->context();
   if(!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if(!aLineShape1.get()) {
@@ -120,7 +120,7 @@ bool ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel::isValid(
   GeomShapePtr aShape1 = anAttribute1->value();
   ResultPtr aContext1 = anAttribute1->context();
   if(!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if(!aShape1.get()) {
@@ -174,7 +174,7 @@ bool ConstructionPlugin_ValidatorPlaneThreePoints::isValid(const AttributePtr& t
   GeomShapePtr aPointShape1 = aPointAttribute1->value();
   ResultPtr aContext1 = aPointAttribute1->context();
   if(!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if(!aPointShape1.get()) {
@@ -252,7 +252,7 @@ bool ConstructionPlugin_ValidatorPlaneLinePoint::isValid(
   GeomShapePtr aShape1 = anAttribute1->value();
   ResultPtr aContext1 = anAttribute1->context();
   if(!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if(!aShape1.get()) {
@@ -310,7 +310,7 @@ bool ConstructionPlugin_ValidatorPlaneTwoParallelPlanes::isValid(
   GeomShapePtr aShape1 = anAttribute1->value();
   ResultPtr aContext1 = anAttribute1->context();
   if(!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if(!aShape1.get()) {
@@ -363,7 +363,7 @@ bool ConstructionPlugin_ValidatorAxisTwoNotParallelPlanes::isValid(
   GeomShapePtr aShape1 = anAttribute1->value();
   ResultPtr aContext1 = anAttribute1->context();
   if(!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if(!aShape1.get()) {
@@ -414,7 +414,7 @@ bool ConstructionPlugin_ValidatorPointThreeNonParallelPlanes::isValid(
   GeomShapePtr aShape1 = anAttribute1->value();
   ResultPtr aContext1 = anAttribute1->context();
   if (!aContext1.get()) {
-    theError = "One of the attribute not initialized.";
+    theError = "One of the attribute is not initialized.";
     return false;
   }
   if (!aShape1.get()) {
index c09bc99303cf260a184108935b9860952fe06ba4..420ff5438b0794b47324ffb5f3111f29a39d453b 100644 (file)
     <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>THe second point does not contain element with acceptable shape type. The type should be: %1</translation>
+      <translation>The second point does not contain element with acceptable shape type. The type should be: %1</translation>
     </message>
   </context>
   <context>
diff --git a/src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts b/src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..926e0f1
--- /dev/null
@@ -0,0 +1,1295 @@
+<?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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "coincident_point" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "line" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "plane" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "plane1" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "point1" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "edge" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "edge_for_point_projection" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "intersection_line_1" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "object_for_center_of_gravity" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "face_for_point_projection" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "intersection_line" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "intersection_plane_1" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "object_for_center_of_circle" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "face_for_point_projection" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "intersection_line" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "intersection_plane_1" is not initialized.</source>
+      <translation>AA</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 222f2e6eaea1ac3bea1cbbb0aa44e8d0b8465cd8..2a9c196f4905e9b6f8c94b90d220c942ea0d66c9 100644 (file)
@@ -55,6 +55,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     ExchangePlugin_msg_en.ts
+    ExchangePlugin_msg_fr.ts
 )
 
 SET(PROJECT_LIBRARIES
index da17f46b8eed32edd06fa86f6f000ed72f2276f2..bf677c743730ed28aecade2876c3acdfd2e9c675 100644 (file)
@@ -38,6 +38,7 @@
 #include <GeomAlgoAPI_XAOExport.h>
 
 #include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
@@ -255,8 +256,42 @@ static bool isInResults(AttributeSelectionListPtr theSelection,
   // if context is in results, return true
   for(int a = 0; a < theSelection->size(); a++) {
     AttributeSelectionPtr anAttr = theSelection->value(a);
-    ResultBodyPtr aSelected= std::dynamic_pointer_cast<ModelAPI_ResultBody>(anAttr->context());
-    if (aSelected.get() && theCashedResults.count(aSelected))
+    ResultPtr aContext = anAttr->context();
+    // check is it group selected for groups BOP
+    if (aContext.get() && aContext->groupName() == ModelAPI_ResultGroup::group()) {
+      // it is impossible by used results check which result is used in this group result,
+      // so check the results shapes is it in results of this document or not
+      FeaturePtr aSelFeature =
+        std::dynamic_pointer_cast<ModelAPI_Feature>(theSelection->owner());
+      if (!aSelFeature.get() || aSelFeature->results().empty())
+        continue;
+      GeomShapePtr aGroupResShape = aSelFeature->firstResult()->shape();
+
+      std::set<ResultPtr>::iterator allResultsIter = theCashedResults.begin();
+      for(; allResultsIter != theCashedResults.end(); allResultsIter++) {
+        GeomShapePtr aResultShape = (*allResultsIter)->shape();
+
+        GeomAPI_Shape::ShapeType aType =
+          GeomAPI_Shape::shapeTypeByStr(theSelection->selectionType());
+        GeomAPI_ShapeExplorer aGroupResExp(aGroupResShape, aType);
+        for(; aGroupResExp.more(); aGroupResExp.next()) {
+          if (aResultShape->isSubShape(aGroupResExp.current(), false))
+            return true; // at least one shape of the group is in the used results
+        }
+      }
+    }
+    ResultBodyPtr aSelected = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anAttr->context());
+    if (!aSelected.get()) { // try to get selected feature and all its results
+      FeaturePtr aContextFeature = anAttr->contextFeature();
+      if (aContextFeature.get() && !aContextFeature->results().empty()) {
+        const std::list<ResultPtr>& allResluts = aContextFeature->results();
+        std::list<ResultPtr>::const_iterator aResIter = allResluts.cbegin();
+        for(; aResIter != allResluts.cend(); aResIter++) {
+          if (aResIter->get() && theCashedResults.count(*aResIter))
+            return true;
+        }
+      }
+    } else if (aSelected.get() && theCashedResults.count(aSelected))
       return true;
   }
   return false;
@@ -356,6 +391,8 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
     for (int aGroupIndex = 0; aGroupIndex < aGroupCount; ++aGroupIndex) {
       ResultGroupPtr aResultGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(
           (*aDoc)->object(ModelAPI_ResultGroup::group(), aGroupIndex));
+      if (!aResultGroup.get() || !aResultGroup->shape().get())
+        continue;
 
       FeaturePtr aGroupFeature = (*aDoc)->feature(aResultGroup);
 
@@ -366,6 +403,7 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
 
       // conversion of dimension
       std::string aSelectionType = aSelectionList->selectionType();
+      GeomAPI_Shape::ShapeType aSelType = GeomAPI_Shape::shapeTypeByStr(aSelectionType);
       std::string aDimensionString =
         ExchangePlugin_Tools::selectionType2xaoDimension(aSelectionType);
       XAO::Dimension aGroupDimension = XAO::XaoUtils::stringToDimension(aDimensionString);
@@ -374,23 +412,14 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
                                             aResultGroup->data()->name());
 
       try {
-        for (int aSelectionIndex = 0; aSelectionIndex < aSelectionList->size(); ++aSelectionIndex){
-          AttributeSelectionPtr aSelection = aSelectionList->value(aSelectionIndex);
-
-          // complex conversion of reference id to element index
-          // gives bad id in case the selection is done from python script
-          // => using GeomAlgoAPI_CompoundBuilder::id instead
-          // int aReferenceID_old = aSelection->Id();
-
-          int aReferenceID = GeomAlgoAPI_CompoundBuilder::id(aShape, aSelection->value());
-
+        GeomAPI_ShapeExplorer aGroupResExplorer(aResultGroup->shape(), aSelType);
+        for(; aGroupResExplorer.more(); aGroupResExplorer.next()) {
+          int aReferenceID = GeomAlgoAPI_CompoundBuilder::id(aShape, aGroupResExplorer.current());
           if (aReferenceID == 0) // selected value does not found in the exported shape
             continue;
-
           std::string aReferenceString = XAO::XaoUtils::intToString(aReferenceID);
           int anElementID =
             aXao.getGeometry()->getElementIndexByReference(aGroupDimension, aReferenceString);
-
           aXaoGroup->add(anElementID);
         }
       } catch (XAO::XAO_Exception& e) {
index ccc645ab8d3de5129603a5d6dbbe040ba6374e88..774af05d1efa1fd054a79aa5699b995bb3c6d5af 100644 (file)
@@ -42,7 +42,7 @@
     <name>Export:selection_list:GeomValidators_Finite</name>
     <message>
       <source>Infinite result is selected.</source>
-      <translation>Olny finitive shapes can be exported</translation>
+      <translation>Only finitive shapes can be exported</translation>
     </message>
   </context>
   <context>
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>
index b4ea8631a788b1b83fcdb9276d10f0677133788c..59a246ecdcbe081fbe1eaa540f736ffad1039893 100644 (file)
@@ -11,7 +11,7 @@
                helpfile="exportFeature.html">
         <source path="export_widget.xml" />
       </feature>
-      <feature id="Dump" title="Dump" tooltip="Dump python script" icon="icons/Exchange/dump.png"
+      <feature id="Dump" title="Dump" tooltip="Dump Python script" icon="icons/Exchange/dump.png"
                helpfile="dumpFeature.html">
         <export_file_selector id="file_path"
                               type="save"
index bbbc67445715785e365c12aeba3ff2aa15fe73b8..7ab0de9411da7a3c1a45c299de1d7e91050b7e6f 100644 (file)
@@ -42,7 +42,7 @@ double measureDistance(const std::shared_ptr<ModelAPI_Document>& thePart,
                        const ModelHighAPI_Selection& theTo);
 
 /// \ingroup CPPHighAPI
-/// \brief Calculate radius of circular.
+/// \brief Calculate radius of circular edge, cylindrical surface or sphere.
 FEATURESAPI_EXPORT
 double measureRadius(const std::shared_ptr<ModelAPI_Document>& thePart,
                      const ModelHighAPI_Selection& theObject);
index b3a8cd8bfa760cb95305942ebb310d1e5133612f..41b86996e151673f46d3052b499e910a651dacd4 100644 (file)
@@ -139,6 +139,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
     FeaturesPlugin_msg_en.ts
+    FeaturesPlugin_msg_fr.ts
     FeaturesPlugin_msg_ru.ts
 )
 
@@ -179,6 +180,7 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestExtrusionCut.py
                TestExtrusionCut_BySize.py
                TestExtrusionCut_ByPlanesAndOffsets.py
+               TestExtrusionCut_ByFaces.py
                TestExtrusionFuse.py
                TestExtrusionFuse_BySize.py
                TestExtrusionFuse_ByPlanesAndOffsets.py
@@ -490,6 +492,7 @@ ADD_UNIT_TESTS(TestExtrusion.py
                Test2854.py
                Test2878.py
                Test2971.py
+               Test3014.py
                TestBooleanCommon_MultiLevelCompound_v0_1.py
                TestBooleanCommon_MultiLevelCompound_v0_2.py
                TestBooleanCommon_MultiLevelCompound_v20190506_1.py
index 4f8b516b61be5c6f1690fbbd72e6cee57aa56d40..e84668d7dbe5790b559907a85abba107205bbb1f 100644 (file)
@@ -211,7 +211,7 @@ private:
   void computeLength();
   /// Compute minimal distance between pair of shapes
   void computeDistance();
-  /// Compute radius of circular edge or cylindrical face
+  /// Compute radius of circular edge, cylindrical surface or sphere.
   void computeRadius();
   /// Compute angle(s) between pair of edges if they are intersected
   void computeAngle();
index 23346e9192c6462763f58337e997deb8287d7b57..48c7141a2cd1a7908b397199e71352730189a27a 100644 (file)
@@ -128,7 +128,7 @@ void FeaturesPlugin_Partition::execute()
 
   int aPartitionVersion = version();
   if (aPartitionVersion < THE_PARTITION_VERSION_1) {
-    // default behaviours of Partition
+    // default behaviors of Partition
     if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
       for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
         storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
@@ -153,6 +153,12 @@ void FeaturesPlugin_Partition::execute()
       keepUnusedSubsOfCompound(aFirstShape, anObjects, ObjectHierarchy(), aMakeShapeList);
 
     if (anIt.more()) {
+      if (aResultCompound->shapeType() != GeomAPI_Shape::COMPOUND) {
+        // put the shape into compound
+        ListOfShape aShapes;
+        aShapes.push_back(aResultCompound);
+        aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+      }
       std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
       for (; anIt.more(); anIt.next())
         aBuilder->add(aResultCompound, anIt.current());
index d7755548e1b5e6aa279a78b9ac64fcafd465a31b..44de21fb5ffc40aa01ab76d7432e6a4a2bf01a98 100644 (file)
@@ -299,7 +299,7 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theA
 
           if(aSelectedWiresFromObjects.isBound(aWire)) {
             theError =
-              "Error: Objects with such wire already selected. Don't allow to select this object.";
+              "Error: Objects with this wire already selected. Don't allow to select this object.";
             return false;
           }
 
@@ -461,7 +461,7 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const Attribute
     GeomValidators_ShapeType aShapeTypeValidator;
     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
-                 "wires on sketch, whole sketch(if it has at least one face), "
+                 "wires on sketch, whole sketch (if it has at least one face), "
                  "and whole objects with shape types: %1";
       std::string anArgumentString;
       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
index 6af8824545464855b49d437f244a6cbe4674c609..c2ec597dfbc60dba004f592bc404ef48abd0fddc 100644 (file)
@@ -71,7 +71,7 @@ class FeaturesPlugin_ValidatorPipeLocationsNumber: public ModelAPI_FeatureValida
 /// \class FeaturesPlugin_ValidatorBaseForGeneration
 /// \ingroup Validators
 /// \brief A validator for selection base for generation. Allows to select faces on sketch,
-/// whole sketch(if it has at least one face), and following objects: vertex, edge, wire, face.
+/// whole sketch (if it has at least one face), and following objects: vertex, edge, wire, face.
 class FeaturesPlugin_ValidatorBaseForGeneration: public ModelAPI_AttributeValidator
 {
 public:
index 0caebe362d418c7fe24000cbbeb1ccd5048a2b95..f383d98035cef258d14c5f80ecb450d0f9e49245 100644 (file)
   <context>
     <name>Extrusion:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>Extrusion:base :FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</translation>
     </message>
   </context>
   <context>
   <context>
     <name>Extrusion:GeomValidators_ZeroOffset</name>
     <message>
-      <source>Wrong number of validator arguments in xml(expected 9).</source>
-      <translation>Wrong number of validator arguments in xml(expected 9).</translation>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Wrong number of validator arguments in xml (expected 9).</translation>
     </message>
   </context>
   <context>
   <context>
     <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>ExtrusionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</translation>
     </message>
   </context>
   <context>
   <context>
     <name>ExtrusionCut:GeomValidators_ZeroOffset</name>
     <message>
-      <source>Wrong number of validator arguments in xml(expected 9).</source>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
       <translation></translation>
     </message>
   </context>
   <context>
     <name>Revolution:GeomValidators_ZeroOffset</name>
     <message>
-      <source>Wrong number of validator arguments in xml(expected 9).</source>
-      <translation>Wrong number of validator "GeomValidators_ZeroOffset" arguments in xml(expected 9).</translation>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Wrong number of validator "GeomValidators_ZeroOffset" arguments in xml (expected 9).</translation>
     </message>
   </context>
   <context>
   <context>
     <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>Revolution:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</translation>
     </message>
   </context>
   <context>
   <context>
     <name>RevolutionCut:GeomValidators_ZeroOffset</name>
     <message>
-      <source>Wrong number of validator arguments in xml(expected 9).</source>
-      <translation>Wrong number of validator "GeomValidators_ZeroOffset" arguments in xml(expected 9).</translation>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Wrong number of validator "GeomValidators_ZeroOffset" arguments in xml (expected 9).</translation>
     </message>
   </context>
   <context>
     <name>RevolutionCut:Model_FeatureValidator</name>
     <message>
       <source>Attribute "main_objects" is not initialized.</source>
-      <translation>Objects for cut is not selected.</translation>
+      <translation>Objects for cut are not selected.</translation>
     </message>
   </context>
   <context>
   <context>
     <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>RevolutionCut:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</translation>
     </message>
   </context>
   <context>
   <context>
     <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>ExtrusionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</translation>
     </message>
   </context>
   <context>
   <context>
     <name>ExtrusionFuse:GeomValidators_ZeroOffset</name>
     <message>
-      <source>Wrong number of validator arguments in xml(expected 9).</source>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
       <translation></translation>
     </message>
   </context>
   <context>
     <name>RevolutionFuse:GeomValidators_ZeroOffset</name>
     <message>
-      <source>Wrong number of validator arguments in xml(expected 9).</source>
-      <translation>Wrong number of validator "GeomValidators_ZeroOffset" arguments in xml(expected 9).</translation>
+      <source>Wrong number of validator arguments in xml (expected 9).</source>
+      <translation>Wrong number of validator "GeomValidators_ZeroOffset" arguments in xml (expected 9).</translation>
     </message>
   </context>
   <context>
   <context>
     <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>RevolutionFuse:base:FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</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>Wrong number of validator "GeomValidators_MinObjectsSelected" arguments(expected 2): selection list id and min number of objects.</translation>
+      <translation>Wrong number of validator "GeomValidators_MinObjectsSelected" arguments (expected 2): selection list id and min number of objects.</translation>
     </message>
   </context>
   <context>
       <translation>Object for pipe path is not selected.</translation>
     </message>
   </context>
-  <context>
-    <name>Pipe:FeaturesPlugin_ValidatorPipeLocations</name>
-    <message>
-      <source>Error: Feature \"%1\" does not supported by this validator.</source>
-      <translation>Feature "%1" does not supported validator "FeaturesPlugin_ValidatorPipeLocations".</translation>
-    </message>
-  </context>
   <context>
     <name>Pipe:FeaturesPlugin_ValidatorPipeLocations</name>
     <message>
   <context>
     <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
     <message>
-      <source>Error: Objects with such wire already selected. Don't allow to select this object.</source>
-      <translation>Objects with such wire already selected. Don't allow to select this object.</translation>
+      <source>Error: Objects with this wire already selected. Don't allow to select this object.</source>
+      <translation>Objects with this wire already selected. Don't allow to select this object.</translation>
     </message>
   </context>
   <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>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</translation>
-    </message>
-  </context>
-  <context>
-    <name>Pipe:base_objects:FeaturesPlugin_ValidatorBaseForGeneration</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
+      <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>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</translation>
     </message>
   </context>
   <context>
       <translation>Selected object has empty context.</translation>
     </message>
   </context>
-  <context>
-    <name>Remove_SubShapes:FeaturesPlugin_ValidatorRemoveSubShapesResult</name>
-    <message>
-      <source>Error: Feature \"%1\" does not supported by this validator.</source>
-      <translation>Feature "%1" does not supported validator "FeaturesPlugin_ValidatorRemoveSubShapesResult".</translation>
-    </message>
-  </context>
   <context>
     <name>Remove_SubShapes:FeaturesPlugin_ValidatorRemoveSubShapesResult</name>
     <message>
       <translation></translation>
     </message>
   </context>
-  <context>
-    <name>Remove_SubShapes:base_shape:GeomValidators_BodyShapes</name>
-    <message>
-      <source>Error: Attribute \"%1\" does not supported by this validator.</source>
-      <translation></translation>
-    </message>
-  </context>
   <context>
     <name>Remove_SubShapes:subshapes:FeaturesPlugin_ValidatorRemoveSubShapesSelection</name>
     <message>
     <name>Intersection:tool_objects:GeomValidators_IntersectionSelection</name>
     <message>
       <source>Error: empty feature.</source>
-      <translation>Selected objects has empty feature.</translation>
+      <translation>Selected objects have empty feature.</translation>
     </message>
   </context>
   <context>
       <translation>Objects from the %1 group can be selected in the %2 document, but an objects from the %3 group is selected.</translation>
     </message>
   </context>
-  <context>
-    <name>Union:FeaturesPlugin_ValidatorUnionArguments</name>
-    <message>
-      <source>Error: This validator supports only \"%1\" feature.</source>
-      <translation>This validator "FeaturesPlugin_ValidatorUnionArguments" supports only "%1" feature.</translation>
-    </message>
-  </context>
   <context>
     <name>Union:FeaturesPlugin_ValidatorUnionArguments</name>
     <message>
   <context>
     <name>FusionFaces:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "base_shape" is not initialized.</source >
-      <translation>Base shape is not selected.</translation >
+      <source>Attribute "base_shape" is not initialized.</source>
+      <translation>Base shape is not selected.</translation>
     </message>
   </context>
 </TS>
diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts
new file mode 100644 (file)
index 0000000..c4eb9c4
--- /dev/null
@@ -0,0 +1,6330 @@
+<?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>
+  </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>
+  </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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>AA</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>
+  </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>
+  </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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "center_point" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <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 "to_size" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_size" is not initialized.</source>
+      <translation>AA</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 "from_offset" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_offset" is not initialized.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Extrusion:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 "to_size" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_size" is not initialized.</source>
+      <translation>AA</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 "from_offset" is not initialized.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 "to_angle" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_angle" is not initialized.</source>
+      <translation>AA</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 "from_offset" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "to_offset" is not initialized.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>Revolution:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 "to_angle" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_angle" is not initialized.</source>
+      <translation>AA</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 "from_offset" is not initialized.</source>
+      <translation>AA</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 "to_offset" is not initialized.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionCut:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 "to_size" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_size" is not initialized.</source>
+      <translation>AA</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 "from_offset" is not initialized.</source>
+      <translation>AA</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 "to_offset" is not initialized.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>ExtrusionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 "to_angle" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "from_angle" is not initialized.</source>
+      <translation>AA</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 "from_offset" is not initialized.</source>
+      <translation>AA</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 "to_offset" is not initialized.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:from_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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 face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a face.</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+  <context>
+    <name>RevolutionFuse:to_object:GeomValidators_Face</name>
+    <message>
+      <source>The shape is not a plane.</source>
+      <translation>AA</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_centering" is not initialized.</source>
+      <translation>AA</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>Placement:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "placement_reverse_direction" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "distance" is not initialized.</source>
+      <translation>AA</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>Union:GeomValidators_MinObjectsSelected</name>
+    <message>
+      <source>Error: Attribute "%1" should contain at least %2 items.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_angular" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_first_dir" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "angle_from" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "angle_point_1" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "circular" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "distance_from" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "edge_for_length" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "center_point" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "axis_object" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>AA</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:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "end_point" is not initialized.</source>
+      <translation>AA</translation>
+    </message>
+    <message>
+      <source>Attribute "main_objects" is not initialized.</source>
+      <translation>AA</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>
+  </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>
diff --git a/src/FeaturesPlugin/Test/Test3014.py b/src/FeaturesPlugin/Test/Test3014.py
new file mode 100644 (file)
index 0000000..711b12e
--- /dev/null
@@ -0,0 +1,50 @@
+# 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 GeomAPI import *
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "nb", "10")
+model.addParameter(Part_1_doc, "h", "20")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 55.86212361331221, 9.333219356250011)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.result(), SketchCircle_1.center())
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchCircle_1.results()[1]], SketchAPI_Line(SketchLine_1).startPoint(), 360, "nb", True)
+[SketchCircle_2, SketchCircle_3, SketchCircle_4, SketchCircle_5, SketchCircle_6, SketchCircle_7, SketchCircle_8, SketchCircle_9, SketchCircle_10] = SketchMultiRotation_1.rotated()
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), "h", 0)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Extrusion_1_4/To_Face"), "h/2", True)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("FACE", "Plane_1"), model.selection("COMPOUND", "all-in-Extrusion_1")], 20190506)
+model.end()
+
+assert(Partition_1.feature().error() == "")
+
+model.testNbResults(Partition_1, 1)
+model.testNbSubResults(Partition_1, [10])
+model.testNbSubShapes(Partition_1, GeomAPI_Shape.SOLID, [20])
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusionCut_ByFaces.py b/src/FeaturesPlugin/Test/TestExtrusionCut_ByFaces.py
new file mode 100644 (file)
index 0000000..ef51f27
--- /dev/null
@@ -0,0 +1,150 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(25, 0, 0, 0)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchPoint_1.result())
+SketchLine_2 = Sketch_1.addLine(0, 0, 0, 200)
+SketchLine_3 = Sketch_1.addLine(0, 200, 25, 200)
+SketchLine_3.setAuxiliary(True)
+SketchLine_4 = Sketch_1.addLine(25, 200, 25, 0)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_5 = 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())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 200)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 25)
+SketchLine_5 = Sketch_1.addLine(125, 243.301270189222, -25, 243.3012701892219)
+SketchLine_5.setAuxiliary(True)
+SketchLine_6 = Sketch_1.addLine(-25, 243.3012701892219, 0, 200)
+SketchLine_6.setAuxiliary(True)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_6.endPoint())
+SketchLine_7 = Sketch_1.addLine(0, 200, 0, 350)
+SketchLine_7.setAuxiliary(True)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_7.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_5.result(), SketchLine_7.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_7.result(), SketchLine_6.result(), 30)
+SketchLine_8 = Sketch_1.addLine(-25, 243.3012701892219, 29.37846722219903, 268.6583658936639)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(29.37846722219903, 268.6583658936639, 14.58682806127452, 300.3791384399466)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintPerpendicular_2 = Sketch_1.setPerpendicular(SketchLine_8.result(), SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_6.result(), 50)
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_8.result(), 60)
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_8.result(), 25)
+SketchConstraintLength_5 = Sketch_1.setLength(SketchLine_9.result(), 35)
+SketchLine_10 = Sketch_1.addLine(23.03919329608853, 282.2529826992136, 36.18065620811996, 288.3809474944538)
+SketchLine_10.setAuxiliary(True)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_10.startPoint(), SketchLine_9.result())
+SketchLine_11 = Sketch_1.addLine(36.18065620811996, 288.3809474944538, 48.85920406034094, 261.1917138833543)
+SketchLine_11.setAuxiliary(True)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint())
+SketchConstraintPerpendicular_3 = Sketch_1.setPerpendicular(SketchLine_10.result(), SketchLine_11.result())
+SketchConstraintPerpendicular_4 = Sketch_1.setPerpendicular(SketchLine_9.result(), SketchLine_10.result())
+SketchConstraintLength_6 = Sketch_1.setLength(SketchLine_11.result(), 30)
+SketchConstraintLength_7 = Sketch_1.setLength(SketchLine_10.result(), 14.5)
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_9.endPoint(), SketchLine_10.startPoint(), 20, True)
+SketchArc_1 = Sketch_1.addArc(4.697206021778518, 257.149304782984, 14.58682806127452, 300.3791384399466, 48.85920406034094, 261.1917138833543, True)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchArc_1.endPoint())
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchLine_10.endPoint(), SketchArc_1.results()[1])
+SketchArc_2 = Sketch_1.addArc(0.1512256873309691, 256.7331845326764, 48.85920406034094, 261.1917138833543, 34.14802119649147, 221.5683791690064, True)
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchArc_2.startPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchArc_1.results()[1])
+SketchArc_3 = Sketch_1.addArc(-71.98457930083825, 187.3071972226404, 0, 200, -25, 243.3012701892219, False)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_3.startPoint())
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchArc_3.endPoint())
+SketchLine_12 = Sketch_1.addLine(-25, 243.301270189222, 0, 222.3237794097899)
+SketchLine_12.setAuxiliary(True)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_12.startPoint())
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_12.endPoint(), SketchLine_7.result())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_12.result())
+SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_6.result(), SketchLine_12.result(), 20)
+SketchArc_4 = Sketch_1.addArc(55, 200, 34.14802119649147, 221.5683791690064, 25, 200, False)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchArc_4.startPoint())
+SketchConstraintTangent_3 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchArc_4.results()[1])
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchArc_4.endPoint(), SketchLine_4.startPoint())
+SketchConstraintTangent_4 = Sketch_1.setTangent(SketchLine_4.result(), SketchArc_4.results()[1])
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_4.results()[1], 30)
+SketchLine_13 = Sketch_1.addLine(-7.179200577043265, 240.5774662449659, 15.47849409887298, 251.1429227884834)
+SketchLine_14 = Sketch_1.addLine(15.47849409887298, 251.1429227884834, 26.04395064239047, 228.4852281125672)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_13.endPoint(), SketchLine_14.startPoint())
+SketchLine_15 = Sketch_1.addLine(26.04395064239047, 228.4852281125672, 3.386255966474217, 217.9197715690497)
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchLine_14.endPoint(), SketchLine_15.startPoint())
+SketchLine_16 = Sketch_1.addLine(3.386255966474217, 217.9197715690497, -7.179200577043265, 240.5774662449659)
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchLine_15.endPoint(), SketchLine_16.startPoint())
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchLine_13.startPoint(), SketchLine_16.endPoint())
+SketchConstraintParallel_1 = Sketch_1.setParallel(SketchLine_13.result(), SketchLine_15.result())
+SketchConstraintParallel_2 = Sketch_1.setParallel(SketchLine_16.result(), SketchLine_14.result())
+SketchConstraintPerpendicular_5 = Sketch_1.setPerpendicular(SketchLine_13.result(), SketchLine_14.result())
+SketchConstraintParallel_3 = Sketch_1.setParallel(SketchLine_13.result(), SketchLine_8.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_15.result(), SketchLine_14.result())
+SketchConstraintLength_8 = Sketch_1.setLength(SketchLine_13.result(), 25)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.result(), SketchLine_16.endPoint(), 10, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchArc_3.endPoint(), SketchLine_16.result(), 15, True)
+SketchConstraintLength_9 = Sketch_1.setLength(SketchLine_5.result(), 150)
+SketchConstraintLength_10 = Sketch_1.setLength(SketchLine_7.result(), 150)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchArc_4_2r-SketchArc_2_2f-SketchArc_1_2f-SketchLine_9r-SketchLine_8r-SketchArc_3_2r-SketchLine_2r-SketchLine_1r-SketchLine_13f-SketchLine_14f-SketchLine_15f-SketchLine_16f")], model.selection(), 10, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_14"))
+SketchLine_17 = Sketch_2.addLine(-221.0712923119171, 10, -196.0712923119172, 0)
+SketchLine_17.setAuxiliary(True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_13][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_14][Extrusion_1_1/To_Face]"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_27 = Sketch_2.setCoincident(SketchLine_17.startPoint(), SketchPoint_2.result())
+SketchProjection_3 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_14][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_15][Extrusion_1_1/From_Face]"), False)
+SketchPoint_3 = SketchProjection_3.createdFeature()
+SketchConstraintCoincidence_28 = Sketch_2.setCoincident(SketchLine_17.endPoint(), SketchPoint_3.result())
+SketchCircle_1 = Sketch_2.addCircle(-208.5712923119172, 5, 4)
+SketchConstraintCoincidence_29 = Sketch_2.setCoincident(SketchLine_17.result(), SketchCircle_1.center())
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchCircle_1.center(), SketchLine_17.result())
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_1.results()[1], 4)
+model.do()
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("WIRE", "Sketch_2/Face-SketchCircle_1_2f_wire")], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchArc_3_2"), 0, model.selection(), 5, [model.selection("SOLID", "Extrusion_1_1")])
+model.do()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(ExtrusionCut_1, [78707.15553129233])
+
+model.testHaveNamingSubshapes(ExtrusionCut_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
index c7b08bb94c8f04bb1873e961276a486ebb98f7f8..11dcce3cb271367dfd4c8ca965ca3f68952b9906 100644 (file)
@@ -109,7 +109,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
 model.testResultsVolumes(Extrusion_1, [57985.85])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
@@ -117,7 +117,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
 model.testResultsVolumes(Extrusion_1, [37985.85])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
index a55c34e6d5e845ebcbf66588b067ebb945f3985b..5444ef5c4e679f168463df4c205586cffc2ac5ad 100644 (file)
@@ -99,7 +99,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
 model.testResultsVolumes(Extrusion_1, [107985.85])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
@@ -107,7 +107,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
 model.testResultsVolumes(Extrusion_1, [87985.85])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
index 83608d6edb1a54a111fe1a3e7891e1c36d96f9da..af9a6c6a3868426d91ebb9f4b5d7dae1c3df027c 100644 (file)
@@ -129,7 +129,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [44])
 model.testResultsVolumes(Extrusion_1, [119535.04])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
@@ -137,7 +137,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
 model.testResultsVolumes(Extrusion_1, [84126.377])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
index 7e8a0eb9dd1d21166b6f47640b26513f3c45b0d0..ef7c7113646ddd806d537609c80dbe126da6caee 100644 (file)
@@ -101,7 +101,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [44])
 model.testResultsVolumes(Extrusion_1, [105008.93])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
@@ -110,7 +110,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
 model.testResultsVolumes(Extrusion_1, [179594.5])
 
 # check failure
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 assert(Extrusion_1.feature().error() != "")
 
index fff109f06d48d4d0ac1215572cef5e25402927a0..8715c1ecb4c5b1e8c65aa97b1269484393ac6b04 100644 (file)
@@ -134,7 +134,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
 model.testResultsVolumes(Extrusion_1, [7626.2279286])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -144,7 +144,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [20])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [40])
 model.testResultsVolumes(Extrusion_1, [21514.8965])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index 095c967961856fff1d6bfd0413ebf733773701b4..0fd7070e75f73e5e313700e28d503c3090a87026 100644 (file)
@@ -92,7 +92,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [40])
 model.testResultsVolumes(Extrusion_1, [31501.9671234])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
@@ -100,7 +100,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
 model.testResultsVolumes(Extrusion_1, [18737.752452])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
index 0318fcd138768ccb9cdaf8f3fb93332f67316356..a3bbdee05b24269a138caaafa019b81235b7b698 100644 (file)
@@ -120,7 +120,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [96])
 model.testResultsVolumes(Extrusion_1, [57985.85])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -128,7 +128,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
 model.testResultsVolumes(Extrusion_1, [37985.85])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index 18ce0b44265352e0b8206a3f73444db43dc004a5..72726ad98c03ce06cfba1386d361a592ad4a47cd 100644 (file)
@@ -104,7 +104,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
 model.testResultsVolumes(Extrusion_1, [107985.85])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -112,7 +112,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
 model.testResultsVolumes(Extrusion_1, [87985.85])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index da81086add5b9c72e1b72de71ac58778c6828bbe..ada092a9f12aca369d4399377a2eab28addcb5bc 100644 (file)
@@ -132,7 +132,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [68])
 model.testResultsVolumes(Extrusion_1, [119535.04])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -140,7 +140,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
 model.testResultsVolumes(Extrusion_1, [84126.377])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index e618ca61c61c4ba5b33210dce0731809ec1e5e58..024dd08aa2724944ec52100c2bfa55dd20f31d97 100644 (file)
@@ -105,7 +105,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [80])
 model.testResultsVolumes(Extrusion_1, [105008.93])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -114,7 +114,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [10])
 model.testResultsVolumes(Extrusion_1, [179594.5])
 
 # check failure
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 assert(Extrusion_1.feature().error() != "")
 
index f66471f5b9cad72dce1552144e7b36d3f48c9aff..8156d5230a5c3f2b4200f5870e7cecbdc4d39087 100644 (file)
@@ -139,7 +139,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [128])
 model.testResultsVolumes(Extrusion_1, [7626.2279286])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -149,7 +149,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [68])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [136])
 model.testResultsVolumes(Extrusion_1, [21514.8965])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index 5473797ac507e17448bcabe0548ae9fa7165e448..7cf8233a6857598346ff74c35f6d23eff56e08f5 100644 (file)
@@ -97,7 +97,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [64])
 model.testResultsVolumes(Extrusion_1, [31501.9671234])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -105,7 +105,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
 model.testResultsVolumes(Extrusion_1, [18737.752452])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index 710db14d5cce9819c5c271a818b3db5b72a0a204..3575f1bb70d366715b27f052b1e0853891bd7aa5 100644 (file)
@@ -101,7 +101,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
 model.testResultsVolumes(Extrusion_1, [2899.292521, 1039.2304845, 2899.292521, 1131.3708499])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 4)
 model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
@@ -111,7 +111,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
 model.testResultsVolumes(Extrusion_1, [3899.292521, 1439.2304845, 3899.292521, 1531.3708499])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 4)
 model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
index 7f8348c69a4e7450c1e7a18e4a9351a7f454f386..21789d9a81e9b83a7e1fe2057e2202c85b4c60f1 100644 (file)
@@ -102,7 +102,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
 model.testResultsVolumes(Extrusion_1, [5399.2925211, 2039.2304845, 5399.2925212, 2131.37085])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 4)
 model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
@@ -112,7 +112,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
 model.testResultsVolumes(Extrusion_1, [6399.2925211, 2439.2304845, 6399.2925212, 2531.37085])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 4)
 model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
index a65ebacdabf8e5b2bddc93cfd9bf57057de06286..edb34500c16e653a6933e44133c057c0501d9b98 100644 (file)
@@ -138,7 +138,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
 model.testResultsVolumes(Extrusion_1, [2295.81450653, 2295.81450653, 5527.16645028])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 3)
 model.testNbSubResults(Extrusion_1, [0, 0, 0])
@@ -148,7 +148,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
 model.testResultsVolumes(Extrusion_1, [1595.81450653, 1595.81450653, 3814.47306888])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 3)
 model.testNbSubResults(Extrusion_1, [0, 0, 0])
index bd18ce050afe624ae37f1aea9f085aedf88d4a8f..8436dbc9db9daa39b7254e00074be2ba2ab3a163 100644 (file)
@@ -104,7 +104,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
 model.testResultsVolumes(Extrusion_1, [1708.843326299, 1708.843325768, 1895.559443038])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 3)
 model.testNbSubResults(Extrusion_1, [0, 0, 0])
@@ -115,12 +115,12 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
 model.testResultsVolumes(Extrusion_1, [2915.069101129, 2915.069100598, 4138.27332218])
 
 # check failure
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 assert(Extrusion_1.feature().error() != "")
 
 # revert failure
-ParamFrom.setValue(10)
+ParamFrom.setValue(-10)
 model.do()
 model.testNbResults(Extrusion_1, 3)
 model.testNbSubResults(Extrusion_1, [0, 0, 0])
index fd8effa219c1cca396c582d939c57c50a9477658..3ec3accb85a9f6bd20b3f9ca78ed54d5c964ba3f 100644 (file)
@@ -135,7 +135,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [20])
 model.testResultsVolumes(Extrusion_1, [1504.36096473])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
@@ -145,7 +145,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
 model.testResultsVolumes(Extrusion_1, [4336.142699])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [2])
index 2edfe7af7b373dad7c0677e7512b67d3fb160caf..8e86fe8590596adf84c39340b7188d94a0b269da 100644 (file)
@@ -97,7 +97,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 10])
 model.testResultsVolumes(Extrusion_1, [1314.8586588, 1022.169915122, 2601.32913399])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 3)
 model.testNbSubResults(Extrusion_1, [0, 0, 0])
@@ -105,7 +105,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
 model.testResultsVolumes(Extrusion_1, [825.71966141, 533.030917699, 1551.6191757579])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 3)
 model.testNbSubResults(Extrusion_1, [0, 0, 0])
index 68584bc5c719c5177c89c9088e099b1045f6e8fa..9abd1ca358c22a1dec5231e35c9d9250d9892f48 100644 (file)
@@ -117,7 +117,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
 model.testResultsVolumes(Extrusion_1, [7969.186376787])
 
 # offset "From" face
-ParamFrom.setValue(-20)
+ParamFrom.setValue(20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
@@ -127,7 +127,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
 model.testResultsVolumes(Extrusion_1, [10769.186376787])
 
-ParamFrom.setValue(20)
+ParamFrom.setValue(-20)
 model.do()
 model.testNbResults(Extrusion_1, 1)
 model.testNbSubResults(Extrusion_1, [0])
index 9ea0416c129bde364bfbfe83da2669b62beabb9a..85ca64d7198d8bbaaf203c57c783fe887542df30 100644 (file)
@@ -4,7 +4,7 @@
                    label="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."
+3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it."
                    shape_types="vertices edges wires faces shells solids compsolids compounds">
     <validator id="FeaturesPlugin_ValidatorCompositeLauncher" parameters="base,Sketch"/>
   </sketch_launcher>
index 96079ccbd281a6b1de39bc7de8417fa733c58224..c8561193e7c5879980a62224f52b4d6385c44cf7 100644 (file)
@@ -5,7 +5,7 @@
       label="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."
+3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it."
       shape_types="wires faces shells">
       <validator id="FeaturesPlugin_ValidatorCompositeLauncher" parameters="base,Sketch"/>
     </sketch_launcher>
           </doublevalue>
         </groupbox>
       </box>
-      <box id="ByPlanesAndOffsets" title="By bounding planes and offsets" icon="icons/Features/plane_inverted_32x32.png">
+      <box id="ByPlanesAndOffsets" title="By bounding faces and offsets" icon="icons/Features/plane_inverted_32x32.png">
         <groupbox title="From">
           <shape_selector id="from_object"
                           icon="icons/Features/plane.png"
-                          label="Plane face"
-                          tooltip="Bounding plane (select a planar face)"
+                          label="From face"
+                          tooltip="From face"
                           shape_types="face"
                           geometrical_selection="true"
                           default="&lt;base sketch&gt;">
-            <validator id="GeomValidators_Face" parameters="plane"/>
+            <validator id="FeaturesPlugin_ValidatorExtrusionBoundary"/>
           </shape_selector>
           <doublevalue id="from_offset"
             label="Offset" step="1.0" default="0"
         <groupbox title="To">
           <shape_selector id="to_object"
                           icon="icons/Features/plane_inverted.png"
-                          label="Plane face"
-                          tooltip="Bounding plane (select a planar face)"
+                          label="To face"
+                          tooltip="To face"
                           shape_types="face"
                           geometrical_selection="true"
                           default="&lt;base sketch&gt;">
-            <validator id="GeomValidators_Face" parameters="plane"/>
+            <validator id="FeaturesPlugin_ValidatorExtrusionBoundary"/>
           </shape_selector>
           <doublevalue  id="to_offset"
             label="Offset" step="1.0" default="0"
index 80082d14ec637dc2c0b1ccebc6d0c205ef33dea1..b0c18a5c4d981744eb6f254aadf17ea394058c08 100644 (file)
@@ -5,7 +5,7 @@
       label="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."
+3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it."
       shape_types="vertices edges wires faces shells compounds">
       <validator id="FeaturesPlugin_ValidatorCompositeLauncher" parameters="base,Sketch"/>
     </sketch_launcher>
           </doublevalue>
         </groupbox>
       </box>
-      <box id="ByPlanesAndOffsets" title="By bounding planes and offsets" icon="icons/Features/plane_inverted_32x32.png">
+      <box id="ByPlanesAndOffsets" title="By bounding faces and offsets" icon="icons/Features/plane_inverted_32x32.png">
         <groupbox title="From">
           <shape_selector id="from_object"
                           icon="icons/Features/plane.png"
-                          label="Plane face"
-                          tooltip="Bounding plane (select a planar face)"
+                          label="From face"
+                          tooltip="From face"
                           shape_types="face"
                           geometrical_selection="true"
                           default="&lt;base sketch&gt;">
-            <validator id="GeomValidators_Face" parameters="plane"/>
+            <validator id="FeaturesPlugin_ValidatorExtrusionBoundary"/>
           </shape_selector>
           <doublevalue id="from_offset"
             label="Offset" step="1.0" default="0"
         <groupbox title="To">
           <shape_selector id="to_object"
                           icon="icons/Features/plane_inverted.png"
-                          label="Plane face"
-                          tooltip="Bounding plane (select a planar face)"
+                          label="To face"
+                          tooltip="To face"
                           shape_types="face"
                           geometrical_selection="true"
                           default="&lt;base sketch&gt;">
-            <validator id="GeomValidators_Face" parameters="plane"/>
+            <validator id="FeaturesPlugin_ValidatorExtrusionBoundary"/>
           </shape_selector>
           <doublevalue  id="to_offset"
             label="Offset" step="1.0" default="0"
index 5f09fb238a73758d5fa9c8f5981f0038351fd435..bc07db63046ca749af016817d7f0c361d1938bd4 100644 (file)
@@ -2,7 +2,7 @@
   <multi_selector id="main_objects"
     label="Objects"
     icon="icons/Features/cut_shape.png"
-    tooltip="Select objects(compounds, compsolids, solids, shells, faces or edges)"
+    tooltip="Select objects (compounds, compsolids, solids, shells, faces or edges)"
     shape_types="edges faces shells solids compsolids compounds"
     use_choice="false"
     concealment="true">
index 3f5ca15e748fdbcbd49f64fd0ea604f8404033d5..2b72ece65c13d08d2a8ec6cb15fe89e8ddd85aa0 100644 (file)
@@ -26,7 +26,7 @@
                       default="">
       </shape_selector>
     </box>
-    <box id="Radius" title="Radius of circular" icon="icons/Features/meas_radius_32x32.png">
+    <box id="Radius" title="Radius of circular edge, cylindrical surface or sphere" icon="icons/Features/meas_radius_32x32.png">
       <shape_selector id="circular"
                       icon=""
                       label="Object"
index 8577aa6ee16e06b579843999b700f75372058de7..65c1a1e45998eb49143b4a11e0321efc1f02a32c 100644 (file)
                icon="icons/Features/extrusion.png" helpfile="extrusionFeature.html">
           <source path="extrusion_widget.xml"/>
       </feature>
-      <feature id="ExtrusionCut" title="ExtrusionCut" tooltip=""
+      <feature id="ExtrusionCut" title="ExtrusionCut" tooltip="Cuts an extrusion from a solid"
                icon="icons/Features/extrusion_cut.png" helpfile="extrusionCutFeature.html">
         <source path="extrusioncut_widget.xml"/>
       </feature>
-      <feature id="ExtrusionFuse" title="ExtrusionFuse" tooltip=""
+      <feature id="ExtrusionFuse" title="ExtrusionFuse" tooltip="Fuses an extrusion with a solid"
                icon="icons/Features/extrusion_fuse.png" helpfile="extrusionFuseFeature.html">
         <source path="extrusionfuse_widget.xml"/>
       </feature>
                icon="icons/Features/revol.png" helpfile="revolutionFeature.html">
           <source path="revolution_widget.xml"/>
       </feature>
-      <feature id="RevolutionCut" title="RevolutionCut" tooltip=""
+      <feature id="RevolutionCut" title="RevolutionCut" tooltip="Cuts a revolution from a solid"
                icon="icons/Features/revol_cut.png" helpfile="revolutionCutFeature.html">
         <source path="revolutioncut_widget.xml"/>
       </feature>
-      <feature id="RevolutionFuse" title="RevolutionFuse" tooltip=""
+      <feature id="RevolutionFuse" title="RevolutionFuse" tooltip="Fuses a revolution with a solid"
                icon="icons/Features/revol_fuse.png" helpfile="revolutionFuseFeature.html">
         <source path="revolutionfuse_widget.xml"/>
       </feature>
index 3a641befbb6c73cf46031437a8dcd25caf138169..f69065d75ff8bf58b30eb63d956d1c9a8983d48a 100644 (file)
@@ -4,7 +4,7 @@
                    label="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."
+3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it."
                    shape_types="vertices edges wires faces shells compounds">
     <validator id="FeaturesPlugin_ValidatorCompositeLauncher" parameters="base,Sketch"/>
   </sketch_launcher>
index 217f4fb60896860f2a7ee5aab24059ec9143e19b..a8edd4a49206d282d77dc588b79e750d28886f82 100644 (file)
@@ -5,7 +5,7 @@
       label="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."
+3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it."
       shape_types="wires faces shells">
       <validator id="FeaturesPlugin_ValidatorCompositeLauncher" parameters="base,Sketch"/>
     </sketch_launcher>
index 26c0de8ffec76c7048b3c67048efb259a20b2c8d..7981db76c305aa9751236ff148d9d11e0d4c5e66 100644 (file)
@@ -5,7 +5,7 @@
       label="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."
+3. An existing result shape of kind: wires/edge/vertices. Extrusion will be filled by it."
       shape_types="vertices edges wires faces shells compounds">
       <validator id="FeaturesPlugin_ValidatorCompositeLauncher" parameters="base,Sketch"/>
     </sketch_launcher>
@@ -63,7 +63,7 @@
           <doublevalue id="from_offset" label="Angle"
             step="1.0" default="0"
             icon="icons/Features/angle_up_down.png"
-            tooltip="Angle for &quot;from&quot; for bounding plane">
+            tooltip="Angle for &quot;from&quot; bounding plane">
           </doublevalue>
         </groupbox>
         <groupbox title="To">
index 56ab015a7362fe37d094886783b38a1164553c7c..4c4110155cfe305b7d424d90bc1b9dfd97648cb4 100644 (file)
   }
 }
 
+%typemap(in) double & (double temp) {
+  if (PyLong_Check($input)) {
+    temp = PyLong_AsLong($input);
+    $1 = &temp;
+  }
+}
+
+%typemap(argout) double & {
+  $result = PyFloat_FromDouble(*$1);
+}
+
 
 // all supported interfaces
 %include "GeomAPI_Interface.h"
index 7a86b1e8c410e3e88eb24f06bc2c76febad1d672..45f57fa5a241a7a8b3012b8d0fe7c5f8a8d65b2e 100644 (file)
@@ -406,6 +406,10 @@ bool GeomAPI_AISObject::setDeflection(const double theDeflection)
       if (fabs(aCoefficient-theDeflection) > Precision::Confusion()) {
         isModified = true;
         anAISShape->SetOwnDeviationCoefficient(theDeflection);
+        Handle(Prs3d_Drawer) aDrawer = anAISShape->DynamicHilightAttributes();
+        if (!aDrawer.IsNull()) {
+          aDrawer->SetDeviationCoefficient(theDeflection);
+        }
         // redisplay is necessary here to update presentation in all modes
         // Standard True flag. Displayer uses Standard False flag. If it will be changed in
         // displayer, redisplay here will not be necessary. But performance should be checked.
index facc1ec2a970ac4315c08bbc01f8fa8465e292f3..a3bb8d97a7833ebababfa3a4888bf1bca79b157f 100644 (file)
@@ -58,7 +58,8 @@ GeomAPI_Circ::GeomAPI_Circ(const std::shared_ptr<GeomAPI_Pnt>& theCenter,
 //=================================================================================================
 GeomAPI_Circ::GeomAPI_Circ(const GeomCurvePtr& theCurve)
 {
-  Handle(Geom_Curve) aCurve = theCurve->impl<Handle(Geom_Curve)>();
+  GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve();
+  Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl<Handle(Geom_Curve)>();
   Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve);
   if (aCirc.IsNull())
     throw Standard_ConstructionError("GeomAPI_Circ: Curve is not a circle");
index 5204f25e5ca5def7ac0d599552ca98c73737a5fd..25c2e32f851d9b614c5fb1f9cd31a3e3f8651241 100644 (file)
@@ -54,6 +54,12 @@ static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY,
 }
 
 
+GeomAPI_Circ2d::GeomAPI_Circ2d(const double theCenterX,
+                               const double theCenterY,
+                               const double theRadius)
+  : GeomAPI_Interface(newCirc2d(theCenterX, theCenterY, gp::DX2d(), theRadius))
+{
+}
 
 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
                                const std::shared_ptr<GeomAPI_Pnt2d>& theCirclePoint)
index 479f6edf63feb4963033899e02f46caa74d0774c..efa65b1d35230e7077372c9e62c6e3670508c406 100644 (file)
@@ -35,7 +35,11 @@ class GeomAPI_Shape;
 
 class GeomAPI_Circ2d : public GeomAPI_Interface
 {
- public:
+public:
+  /// Creation of circle defined by center point and circle radius
+  GEOMAPI_EXPORT
+  GeomAPI_Circ2d(const double theCenterX, const double theCenterY, const double theRadius);
+
   /// Creation of circle defined by center point and circle radius
   GEOMAPI_EXPORT
   GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
index 7276c848597b451c2dca046099d894e6b26ac7aa..2ffc946464537d2a2ac5a92a46c5ef42dd23ff9b 100644 (file)
 #include <TopoDS_Shape.hxx>
 #include <Geom_Circle.hxx>
 #include <Geom_Curve.hxx>
+#include <Geom_Ellipse.hxx>
 #include <Geom_Line.hxx>
 #include <Geom_TrimmedCurve.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <BRep_Tool.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS.hxx>
@@ -33,7 +35,9 @@
 #define MY_CURVE (*(implPtr<Handle_Geom_Curve>()))
 
 GeomAPI_Curve::GeomAPI_Curve()
-    : GeomAPI_Interface(new Handle_Geom_Curve()), myStart(0), myEnd(1)
+    : GeomAPI_Interface(new Handle_Geom_Curve()),
+      myStart(-Precision::Infinite()),
+      myEnd(Precision::Infinite())
 {
 }
 
@@ -55,14 +59,53 @@ bool GeomAPI_Curve::isNull() const
   return MY_CURVE.IsNull() == Standard_True;
 }
 
+static bool isCurveType(const Handle(Geom_Curve)& theCurve, const Handle(Standard_Type)& theType)
+{
+  if (theCurve.IsNull())
+    return false;
+  Handle(Geom_Curve) aCurve = theCurve;
+  if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
+    aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
+  return aCurve->DynamicType() == theType;
+}
+
 bool GeomAPI_Curve::isLine() const
 {
-  return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_Line);
+  return isCurveType(MY_CURVE, STANDARD_TYPE(Geom_Line));
 }
 
 bool GeomAPI_Curve::isCircle() const
 {
-  return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_Circle);
+  return isCurveType(MY_CURVE, STANDARD_TYPE(Geom_Circle));
+}
+
+bool GeomAPI_Curve::isEllipse() const
+{
+  return isCurveType(MY_CURVE, STANDARD_TYPE(Geom_Ellipse));
+}
+
+double GeomAPI_Curve::startParam()
+{
+  if (Precision::IsInfinite(myStart)) {
+    if (isTrimmed()) {
+      myStart = Handle(Geom_TrimmedCurve)::DownCast(MY_CURVE)->FirstParameter();
+    }
+    else if (MY_CURVE->IsClosed() && MY_CURVE->IsPeriodic())
+      myStart = 0.0;
+  }
+  return myStart;
+}
+
+double GeomAPI_Curve::endParam()
+{
+  if (Precision::IsInfinite(myEnd)) {
+    if (isTrimmed()) {
+      myEnd = Handle(Geom_TrimmedCurve)::DownCast(MY_CURVE)->LastParameter();
+    }
+    else if (MY_CURVE->IsClosed() && MY_CURVE->IsPeriodic())
+      myEnd = MY_CURVE->Period();
+  }
+  return myEnd;
 }
 
 std::shared_ptr<GeomAPI_Pnt> GeomAPI_Curve::getPoint(double theParam)
@@ -82,8 +125,6 @@ bool GeomAPI_Curve::isTrimmed() const
   return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve);
 }
 
-// unused in the unit tests for now
-// LCOV_EXCL_START
 GeomCurvePtr GeomAPI_Curve::basisCurve() const
 {
   Handle(Geom_Curve) aCurve = MY_CURVE;
@@ -94,7 +135,25 @@ GeomCurvePtr GeomAPI_Curve::basisCurve() const
   aNewCurve->setImpl(new Handle(Geom_Curve)(aCurve));
   return aNewCurve;
 }
-// LCOV_EXCL_STOP
+
+
+const std::shared_ptr<GeomAPI_Pnt> GeomAPI_Curve::project(
+    const std::shared_ptr<GeomAPI_Pnt>& thePoint) const
+{
+  std::shared_ptr<GeomAPI_Pnt> aResult;
+  if (MY_CURVE.IsNull())
+    return aResult;
+
+  const gp_Pnt& aPoint = thePoint->impl<gp_Pnt>();
+
+  GeomAPI_ProjectPointOnCurve aProj(aPoint, MY_CURVE);
+  Standard_Integer aNbPoint = aProj.NbPoints();
+  if (aNbPoint > 0) {
+    gp_Pnt aNearest = aProj.NearestPoint();
+    aResult = GeomPointPtr(new GeomAPI_Pnt(aNearest.X(), aNearest.Y(), aNearest.Z()));
+  }
+  return aResult;
+}
 
 // ================================================================================================
 
index 30b9bd99840b9ebae2cc9637b2f0a055b08e4fd2..3922217f1deb3c0ac52eccabdd75048c6eb35b3b 100644 (file)
@@ -57,13 +57,17 @@ class GeomAPI_Curve : public GeomAPI_Interface
   GEOMAPI_EXPORT
   virtual bool isCircle() const;
 
+  /// Returns whether the curve is elliptic
+  GEOMAPI_EXPORT
+  virtual bool isEllipse() const;
+
   /// Returns start parameter of the curve
   GEOMAPI_EXPORT
-  double startParam() const { return myStart; }
+  double startParam();
 
   /// Returns end parameter of the curve
   GEOMAPI_EXPORT
-  double endParam() const { return myEnd; }
+  double endParam();
 
   /// Returns \c true if the curve is trimmed
   GEOMAPI_EXPORT
@@ -78,6 +82,10 @@ class GeomAPI_Curve : public GeomAPI_Interface
   GEOMAPI_EXPORT
   std::shared_ptr<GeomAPI_Pnt> getPoint(double theParam);
 
+  /// Project point on curve
+  GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt> project(
+      const std::shared_ptr<GeomAPI_Pnt>& thePoint) const;
+
 public:
   /// \brief Compare addresses of curves
   class Comparator
index c525e8c3fc2a86e691d352b38d155c553db87e8b..1b7a0d35d0416ff7f1dda68865735a03d6c6bbe0 100644 (file)
@@ -66,5 +66,8 @@ class GeomAPI_Dir2d : public GeomAPI_Interface
   double angle(const std::shared_ptr<GeomAPI_Dir2d>& theArg) const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Dir2d> GeomDir2dPtr;
+
 #endif
 
index c9384724ac380a8ea90abedfbdb278e172b37652..75a25477cf7474d90e148a6f8412a52696d697a8 100644 (file)
 
 #include "GeomAPI_Ellipse.h"
 #include "GeomAPI_Ax2.h"
+#include "GeomAPI_Curve.h"
 #include "GeomAPI_Pnt.h"
 
+#include <Geom_Ellipse.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
 #include <gp_Elips.hxx>
 
 #define MY_ELIPS implPtr<gp_Elips>()
@@ -35,6 +39,16 @@ GeomAPI_Ellipse::GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
 {
 }
 
+GeomAPI_Ellipse::GeomAPI_Ellipse(GeomCurvePtr theCurve)
+{
+  GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve();
+  Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl<Handle(Geom_Curve)>();
+  Handle(Geom_Ellipse) anEllipse = Handle(Geom_Ellipse)::DownCast(aCurve);
+  if (anEllipse.IsNull())
+    throw Standard_ConstructionError("GeomAPI_Ellipse: Curve is not an ellipse");
+  setImpl(new gp_Elips(anEllipse->Elips()));
+}
+
 std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::center() const
 {
   const gp_Pnt& aCenter = MY_ELIPS->Location();
@@ -69,3 +83,32 @@ double GeomAPI_Ellipse::majorRadius() const
 {
   return MY_ELIPS->MajorRadius();
 }
+
+const std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::project(
+    const std::shared_ptr<GeomAPI_Pnt>& thePoint) const
+{
+  std::shared_ptr<GeomAPI_Pnt> aResult;
+  if (!MY_ELIPS)
+    return aResult;
+
+  Handle(Geom_Ellipse) aEllipse = new Geom_Ellipse(*MY_ELIPS);
+
+  const gp_Pnt& aPoint = thePoint->impl<gp_Pnt>();
+
+  GeomAPI_ProjectPointOnCurve aProj(aPoint, aEllipse);
+  Standard_Integer aNbPoint = aProj.NbPoints();
+  if (aNbPoint > 0) {
+    gp_Pnt aNearest = aProj.NearestPoint();
+    aResult = GeomPointPtr(new GeomAPI_Pnt(aNearest.X(), aNearest.Y(), aNearest.Z()));
+  }
+  return aResult;
+}
+
+const bool GeomAPI_Ellipse::parameter(const std::shared_ptr<GeomAPI_Pnt> thePoint,
+                                      const double theTolerance,
+                                      double& theParameter) const
+{
+  Handle(Geom_Ellipse) aCurve = new Geom_Ellipse(*MY_ELIPS);
+  return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt>(),
+                                 theTolerance, theParameter) == Standard_True;
+}
index ac63dd97ec3bfb80d8f60cef0af4512d0a53898a..9f1be781af3dea9784c609ebe2acef484e164b5e 100644 (file)
@@ -28,6 +28,7 @@
 #include <memory>
 
 class GeomAPI_Ax2;
+class GeomAPI_Curve;
 class GeomAPI_Dir;
 class GeomAPI_Pnt;
 
@@ -53,6 +54,8 @@ public:
   GEOMAPI_EXPORT GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
                                  double theMajorRadius, double theMinorRadius);
 
+  GEOMAPI_EXPORT GeomAPI_Ellipse(std::shared_ptr<GeomAPI_Curve> theCurve);
+
   /// Returns center of the ellipse
   GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> center() const;
 
@@ -71,6 +74,22 @@ public:
   /// Returns major radius of the ellipse
   GEOMAPI_EXPORT double majorRadius() const;
 
+  /// Project point on ellipse
+  GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt> project(
+      const std::shared_ptr<GeomAPI_Pnt>& thePoint) const;
+
+  /** \brief Computes the parameter of a given point on an ellipse. The point must be
+   *         located either on the circle itself or relatively to the latter
+   *         at a distance less than the tolerance value. Return FALSE if the point
+   *         is beyond the tolerance limit or if computation fails.
+   *         Max Tolerance value is currently limited to 1.e-4
+   *  \param[in]  thePoint point of origin.
+   *  \param[in]  theTolerance tolerance of computation.
+   *  \param[out] theParameter resulting parameter.
+   */
+  GEOMAPI_EXPORT const bool parameter(const std::shared_ptr<GeomAPI_Pnt> thePoint,
+                                      const double theTolerance,
+                                      double& theParameter) const;
 };
 
 //! Pointer on the object
index 20338230448d0cc057133aa0b7b643e9a6658cc9..e10765c7890877ea02ecafd7a9c1c96d80f86b9d 100644 (file)
 // Author:      Artem ZHIDKOV
 
 #include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Circ2d.h>
 #include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Lin2d.h>
 #include <GeomAPI_Pnt2d.h>
 
+#include <Extrema_ExtCC2d.hxx>
+#include <Extrema_ExtElC2d.hxx>
+#include <Geom2d_Ellipse.hxx>
+#include <Geom2dAdaptor_Curve.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
 #include <gp_Ax22d.hxx>
 #include <gp_Elips2d.hxx>
+#include <IntAna2d_AnaIntersection.hxx>
+#include <IntAna2d_Conic.hxx>
 #include <Precision.hxx>
 
 #define MY_ELLIPSE implPtr<gp_Elips2d>()
@@ -112,3 +122,116 @@ double GeomAPI_Ellipse2d::majorRadius() const
 {
   return MY_ELLIPSE->MajorRadius();
 }
+
+// theArrangePoint is used to select the nearest solution point if intersection is detected
+template <typename EXTREMAPTR>
+static double extrema(IntAna2d_AnaIntersection* theIntersectionAlgo,
+                      EXTREMAPTR theExtremaAlgo,
+                      GeomPnt2dPtr theArrangePoint,
+                      GeomPnt2dPtr& thePoint1,
+                      GeomPnt2dPtr& thePoint2)
+{
+  double aDistance = Precision::Infinite();
+  if (theIntersectionAlgo->IsDone() && theIntersectionAlgo->NbPoints() > 0) {
+    gp_Pnt2d anArrangePoint(theArrangePoint->x(), theArrangePoint->y());
+    gp_Pnt2d anInterPnt = theIntersectionAlgo->Point(1).Value();
+    aDistance = anArrangePoint.SquareDistance(anInterPnt);
+    int aNbMergedPoints = 1;
+    // get solution nearest to theArrangePoint,
+    // if there are several point near each other, calculate average coordinates
+    for (int i = 2; i <= theIntersectionAlgo->NbPoints(); ++i) {
+      const IntAna2d_IntPoint& aPnt = theIntersectionAlgo->Point(i);
+      double aSqDist = aPnt.Value().SquareDistance(anArrangePoint);
+      if (aSqDist - aDistance < -Precision::Confusion() * aDistance) {
+        aDistance = aSqDist;
+        anInterPnt = aPnt.Value();
+        aNbMergedPoints = 1;
+      } else if (aSqDist - aDistance < Precision::Confusion() * aDistance) {
+        anInterPnt.ChangeCoord() =
+            (anInterPnt.XY() * aNbMergedPoints + aPnt.Value().XY()) / (aNbMergedPoints + 1);
+        ++aNbMergedPoints;
+      }
+    }
+
+    aDistance = 0.0; // curves are intersected
+    thePoint1 = GeomPnt2dPtr(new GeomAPI_Pnt2d(anInterPnt.X(), anInterPnt.Y()));
+    thePoint2 = GeomPnt2dPtr(new GeomAPI_Pnt2d(anInterPnt.X(), anInterPnt.Y()));
+  }
+  else if (theExtremaAlgo->IsDone() && theExtremaAlgo->NbExt() > 0) {
+    Extrema_POnCurv2d aP1, aP2;
+    for (int i = 1; i <= theExtremaAlgo->NbExt(); ++i) {
+      double aSqDist = theExtremaAlgo->SquareDistance(i);
+      if (aSqDist < aDistance) {
+        aDistance = aSqDist;
+        theExtremaAlgo->Points(i, aP1, aP2);
+      }
+    }
+    aDistance = Sqrt(aDistance);
+    thePoint1 = GeomPnt2dPtr(new GeomAPI_Pnt2d(aP1.Value().X(), aP1.Value().Y()));
+    thePoint2 = GeomPnt2dPtr(new GeomAPI_Pnt2d(aP2.Value().X(), aP2.Value().Y()));
+  }
+  return aDistance;
+}
+
+double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Lin2d>& theLine,
+                                   std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+                                   std::shared_ptr<GeomAPI_Pnt2d>& thePointOnLine)
+{
+  IntAna2d_AnaIntersection anInter(theLine->impl<gp_Lin2d>(), IntAna2d_Conic(*MY_ELLIPSE));
+  Extrema_ExtElC2d anExtema(theLine->impl<gp_Lin2d>(), *MY_ELLIPSE);
+  return extrema(&anInter, &anExtema, theLine->location(), thePointOnLine, thePointOnMe);
+}
+
+double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Circ2d>& theCircle,
+                                   std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+                                   std::shared_ptr<GeomAPI_Pnt2d>& thePointOnCircle)
+{
+  IntAna2d_AnaIntersection anInter(theCircle->impl<gp_Circ2d>(), IntAna2d_Conic(*MY_ELLIPSE));
+  Extrema_ExtElC2d anExtema(theCircle->impl<gp_Circ2d>(), *MY_ELLIPSE);
+  return extrema(&anInter, &anExtema, firstFocus(), thePointOnCircle, thePointOnMe);
+}
+
+double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Ellipse2d>& theEllipse,
+                                   std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+                                   std::shared_ptr<GeomAPI_Pnt2d>& thePointOnEllipse)
+{
+  Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(theEllipse->impl<gp_Elips2d>());
+  Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(*MY_ELLIPSE);
+
+  IntAna2d_AnaIntersection anInter(theEllipse->impl<gp_Elips2d>(), IntAna2d_Conic(*MY_ELLIPSE));
+  Extrema_ExtCC2d* anExtema =
+      new Extrema_ExtCC2d(Geom2dAdaptor_Curve(anEllipse1), Geom2dAdaptor_Curve(anEllipse2));
+  double aDistance = extrema(&anInter, anExtema, theEllipse->firstFocus(),
+                             thePointOnEllipse, thePointOnMe);
+  delete anExtema;
+  return aDistance;
+}
+
+const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::project(
+    const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aResult;
+  if (!MY_ELLIPSE)
+    return aResult;
+
+  Handle(Geom2d_Ellipse) aEllipse = new Geom2d_Ellipse(*MY_ELLIPSE);
+
+  const gp_Pnt2d& aPoint = thePoint->impl<gp_Pnt2d>();
+
+  Geom2dAPI_ProjectPointOnCurve aProj(aPoint, aEllipse);
+  Standard_Integer aNbPoint = aProj.NbPoints();
+  if (aNbPoint > 0) {
+    gp_Pnt2d aNearest = aProj.NearestPoint();
+    aResult.reset(new GeomAPI_Pnt2d(aNearest.X(), aNearest.Y()));
+  }
+  return aResult;
+}
+
+const bool GeomAPI_Ellipse2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+                                        const double theTolerance,
+                                        double& theParameter) const
+{
+  Handle(Geom2d_Ellipse) aCurve = new Geom2d_Ellipse(*MY_ELLIPSE);
+  return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt2d>(),
+                                 theTolerance, theParameter) == Standard_True;
+}
index 11c11f93492a49c0e8827d3b0dbb6c0542f43c7b..7772abbf15b2b396ef864b0c655626969f265a92 100644 (file)
 
 #include <GeomAPI_Interface.h>
 
-class GeomAPI_Pnt2d;
+class GeomAPI_Circ2d;
 class GeomAPI_Dir2d;
+class GeomAPI_Lin2d;
+class GeomAPI_Pnt2d;
 
 /**\class GeomAPI_Ellipse2d
  * \ingroup DataModel
@@ -63,6 +65,41 @@ public:
 
   /// Returns major radius of the ellipse
   GEOMAPI_EXPORT double majorRadius() const;
+
+  /// Project point on ellipse
+  GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt2d> project(
+      const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const;
+
+  /** \brief Computes the parameter of a given point on an ellipse. The point must be
+   *         located either on the circle itself or relatively to the latter
+   *         at a distance less than the tolerance value. Return FALSE if the point
+   *         is beyond the tolerance limit or if computation fails.
+   *         Max Tolerance value is currently limited to 1.e-4
+   *  \param[in]  thePoint point of origin.
+   *  \param[in]  theTolerance tolerance of computation.
+   *  \param[out] theParameter resulting parameter.
+   */
+  GEOMAPI_EXPORT const bool parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+                                      const double theTolerance,
+                                      double& theParameter) const;
+
+  /// Calculate minimal distance between the ellipse and a line.
+  /// Return corresponding points on the ellipse and on the line.
+  GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Lin2d>& theLine,
+                                 std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+                                 std::shared_ptr<GeomAPI_Pnt2d>& thePointOnLine);
+
+  /// Calculate minimal distance between the ellipse and a circle.
+  /// Return corresponding points on the ellipse and on the circle.
+  GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Circ2d>& theCircle,
+                                 std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+                                 std::shared_ptr<GeomAPI_Pnt2d>& thePointOnCircle);
+
+  /// Calculate minimal distance between two ellipses.
+  /// Return corresponding points on the ellipses.
+  GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Ellipse2d>& theEllipse,
+                                 std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+                                 std::shared_ptr<GeomAPI_Pnt2d>& thePointOnEllipse);
 };
 
 #endif
index bb907330c08eb1fd1b2ccea4d2451a8ad2865d99..4af6f9fb10db5a3749e0c9242a87c7bf34be3d87 100644 (file)
@@ -37,6 +37,8 @@
 #include <Geom_SphericalSurface.hxx>
 #include <Geom_ConicalSurface.hxx>
 #include <Geom_CylindricalSurface.hxx>
+#include <Geom_OffsetSurface.hxx>
+#include <Geom_Plane.hxx>
 #include <Geom_RectangularTrimmedSurface.hxx>
 #include <Geom_SweptSurface.hxx>
 #include <Geom_ToroidalSurface.hxx>
@@ -203,20 +205,35 @@ std::shared_ptr<GeomAPI_Pln> GeomAPI_Face::getPlane() const
   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
   if (aSurf.IsNull())
     return aResult;  // no surface
-  GeomLib_IsPlanarSurface isPlanar(aSurf);
-  if(!isPlanar.IsPlanar()) {
-    return aResult;
+  GeomLib_IsPlanarSurface isPlanarSurf(aSurf);
+  gp_Pln aPln;
+  bool isPlanar = false;
+  if (isPlanarSurf.IsPlanar()) {
+    aPln = isPlanarSurf.Plan();
+    isPlanar = true;
   }
-  gp_Pln aPln = isPlanar.Plan();
-  double aA, aB, aC, aD;
-  aPln.Coefficients(aA, aB, aC, aD);
-  if (aFace.Orientation() == TopAbs_REVERSED) {
-    aA = -aA;
-    aB = -aB;
-    aC = -aC;
-    aD = -aD;
+  else if (aSurf->IsKind(STANDARD_TYPE(Geom_OffsetSurface))) {
+    Handle(Geom_OffsetSurface) anOffsetSurf = Handle(Geom_OffsetSurface)::DownCast(aSurf);
+    Handle(Geom_Surface) aBasisSurf = anOffsetSurf->BasisSurface();
+    if (aBasisSurf->IsKind(STANDARD_TYPE(Geom_Plane))) {
+      aPln = Handle(Geom_Plane)::DownCast(aBasisSurf)->Pln();
+      gp_Vec aTranslation(aPln.Axis().Direction().XYZ() * anOffsetSurf->Offset());
+      aPln.Translate(aTranslation);
+      isPlanar = true;
+    }
+  }
+
+  if (isPlanar) {
+    double aA, aB, aC, aD;
+    aPln.Coefficients(aA, aB, aC, aD);
+    if (aFace.Orientation() == TopAbs_REVERSED) {
+      aA = -aA;
+      aB = -aB;
+      aC = -aC;
+      aD = -aD;
+    }
+    aResult = std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(aA, aB, aC, aD));
   }
-  aResult = std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(aA, aB, aC, aD));
   return aResult;
 }
 
index 3fdda3048163340b611f9800183732be0c186845..725c28f1f09103db7cc48c6059e32de340cf6e3f 100644 (file)
@@ -76,5 +76,9 @@ class GeomAPI_Lin2d : public GeomAPI_Interface
   std::shared_ptr<GeomAPI_Pnt2d> shiftedLocation(double theShift) const;
 };
 
+
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Lin2d> GeomLine2dPtr;
+
 #endif
 
index e80d9cf2928f39abc3ec85bded664a2426df79d1..235851975d320db4ffd4596b5215e1af2ee011b9 100644 (file)
@@ -142,6 +142,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_Offset.cpp
     GeomAlgoAPI_SolidClassifier.cpp
     GeomAlgoAPI_MapShapesAndAncestors.cpp
+    GeomAlgoAPI_Projection.cpp
     GeomAlgoAPI_Chamfer.cpp
 )
 
index 232a0d690d894f03d646a36bc8212a881b5b2931..5b20ddb137911d80a46a9c34f108658772d063fc 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <BRep_Tool.hxx>
 #include <ElCLib.hxx>
+#include <GccAna_Circ2d2TanOn.hxx>
 #include <GccAna_Circ2d2TanRad.hxx>
 #include <GccAna_Circ2d3Tan.hxx>
 #include <GccAna_Circ2dTanCen.hxx>
@@ -48,6 +49,7 @@ typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> >  VectorOfGccLine;
 // Provide different mechanisms to create circle:
 // * by passing points
 // * by tangent edges
+// * by transversal line
 // * with specified radius
 // * etc.
 class CircleBuilder
@@ -83,6 +85,19 @@ public:
     }
   }
 
+  void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theLine)
+  {
+    if (!theLine)
+      return;
+
+    const TopoDS_Edge& anEdge = TopoDS::Edge(theLine->impl<TopoDS_Shape>());
+
+    double aFirst, aLast;
+    TopLoc_Location aLoc;
+    Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
+    myTransversalLine = CurveAdaptorPtr(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
+  }
+
   void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
   {
     std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
@@ -115,9 +130,13 @@ public:
       case 1:
         aResult = circleByPointAndTwoTangentCurves();
         break;
-      case 2:
-        aResult = circleByTwoPointsAndTangentCurve();
+      case 2: {
+        if (myTransversalLine)
+          aResult = circleByTwoPointsAndTransversalLine();
+        else
+          aResult = circleByTwoPointsAndTangentCurve();
         break;
+      }
       case 3:
         aResult = circleByThreePassingPoints();
         break;
@@ -342,6 +361,22 @@ private:
   }
 
 
+  Circ2dPtr circleByTwoPointsAndTransversalLine()
+  {
+    const gp_Pnt2d& aPoint1 = myPassingPoints[0];
+    const gp_Pnt2d& aPoint2 = myPassingPoints[1];
+
+    if (myTransversalLine && myTransversalLine->GetType() == GeomAbs_Line) {
+      GccAna_Circ2d2TanOn aCircleBuilder(aPoint1, aPoint2, myTransversalLine->Line(),
+                                         Precision::Confusion());
+      if (aCircleBuilder.NbSolutions() > 0)
+        return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
+    }
+
+    return Circ2dPtr();
+  }
+
+
   Circ2dPtr circleByRadiusAndTwoTangentCurves()
   {
     VectorOfGccCirc aTgCirc;
@@ -467,6 +502,7 @@ private:
   std::shared_ptr<GeomAPI_Pnt2d> myCenter;
   std::vector<gp_Pnt2d> myPassingPoints;
   std::vector<CurveAdaptorPtr> myTangentShapes;
+  CurveAdaptorPtr myTransversalLine;
   double myRadius;
   std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
 };
@@ -497,6 +533,12 @@ void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Sh
     myTangentShapes.push_back(theEdge);
 }
 
+void GeomAlgoAPI_Circ2dBuilder::setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge)
+{
+  if (theEdge->isEdge())
+    myTransversalLine = theEdge;
+}
+
 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
 {
   myPassingPoints.push_back(thePoint);
@@ -526,6 +568,7 @@ std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
   CircleBuilder aCircleBuilder(myPlane);
   aCircleBuilder.setCenter(myCenter);
   aCircleBuilder.setTangentCurves(myTangentShapes);
+  aCircleBuilder.setTransversalLine(myTransversalLine);
   aCircleBuilder.setPassingPoints(myPassingPoints);
   aCircleBuilder.setClosestPoint(myClosestPoint);
   aCircleBuilder.setRadius(myRadius);
index c193e877dc8314128d221bfc8d15b219bb021ca6..3105b504795cef29c875f33dd4b1652dec91157a 100644 (file)
@@ -58,6 +58,10 @@ public:
   GEOMALGOAPI_EXPORT
   void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge);
 
+  /// \brief Constrain circle to be orthogonal to the given edge
+  GEOMALGOAPI_EXPORT
+  void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge);
+
   /// \brief Constrain circle to pass through the given point
   GEOMALGOAPI_EXPORT
   void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
@@ -82,6 +86,7 @@ private:
   std::shared_ptr<GeomAPI_Pnt2d>                myCenter;
   std::vector< std::shared_ptr<GeomAPI_Pnt2d> > myPassingPoints;
   std::vector< std::shared_ptr<GeomAPI_Shape> > myTangentShapes;
+  std::shared_ptr<GeomAPI_Shape>                myTransversalLine;
   std::shared_ptr<GeomAPI_Pnt2d>                myClosestPoint;
   double                                        myRadius;
 };
index 85828425c2aaee9eb5e56004d8c001554101eb30..9bfc1a50a20364ac3d8c4af28ca2c23fb34d9bd8 100644 (file)
 //
 
 #include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Ax2.h>
+#include <GeomAPI_Ellipse.h>
+
 #include <gp_Pln.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <TopoDS_Edge.hxx>
@@ -236,3 +240,29 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipse(
   aRes->setImpl(new TopoDS_Shape(anEdge));
   return aRes;
 }
+
+std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipticArc(
+    const std::shared_ptr<GeomAPI_Pnt>& theCenter,
+    const std::shared_ptr<GeomAPI_Dir>& theNormal,
+    const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
+    const double                        theMajorRadius,
+    const double                        theMinorRadius,
+    const std::shared_ptr<GeomAPI_Pnt>& theStart,
+    const std::shared_ptr<GeomAPI_Pnt>& theEnd)
+{
+  std::shared_ptr<GeomAPI_Ax2> anAx2(new GeomAPI_Ax2(theCenter, theNormal, theMajorAxis));
+  GeomAPI_Ellipse anEllipse(anAx2, theMajorRadius, theMinorRadius);
+
+  GeomPointPtr aStartPnt = anEllipse.project(theStart);
+  GeomPointPtr aEndPnt   = anEllipse.project(theEnd);
+
+  double aStartParam, aEndParam;
+  anEllipse.parameter(aStartPnt, Precision::Confusion(), aStartParam);
+  anEllipse.parameter(aEndPnt, Precision::Confusion(), aEndParam);
+
+  BRepBuilderAPI_MakeEdge anEdgeBuilder(anEllipse.impl<gp_Elips>(), aStartParam, aEndParam);
+  GeomEdgePtr aRes(new GeomAPI_Edge);
+  TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+  aRes->setImpl(new TopoDS_Shape(anEdge));
+  return aRes;
+}
index 259800972bc6c6de42395a7c5d40a69ae1e0d67f..245e97f05888c0795f2d21e37dde3f242ae10e05 100644 (file)
@@ -78,6 +78,17 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder
                                                const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
                                                const double                        theMajorRadius,
                                                const double                        theMinorRadius);
+
+
+  /// Creates elliptic edge
+  static std::shared_ptr<GeomAPI_Edge> ellipticArc(
+      const std::shared_ptr<GeomAPI_Pnt>& theCenter,
+      const std::shared_ptr<GeomAPI_Dir>& theNormal,
+      const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
+      const double                        theMajorRadius,
+      const double                        theMinorRadius,
+      const std::shared_ptr<GeomAPI_Pnt>& theStart,
+      const std::shared_ptr<GeomAPI_Pnt>& theEnd);
 };
 
 #endif
index ea80a97b4f50de6f4d3aa8dabbba2238a14ab305..e0db348e7d48b23b3c264f80e9460562891912f4 100644 (file)
@@ -81,6 +81,7 @@ void GeomAlgoAPI_Intersection::build(const ListOfShape& theObjects)
   anOperation->SetCheckInverted(true);
 
   anOperation->PerformWithFiller(*aDSFiller); // it references a filler fields, so keep the filler
+  myFiller = 0;
   if(anOperation->HasErrors()) {
     return;
   }
index cc1ff67b2f6b7e041338607ae48be3c40c1048fb..a4b9d1b3fff9c305a2ea991104a2d958db53a6b7 100644 (file)
@@ -537,7 +537,7 @@ void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr             theBaseShape
   gp_Vec anExtVec = theDirection->impl<gp_Dir>();
 
   // Moving prism bounding faces according to "from" and "to" sizes.
-  GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, theFromSize, theDirection, *this);
+  GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, -theFromSize, theDirection, *this);
   GeomShapePtr aBoundingToShape   = buildOffset(theToShape, theToSize, theDirection, *this);
 
   // Bounding box for shapes used in prism building.
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp
new file mode 100644 (file)
index 0000000..e85b925
--- /dev/null
@@ -0,0 +1,67 @@
+// 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
+//
+
+#include <GeomAlgoAPI_Projection.h>
+
+#include <GeomAPI_Curve.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pln.h>
+
+#include <Geom_Curve.hxx>
+#include <Geom_Plane.hxx>
+#include <GeomProjLib.hxx>
+
+#include <BRep_Tool.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+
+GeomAlgoAPI_Projection::GeomAlgoAPI_Projection(const GeomPlanePtr& thePlane)
+  : myPlane(thePlane)
+{
+}
+
+GeomCurvePtr GeomAlgoAPI_Projection::project(const GeomCurvePtr& theCurve)
+{
+  Handle(Geom_Curve) aCurve = theCurve->impl<Handle_Geom_Curve>();
+  Handle(Geom_Plane) aPlane = new Geom_Plane(myPlane->impl<gp_Ax3>());
+
+  Handle(Geom_Curve) aProj = GeomProjLib::Project(aCurve, aPlane);
+
+  GeomCurvePtr aProjCurve(new GeomAPI_Curve);
+  aProjCurve->setImpl(new Handle_Geom_Curve(aProj));
+  return aProjCurve;
+}
+
+GeomCurvePtr GeomAlgoAPI_Projection::project(const GeomEdgePtr& theEdge)
+{
+  GeomCurvePtr aCurve(new GeomAPI_Curve);
+
+  const TopoDS_Shape& aShape = theEdge->impl<TopoDS_Shape>();
+  TopoDS_Edge anEdge = TopoDS::Edge(aShape);
+  if (!anEdge.IsNull()) {
+    double aStart, aEnd;
+    Handle(Geom_Curve) anEdgeCurve = BRep_Tool::Curve(anEdge, aStart, aEnd);
+    if (!anEdgeCurve.IsNull() && !BRep_Tool::IsClosed(anEdge))
+      anEdgeCurve = new Geom_TrimmedCurve(anEdgeCurve, aStart, aEnd);
+    aCurve->setImpl(new Handle_Geom_Curve(anEdgeCurve));
+  }
+
+  return project(aCurve);
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Projection.h b/src/GeomAlgoAPI/GeomAlgoAPI_Projection.h
new file mode 100644 (file)
index 0000000..4aeca66
--- /dev/null
@@ -0,0 +1,52 @@
+// 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
+//
+
+#ifndef GeomAlgoAPI_Projection_H_
+#define GeomAlgoAPI_Projection_H_
+
+#include <GeomAlgoAPI.h>
+
+#include <GeomAPI_Pln.h>
+
+#include <memory>
+
+class GeomAPI_Curve;
+class GeomAPI_Edge;
+
+/**\class GeomAlgoAPI_Projection
+ * \ingroup DataAlgo
+ * \brief Project curve onto a plane
+ */
+class GeomAlgoAPI_Projection
+{
+public:
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Projection(const std::shared_ptr<GeomAPI_Pln>& thePlane);
+
+  /// Project curve to the plane
+  GEOMALGOAPI_EXPORT
+  std::shared_ptr<GeomAPI_Curve> project(const std::shared_ptr<GeomAPI_Curve>& theCurve);
+  /// Project edge to the plane
+  GEOMALGOAPI_EXPORT
+  std::shared_ptr<GeomAPI_Curve> project(const std::shared_ptr<GeomAPI_Edge>& theEdge);
+
+private:
+  std::shared_ptr<GeomAPI_Pln> myPlane;
+};
+
+#endif
index 22abe96f8768d12b2911a9d1c20898b3760b75f0..9f0983fe25e56aa9f236d88d5aa421f96548ed34 100644 (file)
@@ -67,7 +67,14 @@ bool XAOExport(const std::string& theFileName,
   }
 
   try {
+    XAO::BrepGeometry* aGeometry = dynamic_cast<XAO::BrepGeometry*>(theXao->getGeometry());
+    TopoDS_Shape aShape = aGeometry->getTopoDS_Shape();
+    bool aWasFree = aShape.Free(); // make top level topology free, same as imported
+    if (!aWasFree)
+      aShape.Free(Standard_True);
     XAO::XaoExporter::saveToFile(theXao, theFileName, "");
+    if (!aWasFree)
+      aShape.Free(Standard_False);
   } catch (XAO::XAO_Exception& e) {
     theError = e.what();
     return false;
index 0b42176575ff4433a1d44ad162c306dc54e06ff0..411a1a21ef59acb0b5a9dd70aa43e1778fda1887 100644 (file)
@@ -41,7 +41,7 @@ bool GeomValidators_ZeroOffset::isValid(const std::shared_ptr<ModelAPI_Feature>&
 {
 // LCOV_EXCL_START
   if(theArguments.size() != 9) {
-    theError = "Wrong number of validator arguments in xml(expected 9).";
+    theError = "Wrong number of validator arguments in xml (expected 9).";
     return false;
   }
 // LCOV_EXCL_STOP
index 3ee8a25dec8776e40f3ef32a561e20ec95510fea..3ee99ee6af12816746d0d9833473e54c1333b34b 100644 (file)
@@ -39,7 +39,7 @@ int Model_AttributeIntArray::size()
     myIsInitialized = myLab.FindAttribute(TDataStd_IntegerArray::GetID(), myArray) == Standard_True;
   }
   // checking the validity because attribute (as a field) may be presented,
-  // but without label: it is undoed
+  // but without label: it is undone
   return (myArray.IsNull() || !myArray->IsValid()) ? 0 : myArray->Length();
 }
 
@@ -52,7 +52,7 @@ void Model_AttributeIntArray::setSize(const int theSize)
     }
   } else { // reset the old array
     if (theSize) {
-      if (theSize != myArray->Length()) { // old data is not keept, a new array is created
+      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);
index ff194dac58e821903d20d866074e6cb6efb238ad..c985315b41dff61020b9533ef23bc5452e840e85 100644 (file)
@@ -69,6 +69,7 @@
 #include <TDF_ChildIDIterator.hxx>
 #include <Geom_Circle.hxx>
 #include <Geom_Ellipse.hxx>
+#include <Geom_TrimmedCurve.hxx>
 #include <BRep_Builder.hxx>
 
 //#define DEB_NAMING 1
@@ -259,7 +260,7 @@ void Model_AttributeSelection::removeTemporaryValues()
   }
 }
 
-// returns the center of the edge: circular or elliptical
+// returns the center of the edge: circular or elliptic
 GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::CenterType theType)
 {
   if (theType != ModelAPI_AttributeSelection::NOT_CENTER && theEdge.get() != NULL) {
@@ -272,11 +273,15 @@ GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::Cen
         TopoDS_Vertex aVertex;
         BRep_Builder aBuilder;
         if (theType == ModelAPI_AttributeSelection::CIRCLE_CENTER) {
+          while(!aCurve.IsNull() && aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
+            aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
           Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve);
           if (!aCirc.IsNull()) {
             aBuilder.MakeVertex(aVertex, aCirc->Location(), Precision::Confusion());
           }
         } else { // ellipse
+          while(!aCurve.IsNull() && aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
+            aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
           Handle(Geom_Ellipse) anEll = Handle(Geom_Ellipse)::DownCast(aCurve);
           if (!anEll.IsNull()) {
             aBuilder.MakeVertex(aVertex,
@@ -780,14 +785,13 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
   if (aCont->groupName() == ModelAPI_ResultPart::group()) {
     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aCont);
     int anIndex;
-    GeomShapePtr aValue = value();
-    if (aValue.get())
-      return aPart->data()->name() + "/" + aPart->nameInPart(aValue, anIndex);
-    else
-      return aPart->data()->name();
+    std::string aResult = aSubSh.get() ?
+      aPart->data()->name() + "/" + aPart->nameInPart(aSubSh, anIndex) : aPart->data()->name();
+    if (aCenterType != NOT_CENTER)
+      aResult += centersMap()[aCenterType];
+    return aResult;
   }
 
-
   // whole infinitive construction
   if (aCont->groupName() == ModelAPI_ResultConstruction::group()) {
     ResultConstructionPtr aConstr = std::dynamic_pointer_cast<Model_ResultConstruction>(aCont);
@@ -1276,6 +1280,58 @@ void Model_AttributeSelection::computeValues(
   }
 }
 
+
+void Model_AttributeSelection::concealedFeature(
+  const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers)
+{
+  std::set<FeaturePtr> alreadyProcessed;
+  alreadyProcessed.insert(theFeature);
+  if (theStop.get())
+    alreadyProcessed.insert(theStop);
+  /// iterate all results to find the concealment-attribute
+  const std::list<ResultPtr>& aRootRes = theFeature->results();
+  std::list<ResultPtr>::const_iterator aRootIter = aRootRes.cbegin();
+  for(; aRootIter != aRootRes.cend(); aRootIter++) {
+    std::list<ResultPtr> allRes;
+    allRes.push_back(*aRootIter);
+    ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true);
+    if (!aRootBody.get())
+      aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRootIter);
+    if (aRootBody.get()) {
+      ModelAPI_Tools::allSubs(aRootBody, allRes);
+    }
+    for(std::list<ResultPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
+      const std::set<AttributePtr>& aRefs = (*aRIter)->data()->refsToMe();
+      std::set<AttributePtr>::const_iterator aRef = aRefs.cbegin();
+      for (; aRef != aRefs.cend(); aRef++) {
+        if (!aRef->get() || !(*aRef)->owner().get())
+          continue;
+        // concealed attribute only
+        FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
+        if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
+          continue;
+        alreadyProcessed.insert(aRefFeat);
+        if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+        {
+          // for extrusion cut in python script the nested sketch reference may be concealed before
+          // it is nested, so, check this composite feature is valid
+          static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+          // need to be validated to update the "Apply" state if not previewed
+          if (aFactory->validate(aRefFeat)) {
+            if (theStop.get()) {
+              std::shared_ptr<Model_Document> aDoc =
+                std::dynamic_pointer_cast<Model_Document>(theStop->document());
+              if (!aDoc->isLaterByDep(theStop, aRefFeat)) // skip feature later than stop
+                continue;
+            }
+            theConcealers.push_back(aRefFeat);
+          }
+        }
+      }
+    }
+  }
+}
+
 bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document> theDoc,
   const TopoDS_Shape theContShape, ResultPtr theContext, TopoDS_Shape theValShape,
   TDF_Label theAccessLabel,
@@ -1339,59 +1395,29 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
 
   if (aResults.empty()) {
     // check the context become concealed by operation which is earlier than this selection
-    std::list<ResultPtr> allRes;
-    ResultPtr aRoot = ModelAPI_Tools::bodyOwner(theContext, true);
-    if (!aRoot.get())
-      aRoot = theContext;
-    ResultBodyPtr aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aRoot);
-    if (aRootBody.get()) {
-      ModelAPI_Tools::allSubs(aRootBody, allRes);
-      allRes.push_back(aRootBody);
-    } else
-      allRes.push_back(aRoot);
-
     FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-    for (std::list<ResultPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
-      ResultPtr aResCont = *aSub;
-      const std::set<AttributePtr>& aRefs = aResCont->data()->refsToMe();
-      std::set<AttributePtr>::const_iterator aRef = aRefs.begin();
-      for (; aRef != aRefs.end(); aRef++) {
-        if (!aRef->get() || !(*aRef)->owner().get())
+    FeaturePtr aContextOwner = theDoc->feature(theContext);
+    std::list<FeaturePtr> aConcealers;
+    concealedFeature(aContextOwner, aThisFeature, aConcealers);
+    std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+    for(; aConcealer != aConcealers.end(); aConcealer++) {
+      std::list<ResultPtr> aRefResults;
+      ModelAPI_Tools::allResults(*aConcealer, aRefResults);
+      std::list<ResultPtr>::iterator aRefIter = aRefResults.begin();
+      for(; aRefIter != aRefResults.end(); aRefIter++) {
+        ResultBodyPtr aRefBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRefIter);
+        if (!aRefBody.get() || aRefBody->numberOfSubs() != 0) // iterate only leafs
           continue;
-        // concealed attribute only
-        FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
-        if (aRefFeat == aThisFeature)
-          continue;
-        if (!ModelAPI_Session::get()->validators()->isConcealed(
-          aRefFeat->getKind(), (*aRef)->id()))
+        GeomShapePtr aRefShape = aRefBody->shape();
+        if (!aRefShape.get() || aRefShape->isNull())
           continue;
-        if (theDoc->isLaterByDep(aThisFeature, aRefFeat)) {
-          // for extrusion cut in python script the nested sketch reference may be concealed before
-          // it is nested, so, check this composite feature is valid
-          static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
-          // need to be validated to update the "Apply" state if not previewed
-          if (aFactory->validate(aRefFeat)) {
-            // there could be a reference to unmodified object, check result contain same shape
-            std::list<ResultPtr> aRefResults;
-            ModelAPI_Tools::allResults(aRefFeat, aRefResults);
-            std::list<ResultPtr>::iterator aRefIter = aRefResults.begin();
-            for(; aRefIter != aRefResults.end(); aRefIter++) {
-              ResultBodyPtr aRefBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRefIter);
-              if (!aRefBody.get() || aRefBody->numberOfSubs() != 0) // iterate only leafs
-                continue;
-              GeomShapePtr aRefShape = aRefBody->shape();
-              if (!aRefShape.get() || aRefShape->isNull())
-                continue;
-              if (aRefShape->impl<TopoDS_Shape>().IsSame(theContShape)) {
-                // add the new context result with the same shape
-                aResults.insert(aRefBody);
-              }
-            }
-            if (aResults.empty())
-              return true; // feature conceals result, return true, so the context will be removed
-          }
+        if (aRefShape->impl<TopoDS_Shape>().IsSame(theContShape)) {
+          // add the new context result with the same shape
+          aResults.insert(aRefBody);
         }
       }
+      if (aResults.empty())
+        return true; // feature conceals result, return true, so the context will be removed
     }
     if (aResults.empty())
       return false; // no modifications found, must stay the same
@@ -1434,11 +1460,42 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
 
 void Model_AttributeSelection::updateInHistory(bool& theRemove)
 {
+  static std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+
   ResultPtr aContext = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
-  // only bodies and parts may be modified later in the history, don't do anything otherwise
   if (!aContext.get() || (aContext->groupName() != ModelAPI_ResultBody::group() &&
-      aContext->groupName() != ModelAPI_ResultPart::group()))
-    return;
+      aContext->groupName() != ModelAPI_ResultPart::group())) {
+    // but check the case the whole results are allowed: whole features may be selected
+    if (myParent && myParent->isWholeResultAllowed()) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myRef.value());
+      if (aFeature.get()) {
+        FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+        std::list<FeaturePtr> aConcealers;
+        concealedFeature(aFeature, aThisFeature, aConcealers);
+        if (aConcealers.empty())
+          return;
+        bool aChanged = false;
+        std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+        for(; aConcealer != aConcealers.end(); aConcealer++)
+          if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+            setValue(*aConcealer, anEmptyShape);
+            aChanged = true;
+          }
+        if (aConcealer == aConcealers.end()) {
+          if (!aChanged) // remove this
+            theRemove = true;
+        } else { // append new
+          for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
+            if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+              myParent->append(*aConcealer, anEmptyShape);
+        }
+        if (aChanged) // searching for the further modifications
+          updateInHistory(theRemove);
+      }
+    }
+    return;// only bodies and parts may be modified later in the history, skip otherwise
+  }
+
   std::shared_ptr<Model_Document> aDoc =
     std::dynamic_pointer_cast<Model_Document>(aContext->document());
   std::shared_ptr<Model_Data> aContData = std::dynamic_pointer_cast<Model_Data>(aContext->data());
@@ -1541,6 +1598,42 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
         aListShapeType = GeomAPI_Shape::FACE;
     }
 
+    // issue #3031: skip topology if there is more convenient shape type presents in the
+    // same context as a result of this
+    bool isWholeResult = myParent && myParent->isWholeResultAllowed() && !aSubShape.get();
+    GeomAPI_Shape::ShapeType allowedType = GeomAPI_Shape::SHAPE;
+    if (isWholeResult) {
+      std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
+      TopTools_ListIteratorOfListOfShape aNewValues(aValShapes);
+      for(; aNewCont != aNewContexts.end(); aNewCont++, aNewValues.Next()) {
+        if (aNewValues.Value().IsNull()) { // only for the whole context
+          GeomAPI_Shape::ShapeType aShapeType = (*aNewCont)->shape()->shapeType();
+          if (allowedType == GeomAPI_Shape::SHAPE) { // just set this one
+            allowedType = aShapeType;
+          } else {
+            GeomAPI_Shape::ShapeType anAllowed = allowedType;
+            if (anAllowed != aShapeType) { // select the best, nearest to the origin
+              GeomAPI_Shape::ShapeType anOldShapeType = aContext->shape()->shapeType();
+              GeomAPI_Shape::ShapeType aDeltaAllowed =
+                (GeomAPI_Shape::ShapeType)(anOldShapeType - anAllowed);
+              if (aDeltaAllowed < 0)
+                aDeltaAllowed = (GeomAPI_Shape::ShapeType)(-aDeltaAllowed);
+              GeomAPI_Shape::ShapeType aDeltaThis =
+                (GeomAPI_Shape::ShapeType)(anOldShapeType - aShapeType);
+              if (aDeltaThis < 0)
+                aDeltaThis = (GeomAPI_Shape::ShapeType)(-aDeltaThis);
+              if (aDeltaThis == aDeltaAllowed) { // equal distance to context, select complicated
+                if (anOldShapeType < anAllowed)
+                  allowedType = aShapeType;
+              } else if (aDeltaAllowed > aDeltaThis) { // this wins
+                allowedType = aShapeType;
+              }
+            }
+          }
+        }
+      }
+    }
+
     std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
     TopTools_ListIteratorOfListOfShape aNewValues(aValShapes);
     bool aFirst = true; // first is set to this, next are appended to parent
@@ -1548,6 +1641,11 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
       if (aSkippedContext.count(*aNewCont))
         continue;
 
+      if (isWholeResult && aNewValues.Value().IsNull())
+        if (allowedType != GeomAPI_Shape::SHAPE &&
+            (*aNewCont)->shape()->shapeType() != allowedType)
+          continue; // there is better result exists with the better shape type (issue #3031)
+
       GeomShapePtr aValueShape;
       if (!aNewValues.Value().IsNull()) {
         aValueShape = std::make_shared<GeomAPI_Shape>();
@@ -1561,7 +1659,10 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
         aShapeShapeType = (*aNewCont)->shape()->shapeType();
       }
       if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) {
-        continue;
+        // exception is for whole results selected
+        if (!isWholeResult) {
+          continue;
+        }
       }
 
       ResultPtr aNewContext = *aNewCont;
@@ -1596,8 +1697,7 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
       if (myParent) {
         theRemove = true;
       } else {
-        ResultPtr anEmptyContext;
-        std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+        static ResultPtr anEmptyContext;
         setValue(anEmptyContext, anEmptyShape); // nullify the selection
         return;
       }
index c3721e9940e28c9c32e7539881b27809a9b19eb3..b7d81ff7406ac5020a369478aa026620c4ec65a2 100644 (file)
@@ -63,7 +63,7 @@ public:
     const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
     const bool theTemporarily = false);
 
-  /// Same as SetValue, but it takes an edge (on circular or elliptical curve)
+  /// Same as SetValue, but it takes an edge (on circular or elliptic curve)
   /// and stores the vertex of the central point (for ellipse the first or the second focus point)
   MODEL_EXPORT virtual void setValueCenter(
     const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Edge>& theEdge,
@@ -202,6 +202,10 @@ protected:
   /// Returns null label otherwise.
   TDF_Label baseDocumentLab();
 
+  /// Returns features that conceals theFeature and located in history before theStop
+  void concealedFeature(
+    const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers);
+
   friend class Model_Data;
   friend class Model_AttributeSelectionList;
 };
index 50b04d3c35d967dd388f9b8637f60d340a5aa19f..170190ef66879e1e44f82e71e4be35340ea4f2ca 100644 (file)
@@ -293,17 +293,19 @@ bool Model_AttributeSelectionList::isInList(const ObjectPtr& theContext,
                                             const std::shared_ptr<GeomAPI_Shape>& theSubShape,
                                             const bool theTemporarily)
 {
-  ResultPtr aResCont = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
   if (myIsCashed) { // the cashing is active
-    if (aResCont.get()) {
-      std::map<ResultPtr, std::list<std::shared_ptr<GeomAPI_Shape> > >::iterator aContext =
-        myCash.find(aResCont);
+    if (theContext.get()) {
+      std::map<ObjectPtr, std::list<std::shared_ptr<GeomAPI_Shape> > >::iterator aContext =
+        myCash.find(theContext);
       if (aContext != myCash.end()) {
         // iterate shapes because "isSame" method must be called for each shape
         std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aShapes = aContext->second.begin();
         for(; aShapes != aContext->second.end(); aShapes++) {
           if (!theSubShape.get()) {
-            if (!aShapes->get() || (*aShapes)->isSame(aContext->first->shape()))
+            if (!aShapes->get())
+              return true;
+            ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aContext->first);
+            if (aRes.get() && (*aShapes)->isSame(aRes->shape()))
               return true;
           } else {
             // we need to call here isSame instead of isEqual to do not check shapes orientation
@@ -316,15 +318,21 @@ bool Model_AttributeSelectionList::isInList(const ObjectPtr& theContext,
     }
   }
   // no-cash method
+  bool isFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theContext).get() != NULL;
+  ResultPtr aRes;
+  if (!isFeature)
+    aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
   for(int anIndex = size() - 1; anIndex >= 0; anIndex--) {
     AttributeSelectionPtr anAttr = value(anIndex);
     if (anAttr.get()) {
-      if (anAttr->context() == theContext) { // contexts are equal, so, check that values are also
+      if (isFeature && anAttr->contextFeature() == theContext)
+        return true; // for the feature value should not be compared
+      if (!isFeature && anAttr->context() == theContext) {
+        // contexts are equal, so, check that values are also
         std::shared_ptr<GeomAPI_Shape> aValue = anAttr->value();
         if (!theSubShape.get()) {
-          if (!aValue.get() || (aResCont.get() && aValue->isSame(aResCont->shape()))) {// both null
+          if (!aValue.get() || (aRes.get() && aValue->isSame(aRes->shape())))
             return true;
-          }
         } else {
           // we need to call here isSame instead of isEqual to do not check shapes orientation
           if (isIn(aValue, theSubShape)) // shapes are equal
@@ -398,7 +406,7 @@ bool Model_AttributeSelectionList::isInitialized()
 }
 
 Model_AttributeSelectionList::Model_AttributeSelectionList(TDF_Label& theLabel)
-: myLab(theLabel)
+: ModelAPI_AttributeSelectionList(), myLab(theLabel)
 {
   reinit();
 }
index ca797e623d75716d1efc9e0ffcfad5c8a5f41cb1..3ed3e2804aca7e396befd8f711a858dd1829a9d2 100644 (file)
@@ -42,7 +42,7 @@ class Model_AttributeSelectionList : public ModelAPI_AttributeSelectionList
   Handle(TDataStd_Comment) mySelectionType;
   std::shared_ptr<Model_AttributeSelection> myTmpAttr; ///< temporary attribute (the last one)
   /// the cashed shapes to optimize isInList method: from context to set of shapes in this context
-  std::map<ResultPtr, std::list<std::shared_ptr<GeomAPI_Shape> > > myCash;
+  std::map<ObjectPtr, std::list<std::shared_ptr<GeomAPI_Shape> > > myCash;
   bool myIsCashed; ///< true if cashing is performed
 public:
   /// Adds the new reference to the end of the list
index 4c812fc26744e03ee87060f3d4ee66b9fa0c3a18..108b7a544307c8c64de2637c7d33d3f28081fbd8 100644 (file)
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Object.h>
 
+#include <TDataStd_UAttribute.hxx>
 #include <Standard_TypeDef.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_ExtendedString.hxx>
 
 #include <string>
 
+// on myLabel if the Unicode string was stored
+static const Standard_GUID kUVALUE_IDENTIFIER("04cac509-b2fc-4887-b442-d2a86f2fd7bd");
+
 void Model_AttributeString::setValue(const std::string& theValue)
 {
   TCollection_ExtendedString aValue(theValue.c_str());
@@ -36,6 +40,7 @@ void Model_AttributeString::setValue(const std::string& theValue)
     if (myString.IsNull())
       myString = TDataStd_Name::Set(myLab, TCollection_ExtendedString());
     myString->Set(aValue);
+    myLab.ForgetAttribute(kUVALUE_IDENTIFIER);
     owner()->data()->sendAttributeUpdated(this);
   }
 }
@@ -47,6 +52,7 @@ void Model_AttributeString::setValue(const std::wstring& theValue)
     if (myString.IsNull())
       myString = TDataStd_Name::Set(myLab, TCollection_ExtendedString());
     myString->Set(aValue);
+    TDataStd_UAttribute::Set(myLab, kUVALUE_IDENTIFIER);
     owner()->data()->sendAttributeUpdated(this);
   }
 }
@@ -57,6 +63,7 @@ std::string Model_AttributeString::value()
     return "";  // not initialized
   return TCollection_AsciiString(myString->Get()).ToCString();
 }
+
 char16_t* Model_AttributeString::valueU()
 {
   if (myString.IsNull()) {   // not initialized
@@ -66,6 +73,10 @@ char16_t* Model_AttributeString::valueU()
   return (char16_t*)(myString->Get().ToExtString());
 }
 
+bool Model_AttributeString::isUValue() const {
+  return !myLab.IsNull() && myLab.IsAttribute(kUVALUE_IDENTIFIER);
+}
+
 Model_AttributeString::Model_AttributeString(TDF_Label& theLabel)
 {
   myLab = theLabel;
index d678d89f9743a9de6ac374f5d9ef4976036b8554..7c0257f38b20956cfb18278a8b0c5f4c17299c27 100644 (file)
@@ -47,6 +47,8 @@ class Model_AttributeString : public ModelAPI_AttributeString
   MODEL_EXPORT virtual std::string value();
   /// Returns a pointer to Unicode string
   MODEL_EXPORT virtual char16_t* valueU();
+  /// Returns true if Unicode string was stored
+  MODEL_EXPORT virtual bool isUValue() const;
 
  protected:
   /// Initializes attributes
index dad2068da15557f5630e5a105aa14c2e61c1990c..10d11678d642420f5bde838baabe2072dce78114 100644 (file)
@@ -810,6 +810,12 @@ static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
     // 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);
index b7a295935dd09db70ae86de99417a1ea951a0b9c..be2877848b1a34b891a39b3dae19561fb94e780a 100644 (file)
@@ -1038,15 +1038,15 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre
           aCurrent = aSub;
         }
       }
-      // #2861: if the parameter is added, add it after parameters existing in the list
-      if (aCurrent.get() &&
-          (aFeature->getKind() == "Parameter" || aFeature->getKind() == "ParametersMgr")) {
-        int anIndex = kUNDEFINED_FEATURE_INDEX;
-        for(FeaturePtr aNextFeat = myObjs->nextFeature(aCurrent, anIndex);
-            aNextFeat.get() && aNextFeat->getKind() == "Parameter";
-            aNextFeat = myObjs->nextFeature(aCurrent, anIndex))
-          aCurrent = aNextFeat;
-      }
+    }
+    // #2861,3029: if the parameter is added, add it after parameters existing in the list
+    if (aCurrent.get() &&
+      (aFeature->getKind() == "Parameter" || aFeature->getKind() == "ParametersMgr")) {
+      int anIndex = kUNDEFINED_FEATURE_INDEX;
+      for(FeaturePtr aNextFeat = myObjs->nextFeature(aCurrent, anIndex);
+        aNextFeat.get() && aNextFeat->getKind() == "Parameter";
+        aNextFeat = myObjs->nextFeature(aCurrent, anIndex))
+        aCurrent = aNextFeat;
     }
     aDocToAdd->myObjs->addFeature(aFeature, aCurrent);
     if (!aFeature->isAction()) {  // do not add action to the data model
index 885259852ee090b8061e310eac6597de176cb7fd..2db766fc6523b6a5155021c3e9533597291a08bc 100644 (file)
@@ -57,9 +57,9 @@ bool Model_FeatureValidator::isValid(const std::shared_ptr<ModelAPI_Feature>& th
         myNotObligatory.find(theFeature->getKind());
       if (aFeatureFind == myNotObligatory.end() || // and it is obligatory for filling
           aFeatureFind->second.find(*it) == aFeatureFind->second.end()) {
-        // TODO(spo): exceptional case for translation
-        theError = "Attribute \"" + anAttr->id() + "\" is not initialized.";
-//        theError.arg(anAttr->id());
+        theError = "Attribute \"%1\" is not initialized.";
+        theError.addParameter(anAttr->id());
+        theError.setContext(theFeature->getKind() + ":" + anAttr->id());
         return false;
       }
     }
index 87d1620f6b3644f3525ac35273734dda34f595b8..c40c90738ed8feac8e7c1d91c34d6a1476fb4d77 100644 (file)
@@ -22,6 +22,7 @@
 #include <ModelAPI_AttributeSelectionList.h>
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <Config_PropManager.h>
 
@@ -68,11 +69,33 @@ std::shared_ptr<GeomAPI_Shape> Model_ResultGroup::shape()
   if (!aResult && myOwnerData) {
     AttributeSelectionListPtr aList = myOwnerData->selectionList("group_list");
     if (aList) {
+      GeomAPI_DataMapOfShapeShape aShapesMap; // to avoid shapes duplication
       std::list<std::shared_ptr<GeomAPI_Shape> > aSubs;
       for(int a = aList->size() - 1; a >= 0; a--) {
         std::shared_ptr<GeomAPI_Shape> aSelection = aList->value(a)->value();
-        if (aSelection && !aSelection->isNull()) {
-          aSubs.push_back(aSelection);
+        if (aList->isWholeResultAllowed()) { // whole result selection, explode to sub-shapes
+          if (!aSelection.get() || aSelection->isNull()) {
+            ResultPtr aContext = aList->value(a)->context();
+            if (aContext)
+              aSelection = aContext->shape();
+          }
+          if (aSelection && !aSelection->isNull()) {
+            GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(aList->selectionType());
+            if (aType == aSelection->shapeType()) {
+              if (aShapesMap.bind(aSelection, aSelection))
+                aSubs.push_back(aSelection);
+            } else {
+              for(GeomAPI_ShapeExplorer anExp(aSelection, aType); anExp.more(); anExp.next()) {
+                if (aShapesMap.bind(anExp.current(), anExp.current()))
+                  aSubs.push_back(anExp.current());
+              }
+            }
+          }
+        } else { // take selection as it is
+          if (aSelection && !aSelection->isNull()) {
+            if (aShapesMap.bind(aSelection, aSelection))
+              aSubs.push_back(aSelection);
+          }
         }
       }
       if (!aSubs.empty()) {
index f70deecced5c8d4c89507ed48eca4a85f4652cdf..b8fb440d742ac10ce1390ccb52057722e993008a 100644 (file)
@@ -285,7 +285,7 @@ std::string Model_ResultPart::nameInPart(const std::shared_ptr<GeomAPI_Shape>& t
       TopoDS_Shape aBodyShape = *(aBody->shape()->implPtr<TopoDS_Shape>());
       // check is body contain the selected sub-shape
       for(TopExp_Explorer anExp(aBodyShape, aShape.ShapeType()); anExp.More(); anExp.Next()) {
-        if (aShape.IsEqual(anExp.Current())) {
+        if (aShape.IsSame(anExp.Current())) {
           aContext = aBody;
           break;
         }
index 07f87c3edadc54194c031f07628d568c490c5fbe..d8896e68039a01774be036a7720ca08e9a9b1f8e 100644 (file)
@@ -647,7 +647,12 @@ bool Model_Update::processFeature(FeaturePtr theFeature)
     }
     // searching for the next not used reason
     aProcessedReasons.insert(aReason);
-    aReasons.erase(aReason);
+    // check theFeature is still in the list of modified, because it may be removed sometimes
+    // while updating SketchPlugin_Ellipse
+    if (myModified.find(theFeature) != myModified.end())
+      aReasons.erase(aReason);
+    else
+      break;
   }
   // restore the modified reasons: they will be used in the update of arguments
   if (allSubsUsed) { // restore theFeature in this set
index f031c68d15c7a4954292867b48a01905be77e27f..1ef43263f40abdae8a3f11daf77b0c21f49d7d9c 100644 (file)
@@ -242,6 +242,8 @@ ADD_UNIT_TESTS(TestConstants.py
                TestSaveOpen1.py
                TestSaveOpen2.py
                TestSelectionInitialization.py
+               TestSelectionCircleCenter.py
+               TestSelectionInPart.py
                Test2828.py
                TestSelectionRestore.py
                Test2491.py
@@ -251,4 +253,5 @@ ADD_UNIT_TESTS(TestConstants.py
                Test2873.py
                Test2901.py
                Test2903.py
+               Test3020.py
 )
index 0f44acb010c7399b7ec31a293868b51a752e81f7..119485dc495ae4b69e617f1d2b1c04b29e74edc3 100644 (file)
@@ -34,7 +34,7 @@ class GeomAPI_Pnt;
 class ModelAPI_AttributeSelection : public ModelAPI_Attribute
 {
  public:
-   /// Type of the center of the circular of elliptical edge
+   /// Type of the center of the circular of elliptic edge
    enum CenterType {
      NOT_CENTER, ///< this is not a center
      CIRCLE_CENTER, ///< center of the circle
@@ -52,7 +52,7 @@ class ModelAPI_AttributeSelection : public ModelAPI_Attribute
     const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
     const bool theTemporarily = false) = 0;
 
-  /// Same as SetValue, but it takes an edge (on circular or elliptical curve)
+  /// Same as SetValue, but it takes an edge (on circular or elliptic curve)
   /// and stores the vertex of the central point (for ellipse the first or the second focus point)
   virtual void setValueCenter(
     const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Edge>& theEdge,
index 820d33baf99953578c573a0e04fa2fea909549a0..d7d7a4435b1dbba2da353b6674bab73d28bd1b49 100644 (file)
@@ -27,7 +27,3 @@ std::string ModelAPI_AttributeSelectionList::attributeType()
 ModelAPI_AttributeSelectionList::~ModelAPI_AttributeSelectionList()
 {
 }
-
-MODELAPI_EXPORT ModelAPI_AttributeSelectionList::ModelAPI_AttributeSelectionList()
-{
-}
index 4280f613aa118f2cbc460041243d799bd41bc5d1..a88017e3412403701017112c1a31277e6e17f0f8 100644 (file)
@@ -35,6 +35,10 @@ class GeomAPI_Shape;
 
 class ModelAPI_AttributeSelectionList : public ModelAPI_Attribute
 {
+  /// Flag that indicates that the whole result selection is allowed while the selection type
+  /// may be sub-objects, so, it is the same as all sub-shapes are selected (#3005). It is "false"
+  /// by default.
+  bool myIsWholeResultAllowed;
  public:
   /// Adds the new reference to the end of the list
   /// \param theContext object where the sub-shape was selected
@@ -121,9 +125,20 @@ class ModelAPI_AttributeSelectionList : public ModelAPI_Attribute
   /// Sets a selection filters feature if it is defined for this selection list
   MODELAPI_EXPORT virtual void setFilters(FiltersFeaturePtr theFeature) = 0;
 
+  /// Returns true if the whole result selection corresponds to selection of all sub-shapes.
+  MODELAPI_EXPORT virtual const bool isWholeResultAllowed() const {
+    return myIsWholeResultAllowed;
+  }
+
+  /// Sets whether the whole result selection corresponds to selection of all sub-shapes.
+  MODELAPI_EXPORT virtual void setWholeResultAllowed(const bool theFlag)  {
+    myIsWholeResultAllowed = theFlag;
+  }
+
 protected:
-  /// Objects are created for features automatically
-  MODELAPI_EXPORT ModelAPI_AttributeSelectionList();
+  /// Default constructor
+  MODELAPI_EXPORT ModelAPI_AttributeSelectionList() : ModelAPI_Attribute()
+  {myIsWholeResultAllowed = false;}
 
 };
 
index d753784c40bf8a37cfd3094e57cd59300393848f..d6c4b88616670c4de994105dbc78b96de5450cec 100644 (file)
@@ -41,6 +41,7 @@ class ModelAPI_AttributeString : public ModelAPI_Attribute
   MODELAPI_EXPORT virtual std::string value() = 0;
   /// Returns a pointer to Unicode string
   MODELAPI_EXPORT virtual char16_t* valueU() = 0;
+  MODELAPI_EXPORT virtual bool isUValue() const = 0;
 
   /// Returns the type of this class of attributes
   MODELAPI_EXPORT static std::string typeId()
diff --git a/src/ModelAPI/Test/Test3020.py b/src/ModelAPI/Test/Test3020.py
new file mode 100644 (file)
index 0000000..429dd91
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+from ModelAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(25, 20, 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 20, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_2 = Sketch_2.addCircle(25, 20, 5)
+SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchPoint_1.result(), SketchCircle_2.center())
+model.end()
+# check the sketch_2 projection and the whole sketch is valid after selection of the circle center from another part
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(SketchProjection_1.feature()))
+assert(aFactory.validate(Sketch_2.feature()))
+
+assert(model.checkPythonDump())
diff --git a/src/ModelAPI/Test/TestSelectionCircleCenter.py b/src/ModelAPI/Test/TestSelectionCircleCenter.py
new file mode 100644 (file)
index 0000000..0b1a082
--- /dev/null
@@ -0,0 +1,85 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(15, 10, -10, 10)
+SketchLine_2 = Sketch_1.addLine(-10, 10, -10, -10)
+SketchLine_3 = Sketch_1.addLine(-10, -10, 20, -10)
+SketchLine_4 = Sketch_1.addLine(20, -10, 20, 5)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_1.setName("SketchConstraintCoincidence_2")
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2.setName("SketchConstraintCoincidence_3")
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3.setName("SketchConstraintCoincidence_4")
+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())
+SketchArc_1 = Sketch_1.addArc(15, 5, 20, 5, 15, 10, False)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_4.endPoint())
+SketchConstraintCoincidence_4.setName("SketchConstraintCoincidence_5")
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_5.setName("SketchConstraintCoincidence_6")
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_1.result())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_3.result(), 30)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 5)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchProjection_1.setName("SketchProjection_3")
+SketchProjection_1.result().setName("SketchProjection_3")
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchPoint_1.setName("SketchPoint_3")
+SketchPoint_1.result().setName("SketchPoint_3")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_2.startPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_2.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchArc_1_2f")], model.selection(), 10, 0)
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3]")], 10)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Fillet_1_1/MF:Fillet&Extrusion_1_1/To_Face"))
+SketchLine_5 = Sketch_2.addLine(15, 5, 0, 0)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Fillet_1_1/MF:Fillet&Extrusion_1_1/To_Face][Extrusion_1_1/Generated_Face&Sketch_1/SketchArc_1_2]__cc"), False)
+SketchProjection_2.setName("SketchProjection_1")
+SketchProjection_2.result().setName("SketchProjection_1")
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchPoint_2.setName("SketchPoint_1")
+SketchPoint_2.result().setName("SketchPoint_1")
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_5.startPoint(), SketchPoint_2.result())
+SketchConstraintCoincidence_6.setName("SketchConstraintCoincidence_7")
+SketchProjection_3 = Sketch_2.addProjection(model.selection("VERTEX", "[Fillet_1_1/GF:Fillet&Fillet_1_1/FilletSelected][Fillet_1_1/MF:Fillet&Extrusion_1_1/To_Face]__cc"), False)
+SketchProjection_3.setName("SketchProjection_2")
+SketchProjection_3.result().setName("SketchProjection_2")
+SketchPoint_3 = SketchProjection_3.createdFeature()
+SketchPoint_3.setName("SketchPoint_2")
+SketchPoint_3.result().setName("SketchPoint_2")
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchPoint_3.result())
+SketchConstraintCoincidence_7.setName("SketchConstraintCoincidence_8")
+model.end()
+# check that the second line-point was created on the point, not arc
+assert(len(SketchPoint_3.feature().results()) == 1)
+assert(SketchPoint_3.feature().firstResult().shape().isVertex())
diff --git a/src/ModelAPI/Test/TestSelectionInPart.py b/src/ModelAPI/Test/TestSelectionInPart.py
new file mode 100644 (file)
index 0000000..cde8ba0
--- /dev/null
@@ -0,0 +1,159 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+model.addParameter(partSet, "ShaftSize", "16")
+model.addParameter(partSet, "ShaftChamfer", "0.2")
+model.addParameter(partSet, "ToolHeight", "5")
+model.addParameter(partSet, "ToolDraftAngle", "11")
+model.addParameter(partSet, "ScrewDiam", "3.5")
+model.addParameter(partSet, "ThreadDiam", "ScrewDiam+1")
+model.addParameter(partSet, "ScrewHeight", "12")
+model.addParameter(partSet, "ToolEdgeSize", "9")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("YOZ"))
+SketchLine_1 = Sketch_1.addLine(7.8, 0, -7.8, 0)
+SketchLine_2 = Sketch_1.addLine(-8, 0.2, -8, 15.8)
+SketchLine_3 = Sketch_1.addLine(-7.8, 16, 7.8, 16)
+SketchLine_4 = Sketch_1.addLine(8, 15.8, 8, 0.2)
+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())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchLine_5 = Sketch_1.addLine(-8, 0.2, -7.8, 0)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(7.8, 0, 8, 0.2)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_6.endPoint())
+SketchLine_7 = Sketch_1.addLine(-8, 15.8, -7.8, 16)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_3.startPoint(), SketchLine_7.endPoint())
+SketchLine_8 = Sketch_1.addLine(7.8, 16, 8, 15.8)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_4.startPoint(), SketchLine_8.endPoint())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_3.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_4.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_6.result(), SketchLine_7.result())
+SketchConstraintEqual_6 = Sketch_1.setEqual(SketchLine_7.result(), SketchLine_8.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_5.startPoint(), SketchLine_4.result(), "ShaftSize", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_1.endPoint(), SketchLine_3.result(), "ShaftSize", True)
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_5.startPoint(), SketchLine_1.endPoint(), "ShaftChamfer")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_1.endPoint(), SketchLine_5.startPoint(), "ShaftChamfer")
+model.do()
+Part_1 = model.addPart(partSet)
+Part_1.setName("TurnShaft")
+Part_1.result().setName("TurnShaft")
+Part_1.result().setColor(75, 75, 75)
+Part_1_doc = Part_1.document()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "PartSet/Sketch_1/Face-SketchLine_6f-SketchLine_4r-SketchLine_8r-SketchLine_3r-SketchLine_7r-SketchLine_2r-SketchLine_5f-SketchLine_1r")], model.selection(), 100, 0)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), model.selection("FACE", "Extrusion_1_1/Generated_Face&PartSet/Sketch_1/SketchLine_4"), 0, model.selection(), 0, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&PartSet/Sketch_1/SketchLine_2"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/Sketch_1/SketchLine_7"), True)
+SketchLine_9 = SketchProjection_2.createdFeature()
+SketchLine_10 = Sketch_2.addLine(0, 15.8, 0.2, 16)
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_9).startPoint(), SketchLine_10.startPoint())
+SketchLine_11 = Sketch_2.addLine(0.2, 16, 0, 16)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_10.endPoint(), SketchLine_11.startPoint())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_9).endPoint(), SketchLine_11.endPoint())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_11.result())
+SketchConstraintEqual_7 = Sketch_2.setEqual(SketchLine_9.result(), SketchLine_11.result())
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/Sketch_1/SketchLine_5"), True)
+SketchLine_12 = SketchProjection_3.createdFeature()
+SketchLine_13 = Sketch_2.addLine(0, 0.2, 0.2, 0)
+SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_12).startPoint(), SketchLine_13.startPoint())
+SketchLine_14 = Sketch_2.addLine(0.2, 0, 0, 0)
+SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchLine_13.endPoint(), SketchLine_14.startPoint())
+SketchConstraintCoincidence_14 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_12).endPoint(), SketchLine_14.endPoint())
+SketchConstraintHorizontal_4 = Sketch_2.setHorizontal(SketchLine_14.result())
+SketchConstraintEqual_8 = Sketch_2.setEqual(SketchLine_12.result(), SketchLine_14.result())
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+ExtrusionCut_2 = model.addExtrusionCut(Part_1_doc, [], model.selection(), model.selection("FACE", "ExtrusionCut_1_1/Modified_Face&PartSet/Sketch_1/SketchLine_1"), 0, model.selection(), 0, [model.selection("SOLID", "ExtrusionCut_1_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionCut_1_1/Modified_Face&PartSet/Sketch_1/SketchLine_3"))
+SketchProjection_4 = Sketch_3.addProjection(model.selection("EDGE", "[ExtrusionCut_1_1/Modified_Face&PartSet/Sketch_1/SketchLine_3][ExtrusionCut_1_1/Generated_Face&Sketch_1/SketchLine_2]"), False)
+SketchLine_15 = SketchProjection_4.createdFeature()
+SketchProjection_5 = Sketch_3.addProjection(model.selection("VERTEX", "PartSet/Sketch_1/SketchLine_2_EndVertex"), False)
+SketchPoint_2 = SketchProjection_5.createdFeature()
+SketchLine_16 = Sketch_3.addLine(0, -8, 0.2, -8)
+SketchConstraintCoincidence_15 = Sketch_3.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_16.startPoint())
+SketchLine_17 = Sketch_3.addLine(0.2, -8, 0, -7.8)
+SketchConstraintCoincidence_16 = Sketch_3.setCoincident(SketchLine_16.endPoint(), SketchLine_17.startPoint())
+SketchLine_18 = Sketch_3.addLine(0, -7.8, 0, -8)
+SketchConstraintCoincidence_17 = Sketch_3.setCoincident(SketchLine_17.endPoint(), SketchLine_18.startPoint())
+SketchConstraintCoincidence_18 = Sketch_3.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_18.endPoint())
+SketchConstraintHorizontal_5 = Sketch_3.setHorizontal(SketchLine_16.result())
+SketchConstraintVertical_3 = Sketch_3.setVertical(SketchLine_18.result())
+SketchConstraintEqual_9 = Sketch_3.setEqual(SketchLine_16.result(), SketchLine_18.result())
+SketchConstraintCoincidence_19 = Sketch_3.setCoincident(SketchLine_16.endPoint(), SketchLine_15.result())
+SketchProjection_6 = Sketch_3.addProjection(model.selection("VERTEX", "PartSet/Sketch_1/SketchLine_8_EndVertex"), False)
+SketchPoint_3 = SketchProjection_6.createdFeature()
+SketchLine_19 = Sketch_3.addLine(0, 8, 0, 7.8)
+SketchConstraintCoincidence_20 = Sketch_3.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchLine_19.startPoint())
+SketchLine_20 = Sketch_3.addLine(0, 7.8, 0.2, 8)
+SketchConstraintCoincidence_21 = Sketch_3.setCoincident(SketchLine_19.endPoint(), SketchLine_20.startPoint())
+SketchLine_21 = Sketch_3.addLine(0.2, 8, 0, 8)
+SketchConstraintCoincidence_22 = Sketch_3.setCoincident(SketchLine_20.endPoint(), SketchLine_21.startPoint())
+SketchConstraintCoincidence_23 = Sketch_3.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchLine_21.endPoint())
+SketchConstraintVertical_4 = Sketch_3.setVertical(SketchLine_19.result())
+SketchConstraintHorizontal_6 = Sketch_3.setHorizontal(SketchLine_21.result())
+SketchConstraintEqual_10 = Sketch_3.setEqual(SketchLine_19.result(), SketchLine_21.result())
+SketchConstraintCoincidence_24 = Sketch_3.setCoincident(SketchLine_20.endPoint(), SketchLine_15.result())
+ExtrusionCut_2.setNestedSketch(Sketch_3)
+ExtrusionCut_3 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 3, [model.selection("SOLID", "ExtrusionCut_2_1")])
+Sketch_4 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionCut_1_1/Modified_Face&PartSet/Sketch_1/SketchLine_3"))
+SketchCircle_1 = Sketch_4.addCircle(10, 0, 5)
+SketchProjection_7 = Sketch_4.addProjection(model.selection("EDGE", "[ExtrusionCut_2_1/Modified_Face&Extrusion_1_1/From_Face][ExtrusionCut_2_1/Modified_Face&Sketch_1/SketchLine_2]"), False)
+SketchLine_22 = SketchProjection_7.createdFeature()
+SketchLine_23 = Sketch_4.addLine(10, 0, 0, 0)
+SketchLine_23.setAuxiliary(True)
+SketchConstraintCoincidence_25 = Sketch_4.setCoincident(SketchCircle_1.center(), SketchLine_23.startPoint())
+SketchConstraintCoincidence_26 = Sketch_4.setCoincident(SketchLine_23.endPoint(), SketchLine_22.result())
+SketchConstraintMiddle_2 = Sketch_4.setMiddlePoint(SketchLine_23.endPoint(), SketchLine_22.result())
+SketchConstraintPerpendicular_1 = Sketch_4.setPerpendicular(SketchLine_23.result(), SketchLine_22.result())
+SketchConstraintRadius_1 = Sketch_4.setRadius(SketchCircle_1.results()[1], 5)
+SketchConstraintLength_1 = Sketch_4.setLength(SketchLine_23.result(), 10)
+ExtrusionCut_3.setNestedSketch(Sketch_4)
+model.do()
+Part_2 = model.addPart(partSet)
+Part_2.setName("Stamp")
+Part_2.result().setName("Stamp")
+Part_2_doc = Part_2.document()
+Sketch_5 = model.addSketch(Part_2_doc, model.defaultPlane("XOZ"))
+SketchProjection_8 = Sketch_5.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_4 = SketchProjection_8.createdFeature()
+SketchCircle_2 = Sketch_5.addCircle(0, 0, 5)
+SketchConstraintCoincidence_27 = Sketch_5.setCoincident(SketchPoint_4.result(), SketchCircle_2.center())
+SketchConstraintRadius_2 = Sketch_5.setRadius(SketchCircle_2.results()[1], 5)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_2_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 10, 0)
+model.do()
+Placement_1 = model.addPlacement(partSet, [model.selection("COMPOUND", "Stamp/")], model.selection("FACE", "Stamp/Extrusion_1_1/To_Face"), model.selection("FACE", "TurnShaft/ExtrusionCut_3_1/From_Face"), False, True)
+model.end()
+
+# check that names of selection are exported and imported correctly
+assert(model.checkPythonDump())
index a699cbdb34eee43e5f8e384821bef95be919b43c..6d8f1c8e26dd22b315a84c971df4ba89d4afe47f 100644 (file)
@@ -31,6 +31,7 @@ aBoxResult = Box_1.feature().results()[0]
 aShell = GeomAPI_ShapeExplorer(aBoxResult.shape(), GeomAPI_Shape.SHELL)
 aGroup = Part_1_doc.addFeature("Group")
 aGroup.selectionList("group_list").append(aBoxResult, aShell.current())
+aGroup.selectionList("group_list").setSelectionType("SHELL") # to compute the shape for the whole result selection correctly
 model.end()
 
 # check that the resulting group is correct
index 6eff0ea8b0f357ebabd87c72866223c09d8fb135..61adc7cc2f2adb3717c195bc8b247ec15d5466c6 100644 (file)
@@ -349,15 +349,8 @@ bool ModelGeomAlgo_Point2D::isPointOnEdge(const std::shared_ptr<GeomAPI_Shape> t
 {
   bool isInside = false;
   if (theBaseShape->shapeType() == GeomAPI_Shape::EDGE) {
-    std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theBaseShape));
-    if (anEdge->isLine()) {
-      std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
-      theProjectedPoint = aLine->project(thePoint);
-    }
-    else if (anEdge->isCircle() || anEdge->isArc()) {
-      std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
-      theProjectedPoint = aCircle->project(thePoint);
-    }
+    GeomCurvePtr aCurve(new GeomAPI_Curve(theBaseShape->edge()));
+    theProjectedPoint = aCurve->project(thePoint);
     if (theProjectedPoint.get()) {
       std::shared_ptr<GeomAPI_Vertex> aVertexShape(new GeomAPI_Vertex(theProjectedPoint->x(),
                                                 theProjectedPoint->y(), theProjectedPoint->z()));
@@ -375,7 +368,7 @@ bool ModelGeomAlgo_Point2D::isInnerPointOnEdge(const std::shared_ptr<GeomAPI_Sha
   bool isInside = isPointOnEdge(theBaseShape, thePoint, theProjectedPoint);
   if (isInside) {
     std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theBaseShape));
-    if (!anEdge->isCircle()) {
+    if (!anEdge->isClosed()) {
       // check the point is not on the boundary
       GeomVertexPtr aVertex(new GeomAPI_Vertex(theProjectedPoint->x(),
           theProjectedPoint->y(), theProjectedPoint->z()));
index 207e4f3aa807ce4c1b861cd4f76df85927b0a26c..2f81c1f3891aae552165d7a04672495d5f0ba7d4 100644 (file)
@@ -84,7 +84,7 @@ namespace ModelGeomAlgo_Shape
     return aFoundSubs;
   }
 
-  // Find circular/elliptical edge, which center/focus coincide with the given point
+  // Find circular/elliptic edge, which center/focus coincide with the given point
   static GeomShapePtr findEdgeByCenter(const GeomShapePtr& theBaseShape,
                                        const GeomPointPtr& theCenter,
                                        const double theTolerance,
index f26df1e5d32b3b5610fb1c06347d111d0284936f..72971cc015fdb391b1226a44f2c303097ff74f1d 100644 (file)
   std::shared_ptr<ModelAPI_Attribute> * temp_attribute;
   std::shared_ptr<ModelAPI_Object> * temp_object;
   std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
+  ModelHighAPI_Selection* temp_selection;
   int newmem = 0;
+  if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+    if (!temp_selection) {
+      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+      return NULL;
+    }
+    temp = ModelHighAPI_RefAttr(std::shared_ptr<ModelAPI_Object>(temp_selection->resultSubShapePair().first));
+    if (newmem & SWIG_CAST_NEW_MEMORY) {
+      delete temp_selection;
+    }
+    $1 = &temp;
+  } else
   if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
     if (!temp_attribute) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
       return NULL;
     }
     temp = ModelHighAPI_RefAttr(*temp_attribute);
   } else
   if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
     if (!temp_object) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
       return NULL;
     }
     temp = ModelHighAPI_RefAttr(*temp_object);
   } else
   if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
     if (!temp_interface) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
       return NULL;
     }
     temp = ModelHighAPI_RefAttr(*temp_interface);
   } else
   if ((SWIG_ConvertPtr($input, (void **)&$1, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) {
   } else {
-    PyErr_SetString(PyExc_ValueError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+    PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
     return NULL;
   }
 }
   $result = SWIG_NewPointerObj( (void*) ptr, $1_descriptor, 1 );
 }
 
+%typemap(out) const ModelHighAPI_RefAttr & {
+  $1_basetype * ptr = new $1_basetype(*$1);
+  $result = SWIG_NewPointerObj( (void*) ptr, $1_descriptor, 1 );
+}
+
 // std::list -> []
 %template(SelectionList) std::list<ModelHighAPI_Selection>;
 %template(SelectionListList) std::list<std::list<ModelHighAPI_Selection> >;
index c8e37dc1c6598fbffb86604342bdce884a57119d..836f33c93016d29eb194e2f6e91a8e379842d9a6 100644 (file)
@@ -1227,7 +1227,8 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const AttributePtr& theAttr
   // Check the attribute belongs to copied (in multi-translation or multi-rotation) feature.
   // In this case we need to cast explicitly feature to appropriate type.
   AttributeBooleanPtr isCopy = anOwner->boolean("Copy");
-  if (isCopy.get() && isCopy->value()) {
+  AttributeReferencePtr hasParent = anOwner->reference("ParentFeature");
+  if ((isCopy.get() && isCopy->value()) || (hasParent && hasParent->value())) {
     aWrapperPrefix = featureWrapper(anOwner) + "(";
     aWrapperSuffix = ")";
     importModule("SketchAPI");
index 09e944d4ee7995413c522e680eea05f3dbc59060..adba1299442d7961196cb8c66ad60685982a18f3 100644 (file)
@@ -281,6 +281,12 @@ std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) {
     std::list<std::string> aResList; // list of resulting strings
     for(std::list<ObjectPtr>::iterator aL = aList.begin(); aL != aList.end(); aL++) {
       if (aL->get()) {
+        if (isSketchFeatures) {
+          // do not control construction features of an ellipse and other
+          FeaturePtr aFeature = ModelAPI_Feature::feature(*aL);
+          if (aFeature->getKind() == "SketchConstraintCoincidenceInternal")
+            continue; // skip internal constraints
+        }
         aResList.push_back((*aL)->data()->name());
       } else if (!isSketchFeatures) {
         aResList.push_back("__empty__");
index 7b7364103291f818e5ebaa2809305190178fcc36..7fd21232ced3b794e80740b2a59e30d85c3f8ba3 100644 (file)
     END_INIT() \
   public:
 
+//--------------------------------------------------------------------------------------
+#define INTERFACE_13(KIND, \
+                     N_0, AN_0, T_0, C_0, \
+                     N_1, AN_1, T_1, C_1, \
+                     N_2, AN_2, T_2, C_2, \
+                     N_3, AN_3, T_3, C_3, \
+                     N_4, AN_4, T_4, C_4, \
+                     N_5, AN_5, T_5, C_5, \
+                     N_6, AN_6, T_6, C_6, \
+                     N_7, AN_7, T_7, C_7, \
+                     N_8, AN_8, T_8, C_8, \
+                     N_9, AN_9, T_9, C_9, \
+                     N_10, AN_10, T_10, C_10, \
+                     N_11, AN_11, T_11, C_11, \
+                     N_12, AN_12, T_12, C_12) \
+  public: \
+    INTERFACE_COMMON(KIND) \
+    DEFINE_ATTRIBUTE(N_0, T_0, C_0) \
+    DEFINE_ATTRIBUTE(N_1, T_1, C_1) \
+    DEFINE_ATTRIBUTE(N_2, T_2, C_2) \
+    DEFINE_ATTRIBUTE(N_3, T_3, C_3) \
+    DEFINE_ATTRIBUTE(N_4, T_4, C_4) \
+    DEFINE_ATTRIBUTE(N_5, T_5, C_5) \
+    DEFINE_ATTRIBUTE(N_6, T_6, C_6) \
+    DEFINE_ATTRIBUTE(N_7, T_7, C_7) \
+    DEFINE_ATTRIBUTE(N_8, T_8, C_8) \
+    DEFINE_ATTRIBUTE(N_9, T_9, C_9) \
+    DEFINE_ATTRIBUTE(N_10, T_10, C_10) \
+    DEFINE_ATTRIBUTE(N_11, T_11, C_11) \
+    DEFINE_ATTRIBUTE(N_12, T_12, C_12) \
+  protected: \
+    START_INIT() \
+      SET_ATTRIBUTE(N_0, T_0, AN_0) \
+      SET_ATTRIBUTE(N_1, T_1, AN_1) \
+      SET_ATTRIBUTE(N_2, T_2, AN_2) \
+      SET_ATTRIBUTE(N_3, T_3, AN_3) \
+      SET_ATTRIBUTE(N_4, T_4, AN_4) \
+      SET_ATTRIBUTE(N_5, T_5, AN_5) \
+      SET_ATTRIBUTE(N_6, T_6, AN_6) \
+      SET_ATTRIBUTE(N_7, T_7, AN_7) \
+      SET_ATTRIBUTE(N_8, T_8, AN_8) \
+      SET_ATTRIBUTE(N_9, T_9, AN_9) \
+      SET_ATTRIBUTE(N_10, T_10, AN_10) \
+      SET_ATTRIBUTE(N_11, T_11, AN_11) \
+      SET_ATTRIBUTE(N_12, T_12, AN_12) \
+    END_INIT() \
+  public:
+
 //--------------------------------------------------------------------------------------
 #define INTERFACE_14(KIND, \
                      N_0, AN_0, T_0, C_0, \
index 30c15a9240a3c1b4f00e4441e6154026bb717047..03548d25270fe4ec2d63747e93fd1e8b68803bab 100644 (file)
@@ -79,7 +79,7 @@ void ModelHighAPI_RefAttr::appendToList(
 //--------------------------------------------------------------------------------------
 bool ModelHighAPI_RefAttr::isEmpty() const
 {
-  return !(myAttribute && myObject);
+  return !(myAttribute || myObject);
 }
 
 //--------------------------------------------------------------------------------------
index 3aa3579ad19d4df58f63c5c2c0bdae55f275466d..8f1938720491f21997eee2676bc0b331c92a68e9 100644 (file)
@@ -193,7 +193,7 @@ void fillAttribute(const std::list<ModelHighAPI_Selection> & theValue,
 {
   theAttribute->clear();
 
-  if(!theValue.empty()) {
+  if(!theValue.empty() && theAttribute->selectionType().empty()) {
     const ModelHighAPI_Selection& aSelection = theValue.front();
     GeomAPI_Shape::ShapeType aSelectionType = getShapeType(aSelection);
     theAttribute->setSelectionType(strByShapeType(aSelectionType));
@@ -403,6 +403,10 @@ std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc,
   std::list<ObjectPtr>::iterator allIter = allObjects.begin();
   for(; allIter != allObjects.end(); allIter++) {
     ObjectPtr anObject = *allIter;
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
+    if (aFeature && aFeature->getKind() == "SketchConstraintCoincidenceInternal")
+      continue; // no need to dump and check internal constraints
+
     if (theCompare) {
       std::map<std::string, ModelHighAPI_FeatureStore>::iterator
         anObjFind = aDocFind->second.find(anObject->data()->name());
@@ -420,7 +424,6 @@ std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc,
       theStore[theDocName][anObject->data()->name()] = ModelHighAPI_FeatureStore(anObject);
     }
 
-    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
     if (aFeature) {
       // iterate all results of this feature
       std::list<ResultPtr> allResults;
@@ -474,9 +477,9 @@ static bool dumpToPython(SessionPtr theSession,
   if (aDump.get()) {
     aDump->string("file_path")->setValue(theFilename);
     aDump->string("file_format")->setValue("py");
-    aDump->boolean("topological_naming")->setValue(theSelectionType & CHECK_NAMING);
-    aDump->boolean("geometric_selection")->setValue(theSelectionType & CHECK_GEOMETRICAL);
-    aDump->boolean("weak_naming")->setValue(theSelectionType & CHECK_WEAK);
+    aDump->boolean("topological_naming")->setValue((theSelectionType & CHECK_NAMING) != 0);
+    aDump->boolean("geometric_selection")->setValue((theSelectionType & CHECK_GEOMETRICAL) != 0);
+    aDump->boolean("weak_naming")->setValue((theSelectionType & CHECK_WEAK) != 0);
   }
   bool isProblem = !aDump.get() || !aDump->error().empty(); // after "finish" dump will be removed
   if (isProblem && aDump.get()) {
index a7ce541f2aa7a71e7bce714288104a660dbedfc3..1f6aca0631f2e7d36019e787f24c5efee4428da0 100644 (file)
@@ -28,6 +28,8 @@ INCLUDE_DIRECTORIES(${QT_INCLUDES})
 # additional preprocessor / compiler flags
 ADD_DEFINITIONS(${QT_DEFINITIONS})
 
+SET(UPDATE_TRANSLATION OFF)
+
 SET(PROJECT_HEADERS
   ModuleBase.h
   ModuleBase_ActionInfo.h
@@ -228,6 +230,10 @@ SET(PROJECT_SOURCES
   ModuleBase_IStepPrs.cpp
 )
 
+SET(TEXT_RESOURCES
+    ModuleBase_msg_fr.ts
+)
+
 SET(PROJECT_LIBRARIES
        Config
        Events
@@ -247,10 +253,21 @@ SET(PROJECT_LIBRARIES
 # sources / moc wrappings
 QT_WRAP_MOC(PROJECT_AUTOMOC ${PROJECT_MOC_HEADERS})
 
-#QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+IF (${UPDATE_TRANSLATION})
+    SET(PROJECT_FILES ${PROJECT_SOURCES} ${PROJECT_HEADERS} )
+    QT5_CREATE_TRANSLATION(QM_RESOURCES
+                           ${PROJECT_FILES}
+                           ${TEXT_RESOURCES}
+                           OPTIONS -extensions cpp -no-recursive
+                          )
+ELSE(${UPDATE_TRANSLATION})
+    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})
-#SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES} ${PROJECT_RESOURCES})
+SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES} ${PROJECT_RESOURCES})
 
 INCLUDE_DIRECTORIES(
     ${OpenCASCADE_INCLUDE_DIR}
@@ -269,7 +286,15 @@ IF(${HAVE_SALOME})
 ENDIF(${HAVE_SALOME})
 
 ADD_DEFINITIONS(-DMODULEBASE_EXPORTS ${OpenCASCADE_DEFINITIONS})
-ADD_LIBRARY(ModuleBase SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${PROJECT_AUTOMOC})
+ADD_LIBRARY(ModuleBase SHARED
+       ${PROJECT_SOURCES}
+       ${PROJECT_HEADERS}
+       ${PROJECT_AUTOMOC}
+        ${TEXT_RESOURCES}
+        ${QM_RESOURCES}
+)
+
 TARGET_LINK_LIBRARIES(ModuleBase GeomAPI ${PROJECT_LIBRARIES})
 
 INSTALL(TARGETS ModuleBase DESTINATION ${SHAPER_INSTALL_BIN})
+INSTALL(FILES ${QM_RESOURCES} DESTINATION ${SHAPER_INSTALL_QM_RESOURCES})
index 22b276fd2d4c84613421ba523d618077e416a7b4..046c8abb55ee9674f57b598bf407df3f54f28037 100644 (file)
@@ -23,6 +23,7 @@
 #include "ModuleBase_IPropertyPanel.h"
 #include "ModuleBase_PageWidget.h"
 #include "ModuleBase_ModelDialogWidget.h"
+#include "ModuleBase_Tools.h"
 
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Events.h>
@@ -46,9 +47,10 @@ ModuleBase_Dialog::ModuleBase_Dialog(ModuleBase_IWorkshop* theParent, const QStr
                                      myActiveWidget(0)
 {
   ModuleBase_WidgetFactory aFactory(myDescription, myWorkshop);
-  std::string aTitle = aFactory.widgetAPI()->getProperty(FEATURE_TEXT);
+  QString aTitle = ModuleBase_Tools::translate("ModuleBase_Dialog",
+      aFactory.widgetAPI()->getProperty(FEATURE_TEXT));
 
-  setWindowTitle(aTitle.c_str());
+  setWindowTitle(aTitle);
 
   SessionPtr aMgr = ModelAPI_Session::get();
   std::shared_ptr<ModelAPI_Document> aDoc = aMgr->activeDocument();
index c52c0d952907c43ee2e4a674413165f5714e3f51..d7f1a32c53973ab0f3386df88640ae72d2835fa3 100644 (file)
@@ -21,6 +21,7 @@
 #define ModuleBase_IViewer_H
 
 #include "ModuleBase.h"
+
 #include <QObject>
 #include <QMap>
 #include <AIS_InteractiveContext.hxx>
@@ -31,6 +32,11 @@ class QMouseEvent;
 class QKeyEvent;
 class QContextMenuEvent;
 class ModuleBase_IViewWindow;
+#ifdef HAVE_SALOME
+class OCCViewer_Fitter;
+#else
+class AppElements_Fitter;
+#endif
 
 /**
  * \ingroup GUI
@@ -191,8 +197,17 @@ Q_OBJECT
     myShowHighlight = false;
   }
 
+#ifdef HAVE_SALOME
+  virtual void setFitter(OCCViewer_Fitter* theFitter) = 0;
+  virtual OCCViewer_Fitter* fitter() const = 0;
+#else
+  virtual void setFitter(AppElements_Fitter* theFitter) = 0;
+  virtual AppElements_Fitter* fitter() const = 0;
+#endif
+
   static Handle(Prs3d_Drawer) DefaultHighlightDrawer;
 
+
 signals:
   /// Signal emited when last view window is closed
   void lastViewClosed();
index dd17a65d83edddf770475a99311d68f2f03732a2..89546edfd4bacde2ac2f40b91a4258dbcef1a299 100644 (file)
@@ -155,6 +155,7 @@ void ModuleBase_ModelWidget::processValueState()
 Events_InfoMessage ModuleBase_ModelWidget::getValueStateError() const
 {
   Events_InfoMessage aMessage;
+  aMessage.setContext(context());
 
   ModuleBase_ModelWidget::ValueState aState = getValueState();
   if (aState != ModuleBase_ModelWidget::Stored) {
index a3c4d0ebdbf3c7c874d2abc25315c6594763d22d..2d6e806705cf5f35ceb4808ecab2c8dfc2fa6528 100644 (file)
@@ -156,7 +156,7 @@ void setFocus(QWidget* theWidget, const QString& theInfo)
 {
   theWidget->setFocus();
   // rectangle of focus is not visible on tool button widgets
-  theWidget->repaint();
+  theWidget->update();
 #ifdef DEBUG_SET_FOCUS
   qDebug(QString("setFocus: %1").arg(theInfo).toStdString().c_str());
 #endif
@@ -939,7 +939,7 @@ bool askToDelete(const std::set<FeaturePtr> theFeatures,
   if (!ModelAPI_Tools::allDocumentsActivated(aNotActivatedNames)) {
     if (ModuleBase_Tools::hasModuleDocumentFeature(theFeatures))
       aNotActivatedDocWrn =
-        QObject::tr("Selected objects can be used in Part documents which are not loaded:%1.\n")
+        QObject::tr("Selected objects can be used in Part documents which are not loaded: %1.\n")
                             .arg(aNotActivatedNames.c_str());
   }
 
index 51f982cb0528894d35960ab8e202b153c78f90ee..fea77f589d706658416dac330dc1313f3741b4c6 100644 (file)
@@ -233,7 +233,7 @@ ModuleBase_WidgetExprEditor::ModuleBase_WidgetExprEditor( QWidget* theParent,
   aMainLay->addWidget(myResultLabel);
   myEditor = new ExpressionEditor(this);
   myEditor->setMinimumHeight(20);
-  myEditor->setPlaceHolderText( QString::fromStdString( thePlaceHolder ) );
+  myEditor->setPlaceHolderText( translate( thePlaceHolder ) );
   aMainLay->addWidget(myEditor);
   this->setLayout(aMainLay);
 
index 23728c5696ed0be83a2054d8285c930db7659681..0cc45bf0947f676388cd9fb748f86c0286a6169e 100644 (file)
@@ -274,7 +274,8 @@ ModuleBase_PageBase* ModuleBase_WidgetFactory::createPageByType(const std::strin
   if (theType == WDG_GROUP) {
     QString aGroupName = qs(myWidgetApi->getProperty(CONTAINER_PAGE_NAME));
     ModuleBase_PageGroupBox* aPage = new ModuleBase_PageGroupBox(theParent);
-    aPage->setTitle(aGroupName);
+    aPage->setTitle(ModuleBase_Tools::translate(
+      myWidgetApi->myFeatureId, aGroupName.toStdString()));
     aResult = aPage;
   }
   else if (theType == WDG_OPTIONALBOX) {
index af8063f6abc936d0487bb6d8f7d77ff040556f33..b717bf1039c7c0dadc958836b56836424e9db179 100644 (file)
@@ -25,7 +25,9 @@
 #include <ModuleBase_Tools.h>
 
 #include <ModelAPI_AttributeString.h>
+#include <Config_Translator.h>
 
+#include <QTextCodec>
 #include <QLabel>
 #include <QVBoxLayout>
 
@@ -71,11 +73,21 @@ bool ModuleBase_WidgetLabel::restoreValueCustom()
   DataPtr aData = myFeature->data();
   AttributeStringPtr aStrAttr = aData->string(attributeID());
   if (aStrAttr.get()) {
-    std::string aMsg;
+    QString aText;
     if (aStrAttr.get()) {
-      aMsg = aStrAttr->value();
+      if (aStrAttr->isUValue()) { // already translated text
+        char16_t* aStr = aStrAttr->valueU();
+        std::wstring aWStr((wchar_t*)aStr);
+        static const int aBufSize = 1000;
+        static char aMBStr[aBufSize];
+        size_t aLen = wcstombs(aMBStr, aWStr.c_str(), aBufSize);
+        std::string aCodec = Config_Translator::codec("");
+        aText = QTextCodec::codecForName(aCodec.c_str())->toUnicode(aMBStr);
+      } else {
+        std::string aMsg = aStrAttr->value();
+        aText = ModuleBase_Tools::translate(myFeature->getKind(), aMsg);
+      }
     }
-    QString aText = ModuleBase_Tools::translate(myFeature->getKind(), aMsg);
     myLabel->setText(aText);
   }
   return true;
index 83dc65f57068644313d1bbc314cdd56acd632fdf..5e0e407e3d23b45d9f740712d4a633163a65d91d 100644 (file)
@@ -36,9 +36,9 @@ ModuleBase_WidgetLabelValue::ModuleBase_WidgetLabelValue(QWidget* theParent,
   aLayout->setContentsMargins(0, 0, 0, 0);
   aLayout->setSpacing(0);
 
-  QString aText = QString::fromStdString(theData->widgetLabel());
+  QString aText = translate(theData->widgetLabel());
   QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
-  QString aToolTip = QString::fromStdString(theData->widgetTooltip());
+  QString aToolTip = translate(theData->widgetTooltip());
 
   myLabel = new ModuleBase_LabelValue(theParent, aText, aToolTip, aLabelIcon);
   bool isOk;
index 8003a76f542cefc90bd670b3b78dbdb31fe96dde..e915477ed7948f52023ec495ecf4cefc000e2f11 100644 (file)
@@ -97,7 +97,7 @@ ModuleBase_WidgetLineEdit::ModuleBase_WidgetLineEdit(QWidget* theParent,
   if (!aLabelIcon.isEmpty())
     aLabel->setPixmap(ModuleBase_IconFactory::loadPixmap(aLabelIcon));
 
-  myLineEdit = new CustomLineEdit( this, QString::fromStdString( thePlaceHolder ) );
+  myLineEdit = new CustomLineEdit( this, translate( thePlaceHolder ) );
   // Here we do not use the Qt's standard method setPlaceHolderText() since it
   // draws the place holder only if there is no focus on widget;
   // we would like to see the place holder in the case of empty text
index 1740c62ffd732e623fd73c1bc67091195791889b..43b380cf7a7fb69f41702d7c66cf187d61abc48c 100644 (file)
@@ -165,7 +165,7 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
     }
   }
 
-  QString aToolTip = QString::fromStdString(theData->widgetTooltip());
+  QString aToolTip = translate(theData->widgetTooltip());
   QString anObjName = QString::fromStdString(attributeID());
   myListView = new ModuleBase_ListView(this, anObjName, aToolTip);
   connect(myListView->getControl(), SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
@@ -809,7 +809,7 @@ void ModuleBase_WidgetMultiSelector::updateSelectionList()
   }
 
   // We have to call repaint because sometimes the List control is not updated
-  myListView->getControl()->repaint();
+  myListView->getControl()->update();
 }
 
 //********************************************************************
index faf5ff52791e14db8726cac27fafe84c1298773d..ca7c3c055209afb2a4ecff874246bb7de8230777 100644 (file)
@@ -60,7 +60,7 @@ ModuleBase_WidgetPointInput::ModuleBase_WidgetPointInput(QWidget* theParent,
 
   myXSpin = new ModuleBase_ParamSpinBox(this);
   myXSpin->setAcceptVariables(aAcceptVariables);
-  myXSpin->setToolTip("X coordinate");
+  myXSpin->setToolTip(tr("X coordinate"));
   myXSpin->setValue(myDefaultValue[0]);
   QLabel* aXLbl = new QLabel(this);
   aXLbl->setPixmap(QPixmap(":pictures/x_size.png"));
@@ -68,7 +68,7 @@ ModuleBase_WidgetPointInput::ModuleBase_WidgetPointInput(QWidget* theParent,
 
   myYSpin = new ModuleBase_ParamSpinBox(this);
   myYSpin->setAcceptVariables(aAcceptVariables);
-  myYSpin->setToolTip("Y coordinate");
+  myYSpin->setToolTip(tr("Y coordinate"));
   myYSpin->setValue(myDefaultValue[1]);
   QLabel* aYLbl = new QLabel(this);
   aYLbl->setPixmap(QPixmap(":pictures/y_size.png"));
@@ -76,7 +76,7 @@ ModuleBase_WidgetPointInput::ModuleBase_WidgetPointInput(QWidget* theParent,
 
   myZSpin = new ModuleBase_ParamSpinBox(this);
   myZSpin->setAcceptVariables(aAcceptVariables);
-  myZSpin->setToolTip("Z coordinate");
+  myZSpin->setToolTip(tr("Z coordinate"));
   myZSpin->setValue(myDefaultValue[2]);
   QLabel* aZLbl = new QLabel(this);
   aZLbl->setPixmap(QPixmap(":pictures/z_size.png"));
index f872e4ec04da7a96c00d648c2c3cade136e098b5..f98ddc5c0b3d0046a80d6c78f42a889fe573ba41 100644 (file)
@@ -56,11 +56,11 @@ int ModuleBase_WidgetRadiobox::addPage(ModuleBase_PageBase* thePage,
   QRadioButton* aButton;
   if (theIcon.isNull()) {
     aButton = new QRadioButton(theName, aWgt);
-    aButton->setToolTip(theTooltip);
+    aButton->setToolTip(translate(theTooltip.toStdString()));
   }
   else {
     aButton = new QRadioButton(aWgt);
-    aButton->setToolTip(theName);
+    aButton->setToolTip(translate(theName.toStdString()));
   }
   aLay->addStretch();
   aLay->addWidget(aButton);
index 10437dca097d5844528e9b04e863f2cc412fc492..4b6871641c811f0d8af12addf410cd46508347e8 100644 (file)
@@ -43,6 +43,7 @@
 #include <StdSelect_BRepOwner.hxx>
 #include <TopoDS_Compound.hxx>
 #include <BRep_Builder.hxx>
+#include <TopExp_Explorer.hxx>
 
 #include <QLayout>
 #include <QPushButton>
@@ -324,7 +325,7 @@ ModuleBase_WidgetSelectionFilter::~ModuleBase_WidgetSelectionFilter()
       myListIO.Clear();
       myShowBtn->setChecked(false);
     }
-    aCtx->UpdateCurrentViewer();
+    myWorkshop->viewer()->update();
   }
   SelectorFeature = FeaturePtr();
   AttributeId = "";
@@ -534,7 +535,7 @@ void ModuleBase_WidgetSelectionFilter::onShowOnly(bool theShow)
       }
     }
   }
-  aCtx->UpdateCurrentViewer();
+  myWorkshop->viewer()->update();
 }
 
 void ModuleBase_WidgetSelectionFilter::updateSelectBtn()
@@ -572,12 +573,60 @@ void ModuleBase_WidgetSelectionFilter::clearCurrentSelection(bool toUpdate)
   }
 }
 
+void replaceSubShapesByResult(QList<ModuleBase_ViewerPrsPtr>& theResults, int theShapeType)
+{
+  QMap<ObjectPtr, QList<GeomShapePtr>> myResShapes;
+  // Sort sub-shapes by result
+  foreach (ModuleBase_ViewerPrsPtr aPrs, theResults) {
+    if (myResShapes.contains(aPrs->object()))
+      myResShapes[aPrs->object()].append(aPrs->shape());
+    else {
+      QList<GeomShapePtr> aShapes;
+      aShapes << aPrs->shape();
+      myResShapes[aPrs->object()] = aShapes;
+    }
+  }
+  // Find Results to replace by whole result
+  QList<GeomShapePtr> aShapes;
+  QList<ObjectPtr> aToReplace;
+  std::list<GeomShapePtr> aSubShapes;
+  foreach(ObjectPtr aObj, myResShapes.keys()) {
+    aShapes = myResShapes[aObj];
+    ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+    TopTools_MapOfShape aShapesMap;
+    if (aRes.get()) {
+      GeomShapePtr aSubShape = aRes->shape();
+      const TopoDS_Shape& aShape = aSubShape->impl<TopoDS_Shape>();
+      for (TopExp_Explorer anExp(aShape, (TopAbs_ShapeEnum)theShapeType);
+        anExp.More(); anExp.Next()) {
+        aShapesMap.Add(anExp.Current());
+      }
+    }
+    if (aShapes.count() == aShapesMap.Size())
+      aToReplace.append(aObj);
+  }
+  // Replace the found results
+  QList<ModuleBase_ViewerPrsPtr>::iterator aIt;
+  foreach(ObjectPtr aObj, aToReplace) {
+    for (aIt = theResults.begin(); aIt != theResults.end(); aIt++) {
+      if ((*aIt)->object() == aObj) {
+        theResults.removeAll(*aIt);
+        aIt--;
+      }
+    }
+    ModuleBase_ViewerPrsPtr aValue(new ModuleBase_ViewerPrs(aObj));
+    theResults.append(aValue);
+  }
+}
+
 void ModuleBase_WidgetSelectionFilter::onFeatureAccepted()
 {
   AttributePtr aAttr = mySelectorFeature->attribute(mySelectorAttribute);
   AttributeSelectionListPtr aSelListAttr =
     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aAttr);
   aSelListAttr->clear();
+  if (aSelListAttr->isWholeResultAllowed())
+    replaceSubShapesByResult(myValues, selectionType(aSelListAttr->selectionType().c_str()));
   foreach(ModuleBase_ViewerPrsPtr aPrs, myValues) {
     aSelListAttr->append(aPrs->object(), aPrs->shape());
   }
index 7d701aaf55616c5e93f9c54a17a02be658caf427..59e836e47229cbfd0d4da1051a68ad8d2b53e37b 100644 (file)
@@ -209,7 +209,9 @@ bool ModuleBase_WidgetSelector::isValidSelectionCustom(const ModuleBase_ViewerPr
 {
   GeomShapePtr aShape = myWorkshop->selection()->getShape(thePrs);
   ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
-  bool aValid = acceptSubShape(aShape, aResult);
+  bool aValid = aResult.get();
+  if (!isWholeResultAllowed())
+    aValid = acceptSubShape(aShape, aResult);
 
   if (aValid) {
     // In order to avoid selection of the same object
@@ -252,3 +254,16 @@ void ModuleBase_WidgetSelector::deactivate()
     aSelectAttr->removeTemporaryValues();
   }
 }
+
+//********************************************************************
+bool ModuleBase_WidgetSelector::isWholeResultAllowed() const
+{
+  AttributePtr anAttribute = attribute();
+  if (anAttribute.get()) {
+    AttributeSelectionListPtr aSelAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(anAttribute);
+    if (aSelAttr.get())
+      return aSelAttr->isWholeResultAllowed();
+  }
+  return false;
+}
index 904647f760a65d72f33e831b3830b28d7739a801..b8e8816347ce46138291dd9a84a3efc861a78a05 100644 (file)
@@ -81,6 +81,8 @@ Q_OBJECT
   /// a shape. If the attribute do not uses the shape, it is empty
   virtual QList<std::shared_ptr<ModuleBase_ViewerPrs>> getAttributeSelection() const;
 
+  virtual bool isWholeResultAllowed() const;
+
 protected:
   /// Returns true if envent is processed. The default implementation is empty, returns false.
   virtual bool processSelection();
index e5ea9338995ae5ac20362446cbfc2a8d0a26f6f2..c8d37d5d3ad3678481d40d680f07996d394746e6 100644 (file)
@@ -216,7 +216,8 @@ void ModuleBase_WidgetShapeSelector::updateSelectionName()
   bool isNameUpdated = false;
   AttributeSelectionPtr aSelect = aData->selection(attributeID());
   if (aSelect) {
-    myTextLine->setText(QString::fromStdString(aSelect->namingName(getDefaultValue())));
+    std::string aDefault = translate(getDefaultValue()).toStdString();
+    myTextLine->setText(QString::fromStdString(aSelect->namingName(aDefault)));
     isNameUpdated = true;
   }
   if (!isNameUpdated) {
@@ -232,7 +233,7 @@ void ModuleBase_WidgetShapeSelector::updateSelectionName()
         myTextLine->setText(QString::fromStdString(anAttrName));
       }
       else {
-        myTextLine->setText(getDefaultValue().c_str());
+        myTextLine->setText(translate(getDefaultValue()));
       }
     }
   }
index 405ddc1984038896cfa15fe9f562e27aa432a559..98d08af2081e900159fc56fe76d39988384d6888 100644 (file)
@@ -59,7 +59,7 @@ int ModuleBase_WidgetSwitch::addPage(ModuleBase_PageBase* thePage, const QString
 {
   int aSuperCount =
     ModuleBase_PagedContainer::addPage(thePage, theName, theCaseId, theIcon, theTooltip);
-  myCombo->addItem(theName);
+  myCombo->addItem(translate(theName.toStdString()));
   int aResultCount = myCombo->count();
   if (aResultCount == 2)
     myCombo->show();
index 188e2f0126cb2460869918fabfb92ad8039cba21..dc1904e4a2b414feedeab4f6c3c7f281b6aeb17f 100644 (file)
@@ -71,7 +71,7 @@ int ModuleBase_WidgetToolbox::addPage(ModuleBase_PageBase* thePage,
 {
   ModuleBase_PagedContainer::addPage(thePage, theName, theCaseId, theIcon, theTooltip);
   QFrame* aFrame = dynamic_cast<QFrame*>(thePage);
-  myToolBox->addItem(aFrame, theName, theIcon );
+  myToolBox->addItem(aFrame, translate(theName.toStdString()), theIcon );
   return myToolBox->count();
 }
 
diff --git a/src/ModuleBase/ModuleBase_msg_fr.ts b/src/ModuleBase/ModuleBase_msg_fr.ts
new file mode 100644 (file)
index 0000000..cf7e5f7
--- /dev/null
@@ -0,0 +1,341 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+  <context>
+    <name>ExpressionEditor</name>
+    <message>
+      <location filename="ModuleBase_WidgetExprEditor.cpp" line="65"/>
+      <source>Ctrl+Space</source>
+      <comment>Complete</comment>
+      <translation>Ctrl+Espace</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_FilterItem</name>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="192"/>
+      <source>Reverse the filter</source>
+      <translation>Inverser le filtre</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="202"/>
+      <source>Delete the filter</source>
+      <translation>Supprimer le filtre</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_FilterStarter</name>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="95"/>
+      <source>Selection by filters</source>
+      <translation>Sélection par filtres</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_ListView</name>
+    <message>
+      <location filename="ModuleBase_ListView.cpp" line="45"/>
+      <source>Copy</source>
+      <translation>Copie</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_ListView.cpp" line="51"/>
+      <source>Delete</source>
+      <translation>Effacer</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_PreferencesDlg</name>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="251"/>
+      <source>Edit preferences</source>
+      <translation>Modifier les préférences</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="267"/>
+      <source>Default</source>
+      <translation>Défaut</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="285"/>
+      <source>Desktop</source>
+      <translation>Bureau</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="291"/>
+      <source>Module</source>
+      <translation>Module</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="300"/>
+      <source>Viewer</source>
+      <translation>Vue</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="303"/>
+      <source>Horizontal gradient</source>
+      <translation>Dégradé horizontal</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="303"/>
+      <source>Vertical gradient</source>
+      <translation>Gradient vertical</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="303"/>
+      <source>First diagonal gradient</source>
+      <translation>Premier gradient en diagonale</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="304"/>
+      <source>Second diagonal gradient</source>
+      <translation>Deuxième gradient diagonal</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="304"/>
+      <source>First corner gradient</source>
+      <translation>Premier angle de dégradé</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="305"/>
+      <source>Second corner gradient</source>
+      <translation>Deuxième angle du dégradé</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="305"/>
+      <source>Third corner gradient</source>
+      <translation>Troisième angle de dégradé</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="306"/>
+      <source>Fourth corner gradient</source>
+      <translation>Quatrième angle</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="312"/>
+      <source>Background</source>
+      <translation>Arrière-plan</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="316"/>
+      <source>Viewer 3d</source>
+      <translation>Vue 3d</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="328"/>
+      <source>Default selection</source>
+      <translation>Sélection par défaut</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="330"/>
+      <source>Faces</source>
+      <translation>Faces</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="333"/>
+      <source>Edges</source>
+      <translation>Arêtes</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="336"/>
+      <source>Vertices</source>
+      <translation>Sommets</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="340"/>
+      <source>Selection sensitivity</source>
+      <translation>Sensibilité de sélection</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="342"/>
+      <source>Vertex</source>
+      <translation>Sommet</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="344"/>
+      <source>Edge</source>
+      <translation>Bord</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="347"/>
+      <source>Additional highlighting</source>
+      <translation>Mise en évidence supplémentaire</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="349"/>
+      <source>In 3d mode</source>
+      <translation>En mode 3D</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="351"/>
+      <source>In 2d mode</source>
+      <translation>En mode 2D</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="354"/>
+      <source>Color scale</source>
+      <translation>Échelle de couleur</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="356"/>
+      <source>X position</source>
+      <translation>Position X</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="361"/>
+      <source>Y position</source>
+      <translation>Position Y</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="366"/>
+      <source>Width</source>
+      <translation>Largeur</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="371"/>
+      <source>Height</source>
+      <translation>Hauteur</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="376"/>
+      <source>Intervals number</source>
+      <translation>Nombre d&apos;intervalles</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="381"/>
+      <source>Text height</source>
+      <translation>Hauteur du texte</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="386"/>
+      <source>Text color</source>
+      <translation>Couleur du texte</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="392"/>
+      <source>Main menu</source>
+      <translation>Menu principal</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="394"/>
+      <source>Size</source>
+      <translation>Taille</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="397"/>
+      <source>Number of rows</source>
+      <translation>Nombre de rangées</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Preferences.cpp" line="404"/>
+      <source>Show Status Bar</source>
+      <translation>Afficher la barre d&apos;état</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_WidgetFileSelector</name>
+    <message>
+      <location filename="ModuleBase_WidgetFileSelector.cpp" line="70"/>
+      <source>Select file...</source>
+      <translation>Choisir le dossier...</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_WidgetMultiSelector</name>
+    <message>
+      <location filename="ModuleBase_WidgetMultiSelector.cpp" line="133"/>
+      <source>Type</source>
+      <translation>Type</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetMultiSelector.cpp" line="188"/>
+      <source>Show only</source>
+      <translation>Montrer seulement</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetMultiSelector.cpp" line="199"/>
+      <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>
+      <location filename="ModuleBase_WidgetPointInput.cpp" line="63"/>
+      <source>X coordinate</source>
+      <translation>Coordonnée X</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetPointInput.cpp" line="71"/>
+      <source>Y coordinate</source>
+      <translation>Coordonnée Y</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetPointInput.cpp" line="79"/>
+      <source>Z coordinate</source>
+      <translation>Coordonnée Z</translation>
+    </message>
+  </context>
+  <context>
+    <name>ModuleBase_WidgetSelectionFilter</name>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="242"/>
+      <source>Filters</source>
+      <translation>Filtres</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="253"/>
+      <source>Add new filter...</source>
+      <translation>Ajouter un nouveau filtre...</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="276"/>
+      <source>Select</source>
+      <translation>Sélectionner</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="287"/>
+      <source>Number of selected objects:</source>
+      <translation>Nombre d&apos;objets sélectionnés:</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="293"/>
+      <source>Show only</source>
+      <translation>Montrer seulement</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="551"/>
+      <location filename="ModuleBase_WidgetSelectionFilter.cpp" line="631"/>
+      <source>Selection is empty</source>
+      <translation>La sélection est vide</translation>
+    </message>
+  </context>
+  <context>
+    <name>QObject</name>
+    <message>
+      <location filename="ModuleBase_Tools.cpp" line="942"/>
+      <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>
+      <location filename="ModuleBase_Tools.cpp" line="1011"/>
+      <source>Delete features</source>
+      <translation>Supprimer les fonctionnalités</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Tools.cpp" line="1021"/>
+      <source>The following parts will be deleted: %1.
+</source>
+      <translation>Les pièces suivantes seront supprimées : %1.
+
+</translation>
+    </message>
+    <message>
+      <location filename="ModuleBase_Tools.cpp" line="1039"/>
+      <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 513cabf11085b62902e992cdfeb249b68b5feb2a..718fa3f4367819c7b443d9734d0630ee41b38180 100644 (file)
@@ -40,6 +40,8 @@
 
 #include <QMessageBox>
 
+#include <ModuleBase_Tools.h>
+
 #include <string>
 #include <set>
 #include <sstream>
@@ -282,10 +284,16 @@ void ParametersPlugin_EvalListener::processObjectRenamedEvent(
 
   std::string aNotActivatedNames;
   if (!ModelAPI_Tools::allDocumentsActivated(aNotActivatedNames)) {
-    QMessageBox::StandardButton aRes = QMessageBox::warning(0, QObject::tr("Warning"),
-               QObject::tr("Selected objects can be used in Part documents which are not loaded: "
-                           "%1. Whould you like to continue?").arg(aNotActivatedNames.c_str()),
-               QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
+    static const std::string aMsgContext("ParametersPlugin");
+    static const std::string aMsgText =
+      "Selected objects can be used in Part documents which are not loaded: " +
+      std::string("%1. Would you like to continue?");
+    Events_InfoMessage aMsg(aMsgContext, aMsgText);
+    aMsg.arg(aNotActivatedNames.c_str());
+    QMessageBox::StandardButton aRes =
+      QMessageBox::warning(0, ModuleBase_Tools::translate(aMsgContext, "Warning"),
+        ModuleBase_Tools::translate(aMsg),
+        QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
     if (aRes != QMessageBox::Yes) {
       setParameterName(aResultParameter, aMessage->oldName());
       return;
index d03062163d77941b0130eac26b983f5a6b7e2953..9078329662e93044b3d61496b2e572539f63be1d 100644 (file)
@@ -60,7 +60,6 @@ enum ColumnType {
 
 const char* NoName = "<NoName>";
 const char* NoValue = "<NoValue>";
-const char* NotValid = "<NotValid>";
 
 /*!
  * \ingroup GUI
@@ -186,7 +185,8 @@ ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theP
   myTable = new ParametersPlugin_TreeWidget(this);
   myTable->setColumnCount(4);
   QStringList aHeaders;
-  aHeaders << tr("Name") << tr("Expression") << tr("Result") << tr("Comment");
+  aHeaders << translate("Name") << translate("Expression")
+           << translate("Result") << translate("Comment");
   myTable->setHeaderLabels(aHeaders);
   myTable->setColumnWidth(Col_Name, 200);
   myTable->setColumnWidth(Col_Equation, 100);
@@ -209,13 +209,13 @@ ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theP
 
   // Define root nodes
   QStringList aNames;
-  aNames<<tr("Parameters");
+  aNames<<translate("Parameters");
   myParameters = new QTreeWidgetItem(aNames);
   myParameters->setFlags(Qt::ItemIsEnabled);
   myTable->addTopLevelItem(myParameters);
 
   aNames.clear();
-  aNames<<tr("Features");
+  aNames<<translate("Features");
   myFeatures = new QTreeWidgetItem(aNames);
   myFeatures->setFlags(Qt::ItemIsEnabled);
   myTable->addTopLevelItem(myFeatures);
@@ -234,15 +234,15 @@ ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theP
 
   aBtnLayout->addStretch();
 
-  myAddBtn = new QPushButton(tr("Add"), this);
+  myAddBtn = new QPushButton(translate("Add"), this);
   connect(myAddBtn, SIGNAL(clicked(bool)), SLOT(onAdd()));
   aBtnLayout->addWidget(myAddBtn);
 
-  myInsertBtn = new QPushButton(tr("Insert"), this);
+  myInsertBtn = new QPushButton(translate("Insert"), this);
   connect(myInsertBtn, SIGNAL(clicked(bool)), SLOT(onInsert()));
   aBtnLayout->addWidget(myInsertBtn);
 
-  myRemoveBtn = new QPushButton(tr("Remove"), this);
+  myRemoveBtn = new QPushButton(translate("Remove"), this);
   connect(myRemoveBtn, SIGNAL(clicked(bool)), SLOT(onRemove()));
   aBtnLayout->addWidget(myRemoveBtn);
 
@@ -258,7 +258,7 @@ void ParametersPlugin_WidgetParamsMgr::setDialogButtons(QDialogButtonBox* theBut
   QWidget* aBtnParentWgt = myOkCancelBtn->parentWidget();
   QHBoxLayout* aBtnParentLayout = dynamic_cast<QHBoxLayout*>(aBtnParentWgt->layout());
 
-  QPushButton* aPreviewBtn = new QPushButton(tr("See preview"), aBtnParentWgt);
+  QPushButton* aPreviewBtn = new QPushButton(translate("See preview"), aBtnParentWgt);
   aBtnParentLayout->insertWidget(0, aPreviewBtn);
   aBtnParentLayout->insertStretch(1, 1);
   connect(aPreviewBtn, SIGNAL(clicked(bool)), SLOT(onShowPreview()));
@@ -293,8 +293,7 @@ bool ParametersPlugin_WidgetParamsMgr::storeValueCustom()
   int aId = 0;
   foreach(FeaturePtr aFeature, myParametersList) {
     if (!aValidator.isValid(aFeature->attribute(aAttrId), aArgs, aErr)) {
-      // TODO(spo): translate
-      QMessageBox::warning(this, tr("Warning"), aErr.messageString().c_str());
+      QMessageBox::warning(this, translate("Warning"), aErr.messageString().c_str());
       selectItemScroll(myParameters->child(aId));
       return false;
     }
@@ -435,13 +434,13 @@ QList<QStringList> ParametersPlugin_WidgetParamsMgr::
 
     std::string aName = aParameter->string(ParametersPlugin_Parameter::VARIABLE_ID())->value();
     if (aName.empty()) {
-      aValues << NoName;
+      aValues << translate(NoName);
     } else
       aValues << aName.c_str();
 
     std::string aExpr = aParameter->string(ParametersPlugin_Parameter::EXPRESSION_ID())->value();
     if (aName.empty()) {
-      aValues << NoValue;
+      aValues << translate(NoValue);
     } else
       aValues << aExpr.c_str();
 
@@ -486,7 +485,7 @@ void ParametersPlugin_WidgetParamsMgr::onCloseEditor(QWidget* theEditor,
           aText.replace(" ", "");
         }
         if (hasName(aText)) {
-          myMessage = tr("Name '%1' already exists.").arg(aText);
+          myMessage = translate("Name '%1' already exists.").arg(aText);
           QTimer::singleShot(50, this, SLOT(sendWarning()));
           return;
         }
@@ -574,8 +573,8 @@ FeaturePtr ParametersPlugin_WidgetParamsMgr::createParameter() const
 QTreeWidgetItem* ParametersPlugin_WidgetParamsMgr::createNewItem(QTreeWidgetItem* theParent) const
 {
   QStringList aValues;
-  aValues << NoName;
-  aValues << NoValue;
+  aValues << translate(NoName);
+  aValues << translate(NoValue);
 
   QTreeWidgetItem* aItem = new QTreeWidgetItem(aValues);
   if (theParent == myParameters) {
@@ -768,7 +767,7 @@ bool ParametersPlugin_WidgetParamsMgr::hasName(const QString& theName) const
 
 void ParametersPlugin_WidgetParamsMgr::sendWarning()
 {
-  QMessageBox::warning(this, tr("Warning"), myMessage);
+  QMessageBox::warning(this, translate("Warning"), myMessage);
   QTreeWidgetItem* aItem = myTable->currentItem();
   if (aItem)
     myTable->editItem(aItem);
@@ -819,7 +818,7 @@ bool ParametersPlugin_WidgetParamsMgr::isValid()
   for(int i = 0; i < myParameters->childCount(); i++) {
     aItem = myParameters->child(i);
     if ((aItem->text(Col_Name) == NoName) ||
-        (aItem->text(Col_Equation) == NoValue) ||
+        (aItem->text(Col_Equation) == translate(NoValue)) ||
         (!ModelAPI_Expression::isVariable(aItem->text(Col_Name).toStdString())) ) {
       return false;
     }
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 47f29b01bc86c4494d235d84a3f76fe2856e6879..0ddb4597d06b9c238e1b55e287ef0d76156a7c02 100644 (file)
@@ -26,6 +26,8 @@ INCLUDE_DIRECTORIES(${QT_INCLUDES})
 # additional preprocessor / compiler flags
 ADD_DEFINITIONS(${QT_DEFINITIONS})
 
+SET(UPDATE_TRANSLATION OFF)
+
 SET(PROJECT_HEADERS
     PartSet.h
     PartSet_Constants.h
@@ -115,9 +117,9 @@ SET(PROJECT_RESOURCES
     PartSet_icons.qrc
 )
 
-#SET(TEXT_RESOURCES
-#    PartSet_msg_fr.ts
-#)
+SET(TEXT_RESOURCES
+    PartSet_msg_fr.ts
+)
 
 SET(PROJECT_LIBRARIES
     ModuleBase
@@ -135,17 +137,24 @@ QT_WRAP_MOC(PROJECT_AUTOMOC ${PROJECT_MOC_HEADERS})
 
 # sources / rcc wrappings
 QT_ADD_RESOURCES(PROJECT_COMPILED_RESOURCES ${PROJECT_RESOURCES})
-#QT4_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
-#QT4_CREATE_TRANSLATION(QM_RESOURCES
-#                       ${PROJECT_SOURCES}
-#                       ${TEXT_RESOURCES}
-#                       OPTIONS -extensions cpp -no-recursive
-#                       )
-
-#SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES} ${QM_RESOURCES})
-SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES})
-#SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES} ${PROJECT_RESOURCES})
-SOURCE_GROUP ("Resource Files" FILES ${PROJECT_RESOURCES})
+
+IF (${UPDATE_TRANSLATION})
+    SET(PROJECT_FILES ${PROJECT_SOURCES} ${ROJECT_HEADERS} )
+    QT5_CREATE_TRANSLATION(QM_RESOURCES
+                           ${PROJECT_FILES}
+                           ${TEXT_RESOURCES}
+                           OPTIONS -extensions cpp -no-recursive
+                          )
+ELSE(${UPDATE_TRANSLATION})
+    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})
+#SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES})
+SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES} ${PROJECT_RESOURCES})
+#SOURCE_GROUP ("Resource Files" FILES ${PROJECT_RESOURCES})
 
 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/XGUI
                     ${PROJECT_SOURCE_DIR}/src/Config
@@ -179,8 +188,8 @@ ADD_LIBRARY(PartSet SHARED
     ${PROJECT_HEADERS}
     ${PROJECT_COMPILED_RESOURCES}
     ${PROJECT_AUTOMOC}
-#    ${TEXT_RESOURCES}
-#    ${QM_RESOURCES}
+    ${TEXT_RESOURCES}
+    ${QM_RESOURCES}
 )
 
 # The Qt5Widgets_LIBRARIES variable also includes QtGui and QtCore
@@ -189,4 +198,4 @@ TARGET_LINK_LIBRARIES(PartSet ${PROJECT_LIBRARIES} XGUI ModelAPI GeomAlgoAPI)
 ADD_DEPENDENCIES(PartSet ModuleBase)
 
 INSTALL(TARGETS PartSet DESTINATION ${SHAPER_INSTALL_BIN})
-#INSTALL(FILES ${QM_RESOURCES} DESTINATION bin)
+INSTALL(FILES ${QM_RESOURCES} DESTINATION ${SHAPER_INSTALL_QM_RESOURCES})
index 549a5395e4be6ad7c3409a029218c7126b5a097c..21465eb1cb133887e2a96caf458beb7fe9b87fd6 100644 (file)
@@ -140,7 +140,7 @@ bool PartSet_CustomPrs::displayPresentation(
       PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
       XGUI_Workshop* aWorkshop = workshop();
       aRedisplayed = aWorkshop->displayer()->displayAIS(myPresentations[theFlag],
-                                         false/*load object in selection*/, false);
+                                         false/*load object in selection*/, 0, false);
       aContext->SetZLayer(anOperationPrs, aModule->getVisualLayerId());
       isModified = true;
     }
index 8e5405d11d4060148c72bcbe45217ff291828153..c7660c93d49ca3c3549f4cb6599a07761129c7da 100644 (file)
@@ -187,7 +187,7 @@ void PartSet_ExternalPointsMgr::updateCenterPresentations()
     else
       myPresentations[aPrs->object()] = aList;
     foreach(AISObjectPtr anAIS, aList) {
-      aDisplayer->displayAIS(anAIS, false);
+      aDisplayer->displayAIS(anAIS, false, 0, false);
       aWorkshop->selectionActivate()->activateAIS(anAIS->impl<Handle(AIS_InteractiveObject)>(),
         TopAbs_VERTEX, false);
     }
index 7859a701c54d767aa784f40617a6538a50141bf4..0ad3ce8f22bf20accb23f184853d37930ddd21ac 100644 (file)
 #include "PartSet_Filters.h"
 #include "PartSet_FilterInfinite.h"
 
+#ifdef _DEBUG
+#include <QDebug>
+#endif
+
 #include <PartSetPlugin_Remove.h>
 #include <PartSetPlugin_Part.h>
 #include <PartSetPlugin_Duplicate.h>
 
 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
 
-#ifdef _DEBUG
-#include <QDebug>
-#endif
-
 /*!Create and return new instance of XGUI_Module*/
 extern "C" PARTSET_EXPORT ModuleBase_IModule* createModule(ModuleBase_IWorkshop* theWshop)
 {
@@ -441,8 +441,8 @@ void PartSet_Module::updatePresentationsOnStart(ModuleBase_Operation* theOperati
   ModuleBase_OperationFeature* aFOperation =
     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
   if (aFOperation) {
-    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeArguments, true);
-    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeResults, true);
+    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeArguments, false);
+    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeResults, false);
   }
 }
 
@@ -454,8 +454,8 @@ void PartSet_Module::operationResumed(ModuleBase_Operation* theOperation)
   ModuleBase_OperationFeature* aFOperation =
     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
   if (aFOperation) {
-    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeArguments, true);
-    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeResults, true);
+    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeArguments, false);
+    myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeResults, false);
   }
 }
 
@@ -857,6 +857,8 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
     connect(aLabelWgt, SIGNAL(showConstraintToggled(int, bool)),
       mySketchMgr, SLOT(onShowConstraintsToggle(int, bool)));
     connect(aLabelWgt, SIGNAL(showFreePoints(bool)), mySketchMgr, SLOT(onShowPoints(bool)));
+    connect(aLabelWgt, SIGNAL(autoConstraints(bool)),
+      sketchReentranceMgr(), SLOT(onAutoConstraints(bool)));
     aLabelWgt->setShowPointsState(mySketchMgr->isShowFreePointsShown());
     aWgt = aLabelWgt;
   } else if (theType == "sketch-2dpoint_selector") {
@@ -1444,16 +1446,20 @@ void PartSet_Module::processEvent(const std::shared_ptr<Events_Message>& theMess
     XGUI_Displayer* aDisplayer = aWorkshop->displayer();
     QObjectPtrList aObjects = aDisplayer->displayedObjects();
     bool aHidden;
+    bool aUpdateViewer = false;
     foreach(ObjectPtr aObj, aObjects) {
       aHidden = !aObj->data() || !aObj->data()->isValid() ||
         aObj->isDisabled() || (!aObj->isDisplayed());
-      if (!aHidden)
+      if (!aHidden) {
         aDisplayer->redisplay(aObj, false);
+        aUpdateViewer = true;
+      }
     }
-    aDisplayer->updateViewer();
+    if (aUpdateViewer)
+     aDisplayer->updateViewer();
     // Update tree items if they are expanded
     if (needUpdate) {
-      aTreeView->viewport()->repaint(aTreeView->viewport()->rect());
+      aTreeView->viewport()->update(aTreeView->viewport()->rect());
     }
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
index f9d91312c53ca0bcbceb0afb742d854fe38dff0d..f27f35f1910f58dcb960a425dba5781c233621f7 100644 (file)
@@ -127,6 +127,9 @@ void PartSet_OperationPrs::Compute(
     // change deviation coefficient to provide more precise circle
     // as there is no result, the shape is processed to correct deviation. To be unified
     ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, aDrawer);
+    Handle(Prs3d_Drawer) aHighlightDrawer = DynamicHilightAttributes();
+    if (!aHighlightDrawer.IsNull())
+      ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, aHighlightDrawer);
 
     if (myUseAISWidth) {
       Handle(AIS_InteractiveObject) anIO = anIter.Value();
index 1b2b688fd1a55986faff84f982cbd827ab71d43b..59fbfa96edecbb2bb0b055177e1fca6800e81ecd 100644 (file)
@@ -74,8 +74,13 @@ void PartSet_OverconstraintListener::setActive(const bool& theActive)
     PartSet_Module* aModule = module();
     CompositeFeaturePtr aSketch = aModule->sketchMgr()->activeSketch();
     if (aSketch.get()) {
-      std::string aDOFMessage = aSketch->string(SketchPlugin_Sketch::SOLVER_DOF())->value();
-      myIsFullyConstrained = QString(aDOFMessage.c_str()).contains("DoF = 0");
+      QString aDOFMessage(aSketch->string(SketchPlugin_Sketch::SOLVER_DOF())->value().c_str());
+      if (aDOFMessage.contains('=')) {
+        // to support old data
+        aDOFMessage =
+          aDOFMessage.right(aDOFMessage.length() - aDOFMessage.lastIndexOf('=')).trimmed();
+      }
+      myIsFullyConstrained = (aDOFMessage == "0");
     }
   }
 }
index b3f2682b1dfca53a8d8e504f543d81102afc6569..13cbcaafd737951bdb365c7b3fbb868591623e28 100644 (file)
@@ -139,9 +139,9 @@ void PartSet_PreviewPlanes::showPreviewPlanes(ModuleBase_IWorkshop* theWorkshop)
     myXYPlane = createPreviewPlane(anOrigin, aXYDir, aB);
   }
   XGUI_Displayer* aDisp = XGUI_Tools::workshop(theWorkshop)->displayer();
-  aDisp->displayAIS(myYZPlane, true, false);
-  aDisp->displayAIS(myXZPlane, true, false);
-  aDisp->displayAIS(myXYPlane, true, false);
+  aDisp->displayAIS(myYZPlane, true, 0, false);
+  aDisp->displayAIS(myXZPlane, true, 0, false);
+  aDisp->displayAIS(myXYPlane, true, 0, false);
   myPreviewDisplayed = true;
 }
 
index e936d729bdd6952ba32ada7763f5cb52f6bf48df..1c88fc4f6bf76b4f5e81138a30fd2c795abdae34 100644 (file)
@@ -70,6 +70,8 @@
 #include <SketchPlugin_Point.h>
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintParallel.h>
@@ -168,7 +170,7 @@ PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
   : QObject(theModule), myModule(theModule), myIsEditLaunching(false), myIsDragging(false),
     myDragDone(false), myIsMouseOverWindow(false),
     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),
-    myIsPopupMenuActive(false), myExternalPointsMgr(0)
+    myIsPopupMenuActive(false), myExternalPointsMgr(0), myNoDragMoving(false)
 {
   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
@@ -353,15 +355,23 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
-  if (!aViewer->canDragByMouse())
-    return;
+  //if (!aViewer->canDragByMouse())
+  //  return;
 
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                (getCurrentOperation());
   if (!aFOperation)
     return;
 
-  if (aFOperation->isEditOperation()) {
+  bool isEditing = aFOperation->isEditOperation();
+  bool aCanDrag = aViewer->canDragByMouse();
+
+  //if (!aViewer->canDragByMouse() && isEditing) {
+  //  // Do not edit by dragging
+  //  return;
+  //}
+
+  if (isEditing) {
     // If the current widget is a selector, do nothing, it processes the mouse press
     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
     if(anActiveWidget && anActiveWidget->isViewerSelector()) {
@@ -381,16 +391,10 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
     if ((!isSketchOpe) && (!isSketcher))
       return;
 
-    bool isEditing = aFOperation->isEditOperation();
-
     // Ignore creation sketch operation
     if ((!isSketcher) && (!isEditing))
       return;
 
-    Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
-    // Remember highlighted objects for editing
-    ModuleBase_ISelection* aSelect = aWorkshop->selection();
-
     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
     storeSelection(aHasShift ? ST_SelectAndHighlightType : ST_HighlightType, myCurrentSelection);
 
@@ -406,9 +410,10 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
     get2dPoint(theWnd, theEvent, myCurrentPoint);
     if (isSketcher) {
-      myIsDragging = true;
-      myDragDone = false;
-
+      if (aCanDrag) {
+        myIsDragging = true;
+        myDragDone = false;
+      }
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
       launchEditing();
       if (aFeature.get() != NULL) {
@@ -434,9 +439,10 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       myIsEditLaunching = !myModule->sketchReentranceMgr()->isInternalEditActive();
       aFOperation->commit();
 
-      myIsDragging = true;
-      myDragDone = false;
-
+      if (aCanDrag) {
+        myIsDragging = true;
+        myDragDone = false;
+      }
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
       launchEditing();
       myIsEditLaunching = aPrevLaunchingState;
@@ -466,27 +472,44 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse
   bool aWasDragging = myIsDragging;
   myIsDragging = false;
 
-  if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))
+  if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent)) {
     return;
-
+  }
   // if mouse is pressed when it was over view and at release the mouse is out of view, do nothing
-  if (!myIsMouseOverViewProcessed)
+  if (!myIsMouseOverViewProcessed) {
     return;
-
+  }
   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
-  if (!aViewer->canDragByMouse())
-    return;
-  ModuleBase_Operation* aOp = getCurrentOperation();
+  //if (!aViewer->canDragByMouse())
+  //  return;
+  ModuleBase_OperationFeature* aOp =
+      dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
   if (aOp) {
-    if (isNestedSketchOperation(aOp)) {
-      // Only for sketcher operations
-      if (aWasDragging) {
-        if (myDragDone) {
-          /// the previous selection is lost by mouse release in the viewer(Select method), but
-          /// it is still stored in myCurrentSelection. So, it is possible to restore selection
-          /// It is important for drag(edit with mouse) of sketch entities.
-          restoreSelection(myCurrentSelection);
-          myCurrentSelection.clear();
+    bool aStartNoDragOperation = !aViewer->canDragByMouse() && aOp->isEditOperation();
+    if (aStartNoDragOperation || myNoDragMoving) {
+      // Process edit operation without dragging
+      if (myCurrentSelection.size() > 0)
+        myNoDragMoving = !myNoDragMoving;
+      else
+        myNoDragMoving = false;
+      if (myNoDragMoving)
+        return;
+      else {
+        restoreSelection(myCurrentSelection);
+        myCurrentSelection.clear();
+      }
+    }
+    else {
+      if (isNestedSketchOperation(aOp)) {
+        // Only for sketcher operations
+        if (aWasDragging) {
+          if (myDragDone) {
+            /// the previous selection is lost by mouse release in the viewer(Select method), but
+            /// it is still stored in myCurrentSelection. So, it is possible to restore selection
+            /// It is important for drag(edit with mouse) of sketch entities.
+            restoreSelection(myCurrentSelection);
+            myCurrentSelection.clear();
+          }
         }
       }
     }
@@ -514,10 +537,13 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     qDebug(QString("%1").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
   }
 #endif
-
   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
     return;
 
+  ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
+  XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
+
   if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {
 #ifdef DRAGGING_DEBUG
     QTime t;
@@ -536,44 +562,46 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
       // the feature is to be erased here, but it is correct to call canDisplayObject because
       // there can be additional check (e.g. editor widget in distance constraint)
       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                 (getCurrentOperation());
+        (getCurrentOperation());
       if (aFOperation) {
         FeaturePtr aFeature = aFOperation->feature();
         visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
       }
     }
+    aDisplayer->updateViewer();
 #ifdef DRAGGING_DEBUG
     cout << "Mouse move processing " << t.elapsed() << endl;
 #endif
   }
   //myClickedPoint.clear();
 
-  if (myIsDragging) {
+  if (myIsDragging || myNoDragMoving) {
     // 1. the current selection is saved in the mouse press method in order to restore it after
     //    moving
     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
     // deselected). This flag should be restored in the slot, processed the mouse release signal.
-
     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
     if (!aCurrentOperation)
       return;
     if (isSketchOperation(aCurrentOperation))
       return; // No edit operation activated
 
+#ifdef DRAGGING_DEBUG
+    QTime t;
+    t.start();
+#endif
+
     Handle(V3d_View) aView = theWnd->v3dView();
     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
     Point aMousePnt;
     get2dPoint(theWnd, theEvent, aMousePnt);
 
     std::shared_ptr<GeomAPI_Pnt2d> anOriginalPosition = std::shared_ptr<GeomAPI_Pnt2d>(
-                            new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
+      new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
     std::shared_ptr<GeomAPI_Pnt2d> aCurrentPosition = std::shared_ptr<GeomAPI_Pnt2d>(
-                            new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
+      new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
 
-    ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
-    XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
-    XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the
     // viewer happens by deselect/select the modified objects. The flag should be restored after
     // the selection processing. The update viewer should be also called.
@@ -582,7 +610,7 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
-                                          aLast = myCurrentSelection.end();
+      aLast = myCurrentSelection.end();
     // 4. the features and attributes modification(move)
     bool isModified = false;
     for (; anIt != aLast; anIt++) {
@@ -592,7 +620,7 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
       // Process selection by attribute: the priority to the attribute
       if (!anAttributes.empty()) {
         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
-                                               anAttLast = anAttributes.end();
+          anAttLast = anAttributes.end();
         for (; anAttIt != anAttLast; anAttIt++) {
           AttributePtr anAttr = *anAttIt;
           if (anAttr.get() == NULL)
@@ -606,7 +634,7 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
               bool isImmutable = aPoint->setImmutable(true);
 
               std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
-                       <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+                <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
               aMessage->setMovedAttribute(aPoint);
               aMessage->setOriginalPosition(anOriginalPosition);
               aMessage->setCurrentPosition(aCurrentPosition);
@@ -617,13 +645,14 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
             }
           }
         }
-      } else {
+      }
+      else {
         // Process selection by feature
         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
         if (aSketchFeature) {
           std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
-                    <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+            <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
           aMessage->setMovedObject(aFeature);
           aMessage->setOriginalPosition(anOriginalPosition);
           aMessage->setCurrentPosition(aCurrentPosition);
@@ -646,6 +675,10 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
     aDisplayer->updateViewer();
 
+#ifdef DRAGGING_DEBUG
+    cout << "Mouse move processing " << t.elapsed() << endl;
+#endif
+
     myDragDone = true;
     myCurrentPoint = aMousePnt;
   }
@@ -926,7 +959,9 @@ bool PartSet_SketcherMgr::isEntity(const std::string& theId)
   return (theId == SketchPlugin_Line::ID()) ||
          (theId == SketchPlugin_Point::ID()) ||
          (theId == SketchPlugin_Arc::ID()) ||
-         (theId == SketchPlugin_Circle::ID());
+         (theId == SketchPlugin_Circle::ID()) ||
+         (theId == SketchPlugin_Ellipse::ID()) ||
+         (theId == SketchPlugin_EllipticArc::ID());
 }
 
 bool PartSet_SketcherMgr::isExternalFeature(const FeaturePtr& theFeature)
@@ -1070,10 +1105,18 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   myExternalPointsMgr = new PartSet_ExternalPointsMgr(myModule->workshop(), myCurrentSketch);
 
   workshop()->viewer()->set2dMode(true);
+
+  PartSet_Fitter* aFitter = new PartSet_Fitter(this);
+  myModule->workshop()->viewer()->setFitter(aFitter);
 }
 
 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
 {
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+  PartSet_Fitter* aFitter = (PartSet_Fitter*)myModule->workshop()->viewer()->fitter();
+  myModule->workshop()->viewer()->setFitter(0);
+  delete aFitter;
+
   myIsMouseOverWindow = false;
   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
@@ -1085,8 +1128,6 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   }
   onShowPoints(false);
 
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
-
   DataPtr aData = myCurrentSketch->data();
   if (!aData->isValid()) {
     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
@@ -2071,3 +2112,59 @@ void PartSet_SketcherMgr::onShowPoints(bool toShow)
   if (aToUpdate)
     aViewer->update();
 }
+
+
+void PartSet_Fitter::fitAll(Handle(V3d_View) theView)
+{
+  CompositeFeaturePtr aSketch = mySketchMgr->activeSketch();
+
+  ModuleBase_IWorkshop* aWorkshop = mySketchMgr->module()->workshop();
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
+  XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
+
+  Bnd_Box aBndBox;
+  int aNumberOfSubs = aSketch->numberOfSubs();
+  double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
+  for (int i = 0; i < aNumberOfSubs; i++) {
+    FeaturePtr aFeature = aSketch->subFeature(i);
+    if (aDisplayer->isVisible(aFeature)) {
+      AISObjectPtr aAisPtr = aDisplayer->getAISObject(aFeature);
+      Handle(AIS_InteractiveObject) aAisObj = aAisPtr->impl<Handle(AIS_InteractiveObject)>();
+      if (!aAisObj->IsInfinite()) {
+        Bnd_Box aBox;
+        aAisObj->BoundingBox(aBox);
+        aBndBox.Add(aBox);
+      }
+    }
+    else {
+      std::list<ResultPtr> aResults = aFeature->results();
+      std::list<ResultPtr>::const_iterator aIt;
+      ResultPtr aRes;
+      for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
+        aRes = (*aIt);
+        if (aRes->isDisplayed()) {
+          FeaturePtr aFeature = ModelAPI_Feature::feature(aRes);
+          if (aFeature.get()) {
+            std::shared_ptr<SketchPlugin_Feature> aSPFeature =
+              std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+            if (aSPFeature.get()) {
+              bool isAxiliary =
+                aSPFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value();
+              if (!(aSPFeature->isExternal() || isAxiliary)) {
+                GeomShapePtr aShape = aRes->shape();
+                aShape->computeSize(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
+                Bnd_Box aBox;
+                aBox.Update(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
+                aBndBox.Add(aBox);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  if (aBndBox.IsVoid())
+    theView->FitAll();
+  else
+    theView->FitAll(aBndBox, 0.01);
+}
index c036615b5ee29855a4495cceedd625903b47b521..7259514a4eb54083d520cf7e8863bc929d96a348 100644 (file)
 
 #include <GeomAPI_Pln.h>
 
+#ifdef HAVE_SALOME
+  #include <OCCViewer_ViewModel.h>
+#else
+  #include <AppElements_Viewer.h>
+#endif
+
+
 #include <SelectMgr_IndexedMapOfOwner.hxx>
 #include <SelectMgr_ListOfFilter.hxx>
 
@@ -55,11 +62,33 @@ class ModuleBase_ModelWidget;
 class ModuleBase_Operation;
 class XGUI_OperationMgr;
 class XGUI_Workshop;
+class XGUI_Displayer;
 class PartSet_ExternalPointsMgr;
 
 class AIS_InteractiveObject;
 
 class QMouseEvent;
+class PartSet_SketcherMgr;
+
+#ifdef HAVE_SALOME
+class PartSet_Fitter : public OCCViewer_Fitter
+#else
+class PartSet_Fitter : public AppElements_Fitter
+#endif
+{
+public:
+  PartSet_Fitter(PartSet_SketcherMgr* theSketchMgr):
+    mySketchMgr(theSketchMgr) {}
+
+  /// A method which has top be reimplemented to provide alterantive implementation FitAll command
+  /// \param theView - a view which has to be fit
+  virtual void fitAll(Handle(V3d_View) theView);
+
+private:
+  PartSet_SketcherMgr* mySketchMgr;
+};
+
+
 
 /**
 * \ingroup Modules
@@ -340,10 +369,14 @@ public:
     return myPointsHighlight.size() > 0;
   }
 
+  PartSet_Module* module() const { return myModule; }
+
 public slots:
   /// Process sketch plane selected event
   void onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln);
 
+  /// The slot is called when user checks "Show free points" button
+  /// \param toShow a state of the check box
   void onShowPoints(bool toShow);
 
 private slots:
@@ -461,6 +494,8 @@ private:
   PartSet_ExternalPointsMgr* myExternalPointsMgr;
 
   QMap<ResultPtr, Handle(AIS_Shape)> myPointsHighlight;
+
+  bool myNoDragMoving;
 };
 
 
index 60134597f37250120035825e71ac8e5ecc405b64..d46c5d30dddae5eb37e7604f55e779e7877358f3 100644 (file)
@@ -31,6 +31,9 @@
 
 #include "GeomDataAPI_Point2D.h"
 
+#include "GeomAPI_Lin2d.h"
+#include "GeomAPI_Dir2d.h"
+
 #include <ModuleBase_IPropertyPanel.h>
 #include <ModuleBase_ISelectionActivate.h>
 #include <ModuleBase_OperationFeature.h>
@@ -51,6 +54,8 @@
 #include <SketchPlugin_Point.h>
 #include <SketchPlugin_Trim.h>
 #include <SketchPlugin_Split.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintVertical.h>
 
 #include <XGUI_Workshop.h>
 #include <XGUI_ModuleConnector.h>
@@ -69,7 +74,8 @@ PartSet_SketcherReentrantMgr::PartSet_SketcherReentrantMgr(ModuleBase_IWorkshop*
   myRestartingMode(RM_None),
   myIsFlagsBlocked(false),
   myIsInternalEditOperation(false),
-  myNoMoreWidgetsAttribute("")
+  myNoMoreWidgetsAttribute(""),
+  myIsAutoConstraints(true)
 {
 }
 
@@ -370,8 +376,11 @@ void PartSet_SketcherReentrantMgr::onNoMoreWidgets(const std::string& thePreviou
           isStarted = startInternalEdit(thePreviousAttributeID);
         }
       }
-      if (!isStarted)
+      if (!isStarted) {
+        if (myIsAutoConstraints)
+          addConstraints(aFOperation->feature());
         aFOperation->commit();
+      }
     }
   }
 }
@@ -495,6 +504,9 @@ bool PartSet_SketcherReentrantMgr::startInternalEdit(const std::string& thePrevi
     // returning to the neutral point of the Sketcher or start internal edit
     workshop()->selector()->clearSelection();
 
+    if (myIsAutoConstraints)
+      addConstraints(aFOperation->feature());
+
     aFOperation->setEditOperation(true/*, false*/);
     createInternalFeature();
 
@@ -823,3 +835,48 @@ void PartSet_SketcherReentrantMgr::setInternalActiveWidget(ModuleBase_ModelWidge
       aPropertyPanel->setInternalActiveWidget(theWidget);
   }
 }
+
+void PartSet_SketcherReentrantMgr::onAutoConstraints(bool isOn)
+{
+  myIsAutoConstraints = isOn;
+}
+
+void PartSet_SketcherReentrantMgr::addConstraints(const FeaturePtr& theFeature)
+{
+  if (theFeature->getKind() != SketchPlugin_Line::ID())
+    return;
+
+  static GeomDir2dPtr myHorDir(new GeomAPI_Dir2d(1, 0));
+  static GeomDir2dPtr myVertDir(new GeomAPI_Dir2d(0, 1));
+
+  std::shared_ptr<ModelAPI_Data> aData = theFeature->data();
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aData->attribute(SketchPlugin_Line::START_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aData->attribute(SketchPlugin_Line::END_ID()));
+  if (aPoint1.get() && aPoint2.get()) {
+    GeomLine2dPtr aLine(new GeomAPI_Lin2d(aPoint1->pnt(), aPoint2->pnt()));
+    GeomDir2dPtr aDir = aLine->direction();
+    double aHorAngle = fabs(myHorDir->angle(aDir));
+    double aVertAngle = fabs(myVertDir->angle(aDir));
+    if (aHorAngle > M_PI/2.)
+      aHorAngle = M_PI - aHorAngle;
+    if (aVertAngle > M_PI/2.)
+      aVertAngle = M_PI - aVertAngle;
+
+    double aTolerance = Config_PropManager::real(SKETCH_TAB_NAME, "angular_tolerance");
+    CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
+    FeaturePtr aFeature;
+    if (aHorAngle < aTolerance)
+      // Add horizontal constraint
+      aFeature = aSketch->addFeature(SketchPlugin_ConstraintHorizontal::ID());
+    else if (aVertAngle < aTolerance)
+      // Add vertical constraint
+      aFeature = aSketch->addFeature(SketchPlugin_ConstraintVertical::ID());
+
+    if (aFeature.get()) {
+      aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(
+          theFeature->firstResult());
+    }
+  }
+}
index fc2f6723cc9440e9edfa4e1b5cc1943b86d9ebbb..046f45dba5911b13358c8d68a9974a3be0899e39 100644 (file)
@@ -131,6 +131,15 @@ public:
   /// \param theMessage a message of reentrant operation
   void setReentrantPreSelection(const std::shared_ptr<Events_Message>& theMessage);
 
+  bool isAutoConstraints() const { return myIsAutoConstraints; }
+
+
+public slots:
+  /// The slot is called when user checks "Automatic constraints" button
+  /// \param isOn a state of the check box
+  void onAutoConstraints(bool isOn);
+
+
 private slots:
   /// SLOT, that is called by a widget activating in the property panel
   /// If the 'internal' edit operation is started, it activates the first widget selection
@@ -188,7 +197,7 @@ private:
   /// \param theSourceFeature a source feature
   /// \param theNewFeature a new feature
   /// \param theSketch an active sketch
-  /// \param isTemporary is used to do not create additional features(e.g. coicidence for line)
+  /// \param isTemporary is used to do not create additional features(e.g. coincidence for line)
   /// \return true is something is copied
   static bool copyReetntrantAttributes(const FeaturePtr& theSourceFeature,
                                       const FeaturePtr& theNewFeature,
@@ -211,6 +220,8 @@ private:
 
   void setInternalActiveWidget(ModuleBase_ModelWidget* theWidget);
 
+  void addConstraints(const FeaturePtr& theFeature);
+
 private:
   ModuleBase_IWorkshop* myWorkshop; /// the workshop
 
@@ -227,6 +238,8 @@ private:
   ObjectPtr mySelectedObject; /// cashed selected object
   std::shared_ptr<ModelAPI_Attribute> mySelectedAttribute; /// cashed selected attribute
   std::shared_ptr<GeomAPI_Pnt2d> myClickedSketchPoint; /// cashed clicked point
+
+  bool myIsAutoConstraints;
 };
 
 #endif
index 4b72de19888a5286ef2696dc4b2e3c3a50581179..f8d05fe0a6c011c731d314ee19bc06739368b871 100644 (file)
@@ -282,26 +282,19 @@ bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection
       return false;
     GeomAPI_Edge aEdge1(aShape);
 
-    if (aEdge1.isLine() || aEdge1.isArc()) {
-      if (aList.size() == 2) {
-        // Check second selection
-        aPrs = aList.last();
-        const GeomShapePtr& aShape2 = aPrs->shape();
-        if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
-          return false;
-        GeomAPI_Edge aEdge2(aShape2);
-
-        if (aEdge1.isLine() && aEdge2.isArc())
-          return true;
-        else if (aEdge1.isArc() && aEdge2.isLine())
-          return true;
-        else
-          return false;
-      } else
-        return true;
+    if (aList.size() == 2) {
+      // Check second selection
+      aPrs = aList.last();
+      const GeomShapePtr& aShape2 = aPrs->shape();
+      if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
+        return false;
+      GeomAPI_Edge aEdge2(aShape2);
+
+      if (aEdge1.isLine() && aEdge2.isLine())
+        return false;
     }
-    return false;
   }
+  return true;
 }
 
 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection,
@@ -335,12 +328,12 @@ bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection,
             aType = 1;
           else if (aType != 1)
             return false;
-        } else if (aEdge.isCircle()) {
+        } else if (aEdge.isCircle() || aEdge.isArc()) {
           if (aCount == 1)
             aType = 2;
           else if (aType != 2)
             return false;
-        } else if (aEdge.isArc()) {
+        } else if (aEdge.isEllipse()) {
           if (aCount == 1)
             aType = 3;
           else if (aType != 3)
index f89385297b0f9133a3b0606a50d451b2c4b8d265..8183806b9d66b41da4ca2e03093a3734821a68f8 100644 (file)
@@ -102,7 +102,7 @@ PartSet_WidgetPoint2D::PartSet_WidgetPoint2D(QWidget* theParent,
 
   // the control should accept the focus, so the boolean flag is corrected to be true
   myIsObligatory = true;
-  QString aPageName = QString::fromStdString(theData->getProperty(CONTAINER_PAGE_NAME));
+  QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
   myGroupBox = new QGroupBox(aPageName, theParent);
   myGroupBox->setFlat(false);
 
@@ -520,7 +520,7 @@ bool PartSet_WidgetPoint2D::setConstraintToPoint(double theClickedX, double theC
     AttributePoint2DPtr aFeaturePoint;
     if (aFeature->isMacro()) {
       // the macro feature will be removed after the operation is stopped, so we need to build
-      // coicidence to possible sub-features
+      // coincidence to possible sub-features
       aFeaturePoint = findFirstEqualPointInArgumentFeatures(aFeature, aClickedPoint);
     }
     else {
@@ -549,7 +549,7 @@ bool PartSet_WidgetPoint2D::setConstraintToObject(const ObjectPtr& theObject)
       AttributePoint2DPtr anAttrPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aThisAttr);
       if (anAttrPoint.get()) {
         // the macro feature will be removed after the operation is stopped, so we need to build
-        // coicidence to possible sub-features
+        // coincidence to possible sub-features
         aFeaturePoint = findFirstEqualPointInArgumentFeatures(feature(),
                                                                    anAttrPoint->pnt());
       }
index a201d5d385578e0ed9a50736a2c775d69a0b2d93..de888dc755b59345e113b6dda7c47620de5435f8 100644 (file)
@@ -82,13 +82,13 @@ PartSet_WidgetSketchCreator::PartSet_WidgetSketchCreator(QWidget* theParent,
 
   ModuleBase_Tools::adjustMargins(aLayout);
 
-  QString aLabelText = QString::fromStdString(theData->widgetLabel());
+  QString aLabelText = translate(theData->widgetLabel());
   QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
 
   // Size of the View control
   mySizeOfViewWidget = new QWidget(this);
   QHBoxLayout* aSizeLayout = new QHBoxLayout(mySizeOfViewWidget);
-  aSizeLayout->addWidget(new QLabel("Size of the view", mySizeOfViewWidget));
+  aSizeLayout->addWidget(new QLabel(tr("Size of the view"), mySizeOfViewWidget));
   mySizeOfView = new QLineEdit(mySizeOfViewWidget);
 
   QDoubleValidator* aValidator = new QDoubleValidator(0, DBL_MAX, 12, mySizeOfView);
index 221207f9d910ebb8b42d124d0f4ef273ca30a160..ae937d3459ce190c9bd4c32ec68813c1edc1a88e 100644 (file)
@@ -21,6 +21,7 @@
 #include "PartSet_Tools.h"
 #include "PartSet_Module.h"
 #include "PartSet_PreviewPlanes.h"
+#include "PartSet_SketcherReentrantMgr.h"
 
 #include "SketchPlugin_SketchEntity.h"
 
@@ -36,6 +37,7 @@
 
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_Tools.h>
+#include <ModelAPI_AttributeString.h>
 
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_ViewerPrs.h>
@@ -101,7 +103,7 @@ myIsSelection(false)
   // Size of the View control
   mySizeOfViewWidget = new QWidget(aFirstWgt);
   QHBoxLayout* aSizeLayout = new QHBoxLayout(mySizeOfViewWidget);
-  aSizeLayout->addWidget(new QLabel("Size of the view", mySizeOfViewWidget));
+  aSizeLayout->addWidget(new QLabel(tr("Size of the view"), mySizeOfViewWidget));
   mySizeOfView = new QLineEdit(mySizeOfViewWidget);
 
   QDoubleValidator* aValidator = new QDoubleValidator(0, DBL_MAX, 12, mySizeOfView);
@@ -110,10 +112,10 @@ myIsSelection(false)
   mySizeOfView->setValidator(aValidator);
   aSizeLayout->addWidget(mySizeOfView);
 
-  QString aText = QString::fromStdString(theData->getProperty("title"));
+  QString aText = translate(theData->getProperty("title"));
   QLabel* aLabel = new QLabel(aText, aFirstWgt);
   aLabel->setWordWrap(true);
-  QString aTooltip = QString::fromStdString(theData->getProperty("tooltip"));
+  QString aTooltip = translate(theData->getProperty("tooltip"));
   aLabel->setToolTip(aTooltip);
   aLabel->setIndent(5);
 
@@ -171,10 +173,18 @@ myIsSelection(false)
   connect(myShowPoints, SIGNAL(toggled(bool)), this, SIGNAL(showFreePoints(bool)));
   aLayout->addWidget(myShowPoints);
 
+  myAutoConstraints = new QCheckBox(tr("Automatic constraints"), this);
+  myAutoConstraints->setToolTip(tr("Automatic vertical and horizontal constraints"));
+  connect(myAutoConstraints, SIGNAL(toggled(bool)), this, SIGNAL(autoConstraints(bool)));
+  aLayout->addWidget(myAutoConstraints);
+
   QPushButton* aPlaneBtn = new QPushButton(tr("Change sketch plane"), aSecondWgt);
   connect(aPlaneBtn, SIGNAL(clicked(bool)), SLOT(onChangePlane()));
   aLayout->addWidget(aPlaneBtn);
 
+  myDoFLabel = new QLabel("", aSecondWgt);
+  aLayout->addWidget(myDoFLabel);
+
   myStackWidget->addWidget(aSecondWgt);
   //setLayout(aLayout);
 
@@ -508,6 +518,13 @@ bool PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(const ModuleBase_View
 
 void PartSet_WidgetSketchLabel::activateCustom()
 {
+  PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+  if (aModule) {
+    bool isBlocked = myAutoConstraints->blockSignals(true);
+    myAutoConstraints->setChecked(aModule->sketchReentranceMgr()->isAutoConstraints());
+    myAutoConstraints->blockSignals(isBlocked);
+  }
+
   std::shared_ptr<GeomAPI_Pln> aPlane = plane();
   if (aPlane.get()) {
     myStackWidget->setCurrentIndex(1);
@@ -718,3 +735,30 @@ void PartSet_WidgetSketchLabel::setShowPointsState(bool theState)
   myShowPoints->setChecked(theState);
   myShowPoints->blockSignals(aBlock);
 }
+
+bool PartSet_WidgetSketchLabel::restoreValueCustom()
+{
+  if (myFeature.get()) {
+    CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
+    if (aSketch.get() && (aSketch->numberOfSubs() > 0)) {
+      AttributeStringPtr aDOFStr = aSketch->string("SolverDOF");
+      if (aDOFStr.get()) {
+        QString aVal(aDOFStr->value().c_str());
+        if (aVal.contains('=')) {
+          // to support old data
+          aVal = aVal.right(aVal.length() - aVal.lastIndexOf('='));
+        }
+        int aDoF = aVal.toInt();
+        if (aDoF == 0) {
+          myDoFLabel->setText(tr("Sketch is fully fixed (DoF = 0)"));
+        } else {
+          myDoFLabel->setText(tr("DoF (degrees of freedom) = ") + aVal);
+        }
+      }
+    }
+    else {
+      myDoFLabel->setText("");
+    }
+  }
+  return true;
+}
index 74a16f2248f33199e47f8d54c402636130499e05..fe9c147160014b099b18171cdc48c911ffdfcd06 100644 (file)
@@ -118,8 +118,14 @@ signals:
   /// \param theState a state of the check box
   void showConstraintToggled(int theType, bool theState);
 
+  /// The signal is emitted when user checks "Show free points" button
+  /// \param toShow a state of the check box
   void showFreePoints(bool toShow);
 
+  /// The signal is emitted when user checks "Automatic constraints" button
+  /// \param isOn a state of the check box
+  void autoConstraints(bool isOn);
+
 protected:
   /// Creates a backup of the current values of the attribute
   /// It should be realized in the specific widget because of different
@@ -146,10 +152,7 @@ protected:
     return true;
   }
 
-  virtual bool restoreValueCustom()
-  {
-    return true;
-  }
+  virtual bool restoreValueCustom();
 
   /// The methiod called when widget is activated
   virtual void activateCustom();
@@ -223,6 +226,7 @@ private:
   QCheckBox* myViewInverted;
   QCheckBox* myRemoveExternal;
   QCheckBox* myShowPoints;
+  QCheckBox* myAutoConstraints;
 
   QMap<PartSet_Tools::ConstraintVisibleState, QCheckBox*> myShowConstraints;
 
@@ -230,6 +234,8 @@ private:
   QLineEdit* mySizeOfView; ///< Value of square of size of View
   QStackedWidget* myStackWidget;
 
+  QLabel* myDoFLabel;
+
   bool myOpenTransaction;
   bool myIsSelection;
 };
diff --git a/src/PartSet/PartSet_msg_fr.ts b/src/PartSet/PartSet_msg_fr.ts
new file mode 100644 (file)
index 0000000..3d69726
--- /dev/null
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+    <name>PartSet_MenuMgr</name>
+    <message>
+        <location filename="PartSet_MenuMgr.cpp" line="91"/>
+        <location filename="PartSet_MenuMgr.cpp" line="529"/>
+        <source>Auxiliary</source>
+        <translation>Auxiliaire</translation>
+    </message>
+    <message>
+        <location filename="PartSet_MenuMgr.cpp" line="95"/>
+        <location filename="PartSet_MenuMgr.cpp" line="100"/>
+        <source>Activate</source>
+        <translation>Activer</translation>
+    </message>
+    <message>
+        <location filename="PartSet_MenuMgr.cpp" line="104"/>
+        <source>Edit...</source>
+        <translation>Modifier...</translation>
+    </message>
+    <message>
+        <location filename="PartSet_MenuMgr.cpp" line="185"/>
+        <location filename="PartSet_MenuMgr.cpp" line="324"/>
+        <location filename="PartSet_MenuMgr.cpp" line="528"/>
+        <source>Detach</source>
+        <translation>Détacher</translation>
+    </message>
+    <message>
+        <location filename="PartSet_MenuMgr.cpp" line="317"/>
+        <source>Detach %1</source>
+        <translation>Détachez %1</translation>
+    </message>
+</context>
+<context>
+    <name>PartSet_WidgetPoint2D</name>
+    <message>
+        <location filename="PartSet_WidgetPoint2d.cpp" line="118"/>
+        <source>X</source>
+        <translation>X</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetPoint2d.cpp" line="134"/>
+        <source>Y</source>
+        <translation>Y</translation>
+    </message>
+</context>
+<context>
+    <name>PartSet_WidgetSketchCreator</name>
+    <message>
+        <location filename="PartSet_WidgetSketchCreator.cpp" line="91"/>
+        <source>Size of the view</source>
+        <translation>Taille de la vue</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchCreator.cpp" line="546"/>
+        <source>Apply current feature</source>
+        <translation>Appliquer la fonctionnalité actuelle</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchCreator.cpp" line="547"/>
+        <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>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="106"/>
+        <source>Size of the view</source>
+        <translation>Taille de la vue</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="127"/>
+        <source>Remove external dependencies</source>
+        <translation>Supprimer les dépendances externes</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="141"/>
+        <source>Sketcher plane</source>
+        <translation>Plan du Sketcher</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="144"/>
+        <source>Reversed</source>
+        <translation>Renversé</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="148"/>
+        <source>Set plane view</source>
+        <translation>Définir la vue plane</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="155"/>
+        <source>Show geometrical constraints</source>
+        <translation>Afficher les contraintes géométriques</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="156"/>
+        <source>Show dimensional constraints</source>
+        <translation>Afficher les contraintes dimensionnelles</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="157"/>
+        <source>Show existing expressions</source>
+        <translation>Afficher les expressions existantes</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="172"/>
+        <source>Show free points</source>
+        <translation>Afficher les points libres</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="176"/>
+        <source>Automatic constraints</source>
+        <translation>Contraintes automatiques</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="177"/>
+        <source>Automatic vertical and horizontal constraints</source>
+        <translation>Automatique des contraintes verticales et horizontales</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="181"/>
+        <source>Change sketch plane</source>
+        <translation>Changer le plan d&apos;esquisse</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="753"/>
+        <source>Sketch is fully fixed (DoF = 0)</source>
+        <translation>L&apos;esquisse est entièrement fixée (DdL = 0)</translation>
+    </message>
+    <message>
+        <location filename="PartSet_WidgetSketchLabel.cpp" line="755"/>
+        <source>DoF (degrees of freedom) = </source>
+        <translation>DdL (degrés de liberté) = </translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <location filename="PartSet_TreeNodes.cpp" line="402"/>
+        <source>Parameters</source>
+        <translation>Paramètres</translation>
+    </message>
+    <message>
+        <location filename="PartSet_TreeNodes.cpp" line="404"/>
+        <source>Constructions</source>
+        <translation>Constructions</translation>
+    </message>
+    <message>
+        <location filename="PartSet_TreeNodes.cpp" line="406"/>
+        <source>Parts</source>
+        <translation>Pièces</translation>
+    </message>
+    <message>
+        <location filename="PartSet_TreeNodes.cpp" line="408"/>
+        <source>Results</source>
+        <translation>Résultats</translation>
+    </message>
+    <message>
+        <location filename="PartSet_TreeNodes.cpp" line="410"/>
+        <source>Fields</source>
+        <translation>Champs</translation>
+    </message>
+    <message>
+        <location filename="PartSet_TreeNodes.cpp" line="412"/>
+        <source>Groups</source>
+        <translation>Groupes</translation>
+    </message>
+</context>
+</TS>
index a9d98e14fbf8445189565f9970dedd812366ea7b..9b3079ba32f5f97bceafc82e75bae368bf07ae22 100644 (file)
@@ -38,8 +38,14 @@ SET(XML_RESOURCES
   plugin-PartSet.xml
 )
 
+SET(TEXT_RESOURCES
+    PartSetPlugin_msg_fr.ts
+)
+
+SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
+
 ADD_DEFINITIONS(-DPARTSETPLUGIN_EXPORTS)
-ADD_LIBRARY(PartSetPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES})
+ADD_LIBRARY(PartSetPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES})
 TARGET_LINK_LIBRARIES(PartSetPlugin ${PROJECT_LIBRARIES} ModelAPI)
 
 INCLUDE_DIRECTORIES(
@@ -49,5 +55,5 @@ INCLUDE_DIRECTORIES(
 )
 
 INSTALL(TARGETS PartSetPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES})
-INSTALL(FILES ${XML_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
+INSTALL(FILES ${XML_RESOURCES} ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/PartSet)
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 0e04ab120b1244c9d5ae6fc0b86fd19786e4c6ac..abc07fbac28a56c08e93093c374c84372768d538 100644 (file)
@@ -45,6 +45,12 @@ SET(XML_RESOURCES
   torus_widget.xml
 )
 
+SET(TEXT_RESOURCES
+    PrimitivesPlugin_msg_fr.ts
+)
+
+SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
+
 INCLUDE_DIRECTORIES(
   ../ModelAPI
   ../GeomAPI
@@ -60,11 +66,11 @@ SET(PROJECT_LIBRARIES
 )
 
 ADD_DEFINITIONS(-DPRIMITIVESPLUGIN_EXPORTS)
-ADD_LIBRARY(PrimitivesPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES})
+ADD_LIBRARY(PrimitivesPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES})
 TARGET_LINK_LIBRARIES(PrimitivesPlugin ${PROJECT_LIBRARIES})
 
 INSTALL(TARGETS PrimitivesPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES})
-INSTALL(FILES ${XML_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
+INSTALL(FILES ${XML_RESOURCES} ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Primitives)
 
 
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 7bb8f5362520a4aa868c69d6f8c0fe4f5a2be667..0d4890dda0c060edef3b6a17572f13a960f8c50c 100644 (file)
@@ -18,6 +18,7 @@
 #
 
 import ModelHighAPI
+from GeomAPI import *
 from GeomDataAPI import *
 from ModelAPI import *
 import math
@@ -111,6 +112,8 @@ def toList(thePoint):
         return thePoint
     elif issubclass(type(thePoint), GeomDataAPI_Point2D):
         return [thePoint.x(), thePoint.y()]
+    elif issubclass(type(thePoint), GeomAPI_Pnt2d):
+        return [thePoint.x(), thePoint.y()]
     else:
         aFeature = toSketchFeature(thePoint)
         aPoint = geomDataAPI_Point2D(aFeature.attribute("PointCoordinates"))
index 76831f99f0e2a12461cc1bab4e5049a7288e9812..e15c9080c9f5b028e2887b0d013c841fed6efe5b 100644 (file)
@@ -25,6 +25,8 @@ INCLUDE_DIRECTORIES(${QT_INCLUDES})
 # additional preprocessor / compiler flags
 ADD_DEFINITIONS(${QT_DEFINITIONS})
 
+SET(UPDATE_TRANSLATION OFF)
+
 SET(PROJECT_HEADERS
     SHAPER_SHAPERGUI.h
     SHAPERGUI.h
@@ -32,7 +34,7 @@ SET(PROJECT_HEADERS
     SHAPERGUI_OCCSelector.h
     SHAPERGUI_SalomeViewer.h
     SHAPERGUI_NestedButton.h
-       SHAPERGUI_ToolbarsMgr.h
+    SHAPERGUI_ToolbarsMgr.h
 )
 
 SET(PROJECT_MOC_HEADERS
@@ -40,7 +42,7 @@ SET(PROJECT_MOC_HEADERS
     SHAPERGUI_DataModel.h
     SHAPERGUI_NestedButton.h
     SHAPERGUI_SalomeViewer.h
-       SHAPERGUI_ToolbarsMgr.h
+    SHAPERGUI_ToolbarsMgr.h
 )
 
 # sources / moc wrappings
@@ -52,7 +54,7 @@ SET(PROJECT_SOURCES
     SHAPERGUI_OCCSelector.cpp
     SHAPERGUI_SalomeViewer.cpp
     SHAPERGUI_NestedButton.cpp
-       SHAPERGUI_ToolbarsMgr.cpp
+    SHAPERGUI_ToolbarsMgr.cpp
 )
 
 SET(PROJECT_RESOURCES
@@ -61,6 +63,24 @@ SET(PROJECT_RESOURCES
     resources/shaper.png
 )
 
+SET(TEXT_RESOURCES
+    SHAPERGUI_msg_fr.ts
+)
+
+IF (${UPDATE_TRANSLATION})
+    SET(PROJECT_FILES ${PROJECT_SOURCES} ${PROJECT_HEADERS} )
+    QT5_CREATE_TRANSLATION(QM_RESOURCES
+                           ${PROJECT_FILES}
+                           ${TEXT_RESOURCES}
+                           OPTIONS -extensions cpp -no-recursive
+                          )
+ELSE(${UPDATE_TRANSLATION})
+    IF(${MAKE_TRANSLATION})
+        QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
+    ENDIF(${MAKE_TRANSLATION})
+ENDIF(${UPDATE_TRANSLATION})
+
+
 SET(PROJECT_LIBRARIES
     Events
     Config
@@ -98,6 +118,7 @@ ADD_LIBRARY(SHAPER SHARED
     ${PROJECT_SOURCES}
     ${PROJECT_HEADERS}
     ${PROJECT_AUTOMOC}
+    ${QM_RESOURCES}
 )
 
 ADD_DEPENDENCIES(SHAPER XGUI)
@@ -113,3 +134,4 @@ CONFIGURE_FILE(
 
 INSTALL(TARGETS SHAPER DESTINATION ${SHAPER_INSTALL_BIN})
 INSTALL(FILES ${PROJECT_RESOURCES} DESTINATION ${SHAPER_INSTALL_RESOURCES})
+INSTALL(FILES ${QM_RESOURCES} DESTINATION ${SHAPER_INSTALL_QM_RESOURCES})
index 785c67f2a6220c2018bdf86a3e33f05754755484..1f0d054f491c861650d04b4d833b68c8a6739529 100644 (file)
@@ -576,6 +576,18 @@ void SHAPERGUI_SalomeViewer::setColorScaleTitle(const QString& theText)
   }
 }
 
+void SHAPERGUI_SalomeViewer::setFitter(OCCViewer_Fitter* theFitter)
+{
+  if (mySelector)
+    mySelector->viewer()->setFitter(theFitter);
+}
+
+OCCViewer_Fitter* SHAPERGUI_SalomeViewer::fitter() const
+{
+  if (mySelector)
+    return mySelector->viewer()->fitter();
+  return 0;
+}
 
 
 //void SHAPERGUI_SalomeViewer::Zfitall()
index 588eafff0c1c958cbb39f28760f5f77601bf08a7..97df56cdc392016221cfcc1c3599cab622aab4d5 100644 (file)
@@ -208,6 +208,9 @@ Q_OBJECT
   // \param theText is a title
   virtual void setColorScaleTitle(const QString& theText);
 
+  virtual void setFitter(OCCViewer_Fitter* theFitter);
+  virtual OCCViewer_Fitter* fitter() const;
+
   // Fit all along Z (perpendicular to display)
   //virtual void Zfitall();
 
diff --git a/src/SHAPERGUI/SHAPERGUI_msg_fr.ts b/src/SHAPERGUI/SHAPERGUI_msg_fr.ts
new file mode 100644 (file)
index 0000000..87743d0
--- /dev/null
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+  <context>
+    <name>SHAPERGUI</name>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="170"/>
+      <source>Inspection</source>
+      <translation>Inspection</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="171"/>
+      <source>Information</source>
+      <translation>Information</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="176"/>
+      <source>Show inspection window</source>
+      <translation>Afficher la fenêtre d&apos;inspection</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="177"/>
+      <source>What Is</source>
+      <translation>Qu’est-ce que c’est</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="183"/>
+      <source>Inspection tool</source>
+      <translation>Outil d&apos;inspection</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="191"/>
+      <source>Edit toolbars of the module</source>
+      <translation>Editer les barres d&apos;outils du module</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="193"/>
+      <source>Edit toolbars...</source>
+      <translation>Editer les barres d&apos;outils...</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="775"/>
+      <source>Viewer</source>
+      <translation>Vue</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="777"/>
+      <source>Default selection</source>
+      <translation>Sélection par défaut</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="779"/>
+      <source>Faces</source>
+      <translation>Faces</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="782"/>
+      <source>Edges</source>
+      <translation>Arêtes</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="785"/>
+      <source>Vertices</source>
+      <translation>Sommets</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="789"/>
+      <source>Selection sensitivity</source>
+      <translation>Sensibilité de sélection</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="791"/>
+      <source>Vertex</source>
+      <translation>Sommet</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="793"/>
+      <source>Edge</source>
+      <translation>Bord</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="796"/>
+      <source>Additional highlighting</source>
+      <translation>Mise en évidence supplémentaire</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="798"/>
+      <source>In 3d mode</source>
+      <translation>En mode 3D</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="800"/>
+      <source>In 2d mode</source>
+      <translation>En mode 2D</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="803"/>
+      <source>Color scale</source>
+      <translation>Échelle de couleur</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="805"/>
+      <source>X position</source>
+      <translation>Position X</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="810"/>
+      <source>Y position</source>
+      <translation>Position Y</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="815"/>
+      <source>Width</source>
+      <translation>Largeur</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="820"/>
+      <source>Height</source>
+      <translation>Hauteur</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="825"/>
+      <source>Intervals number</source>
+      <translation>Nombre d&apos;intervalles</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="830"/>
+      <source>Text height</source>
+      <translation>Hauteur du texte</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI.cpp" line="835"/>
+      <source>Text color</source>
+      <translation>Couleur du texte</translation>
+    </message>
+  </context>
+  <context>
+    <name>SHAPERGUI_ToolbarItemsDlg</name>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="268"/>
+      <source>Edit toolbar</source>
+      <translation>Editer la barre d&apos;outils</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="278"/>
+      <source>Toolbar name:</source>
+      <translation>Nom de la barre d&apos;outils:</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="298"/>
+      <source>Out of toolbars:</source>
+      <translation>Hors des barres d&apos;outils:</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="333"/>
+      <source>In the toolbar:</source>
+      <translation>Dans la barre d&apos;outils:</translation>
+    </message>
+  </context>
+  <context>
+    <name>SHAPERGUI_ToolbarsDlg</name>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="88"/>
+      <source>Toolbars</source>
+      <translation>Barres d&apos;outils</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="103"/>
+      <source>Toolbars:</source>
+      <translation>Barres d&apos;outils:</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="115"/>
+      <source>Number of commands out of toolbars:</source>
+      <translation>Nombre de commandes hors des barres d&apos;outils:</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="125"/>
+      <source>Add...</source>
+      <translation>Ajouter...</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="126"/>
+      <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>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="130"/>
+      <source>Edit...</source>
+      <translation>Modifier...</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="131"/>
+      <source>Edit currently selected toolbar</source>
+      <translation>Modifier la barre d&apos;outils actuellement sélectionnée</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="135"/>
+      <source>Delete</source>
+      <translation>Effacer</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="136"/>
+      <source>Delete currently selected toolbar</source>
+      <translation>Supprimer la barre d&apos;outils actuellement sélectionnée</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="141"/>
+      <source>Reset</source>
+      <translation>Réinitialiser</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="142"/>
+      <source>Restore default toolbars structure</source>
+      <translation>Restaurer la structure des barres d&apos;outils par défaut</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="163"/>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="172"/>
+      <source>Create toolbar</source>
+      <translation>Créer une barre d&apos;outils</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="163"/>
+      <source>Name of a new toolbar</source>
+      <translation>Nom d&apos;une nouvelle barre d&apos;outils</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="171"/>
+      <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>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="205"/>
+      <source>Toolbar %1 will be deleted. Continue?</source>
+      <translation>La barre d&apos;outils %1 sera supprimée. Continuez ?</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="206"/>
+      <source>Delete toolbar</source>
+      <translation>Supprimer la barre d&apos;outils</translation>
+    </message>
+    <message>
+      <location filename="SHAPERGUI_ToolbarsMgr.cpp" line="224"/>
+      <source> (%1 commands)</source>
+      <translation>AA</translation>
+    </message>
+  </context>
+</TS>
index f7672ab2db462dda540c811a3301a8dd322597bd..081f2b03e59026d7cfe4ebc1db8e03f8a1090993 100644 (file)
   <section name="resources">
     <!-- Module resources -->
     <parameter name="SHAPER" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
+    <parameter name="SHAPERGUI" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
+    <parameter name="ModuleBase" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
+    <parameter name="PartSet" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
+    <parameter name="XGUI" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
   </section>
   <section name="Viewer" >
     <!-- Viewer preferences -->
index b93b91f9e4590e8cdc4059f51874d8677c6b16f5..9d2b423d8a244dc27cab1286d334d11b2ec35c43 100644 (file)
@@ -25,17 +25,21 @@ SET(PROJECT_HEADERS
   SketchAPI_Circle.h
   SketchAPI_Constraint.h
   SketchAPI_ConstraintAngle.h
+  SketchAPI_Ellipse.h
+  SketchAPI_EllipticArc.h
   SketchAPI_IntersectionPoint.h
   SketchAPI_Line.h
   SketchAPI_MacroArc.h
   SketchAPI_MacroCircle.h
+  SketchAPI_MacroEllipse.h
+  SketchAPI_MacroEllipticArc.h
   SketchAPI_Mirror.h
-  SketchAPI_Sketch.h
-  SketchAPI_SketchEntity.h
   SketchAPI_Point.h
   SketchAPI_Projection.h
   SketchAPI_Rectangle.h
   SketchAPI_Rotation.h
+  SketchAPI_Sketch.h
+  SketchAPI_SketchEntity.h
   SketchAPI_Translation.h
 )
 
@@ -44,17 +48,21 @@ SET(PROJECT_SOURCES
   SketchAPI_Circle.cpp
   SketchAPI_Constraint.cpp
   SketchAPI_ConstraintAngle.cpp
+  SketchAPI_Ellipse.cpp
+  SketchAPI_EllipticArc.cpp
   SketchAPI_IntersectionPoint.cpp
   SketchAPI_Line.cpp
   SketchAPI_MacroArc.cpp
   SketchAPI_MacroCircle.cpp
+  SketchAPI_MacroEllipse.cpp
+  SketchAPI_MacroEllipticArc.cpp
   SketchAPI_Mirror.cpp
-  SketchAPI_Sketch.cpp
-  SketchAPI_SketchEntity.cpp
   SketchAPI_Point.cpp
   SketchAPI_Projection.cpp
   SketchAPI_Rectangle.cpp
   SketchAPI_Rotation.cpp
+  SketchAPI_Sketch.cpp
+  SketchAPI_SketchEntity.cpp
   SketchAPI_Translation.cpp
 )
 
index 36732e2c2f1abb6472a6ae428108dbdb8b6fbb0d..08f87c104fe754f46b9de4453fa37d5094c9f3a3 100644 (file)
 // standard definitions
 %include "typemaps.i"
 %include "std_list.i"
+%include "std_pair.i"
 %include "std_shared_ptr.i"
 
+// function with named parameters
+%feature("kwargs") SketchAPI_Ellipse::construction;
+%feature("kwargs") SketchAPI_EllipticArc::construction;
+
 // shared pointers
 %shared_ptr(SketchAPI_Arc)
 %shared_ptr(SketchAPI_MacroArc)
 %shared_ptr(SketchAPI_Circle)
 %shared_ptr(SketchAPI_MacroCircle)
+%shared_ptr(SketchAPI_Ellipse)
+%shared_ptr(SketchAPI_MacroEllipse)
+%shared_ptr(SketchAPI_EllipticArc)
+%shared_ptr(SketchAPI_MacroEllipticArc)
 %shared_ptr(SketchAPI_Constraint)
 %shared_ptr(SketchAPI_ConstraintAngle)
 %shared_ptr(SketchAPI_IntersectionPoint)
@@ -65,6 +74,8 @@
 %template(InterfaceList) std::list<std::shared_ptr<ModelHighAPI_Interface> >;
 %template(EntityList)    std::list<std::shared_ptr<SketchAPI_SketchEntity> >;
 %template(SketchPointList) std::list<std::shared_ptr<SketchAPI_Point> >;
+// std::pair -> []
+%template(PointRefAttrPair) std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>;
 
 %typecheck(SWIG_TYPECHECK_POINTER) std::shared_ptr<ModelAPI_Feature>, const std::shared_ptr<ModelAPI_Feature> & {
   std::shared_ptr<ModelAPI_Feature> * temp_feature;
   }
 }
 
-%typemap(in) const ModelHighAPI_RefAttr & (ModelHighAPI_RefAttr temp) {
-  std::shared_ptr<ModelAPI_Attribute> * temp_attribute;
-  std::shared_ptr<ModelAPI_Object> * temp_object;
-  std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
-  ModelHighAPI_Selection* temp_selection;
-  int newmem = 0;
-  if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
-    if (!temp_selection) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
-      return NULL;
-    }
-    temp = ModelHighAPI_RefAttr(std::shared_ptr<ModelAPI_Object>(temp_selection->resultSubShapePair().first));
-    if (newmem & SWIG_CAST_NEW_MEMORY) {
-      delete temp_selection;
-    }
-    $1 = &temp;
-  } else
-  if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
-    if (!temp_attribute) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
-      return NULL;
-    }
-    temp = ModelHighAPI_RefAttr(*temp_attribute);
-    if (newmem & SWIG_CAST_NEW_MEMORY) {
-      delete temp_attribute;
-    }
-    $1 = &temp;
-  } else
-  if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
-    if (!temp_object) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
-      return NULL;
-    }
-    temp = ModelHighAPI_RefAttr(*temp_object);
-    if (newmem & SWIG_CAST_NEW_MEMORY) {
-      delete temp_object;
-    }
-    $1 = &temp;
-  } else
-  if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
-    if (!temp_interface) {
-      PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
-      return NULL;
-    }
-    temp = ModelHighAPI_RefAttr(*temp_interface);
-    if (newmem & SWIG_CAST_NEW_MEMORY) {
-      delete temp_interface;
-    }
-    $1 = &temp;
-  } else
-  if ((SWIG_ConvertPtr($input, (void **)&$1, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) {
-  } else {
-    PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
-    return NULL;
-  }
-}
-
 %typemap(in) const std::list<std::shared_ptr<ModelAPI_Object> > & (std::list<std::shared_ptr<ModelAPI_Object> > temp) {
   std::shared_ptr<ModelAPI_Object> * temp_object;
   std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
   }
 }
 
+%typecheck(SWIG_TYPECHECK_POINTER) std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>, const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & {
+  std::shared_ptr<ModelAPI_Attribute> * temp_attribute;
+  std::shared_ptr<ModelAPI_Object> * temp_object;
+  std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
+  ModelHighAPI_Selection* temp_selection;
+  std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>* temp_pair;
+  std::shared_ptr<GeomAPI_Pnt2d> * temp_point;
+  ModelHighAPI_RefAttr temp_refattr;
+  int newmem = 0;
+  std::list<PyObject*> temp_inputlist;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+      PyObject * temp = PySequence_GetItem($input, i);
+      temp_inputlist.push_back(temp);
+    }
+  } else {
+    temp_inputlist.push_back($input);
+  }
+
+  $1 = 1;
+  for (std::list<PyObject*>::iterator it = temp_inputlist.begin(); it != temp_inputlist.end() && $1; ++it) {
+    PyObject* item = *it;
+
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_selection) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_attribute) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_object) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_interface) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_pair) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr<GeomAPI_Pnt2d> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_point) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+      }
+    } else {
+      $1 = 0;
+    }
+  }
+}
+
+%typemap(in) const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & (std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> temp) {
+  std::shared_ptr<ModelAPI_Attribute> * temp_attribute;
+  std::shared_ptr<ModelAPI_Object> * temp_object;
+  std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
+  ModelHighAPI_Selection* temp_selection;
+  std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>* temp_pair;
+  std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+  ModelHighAPI_RefAttr temp_refattr;
+  int newmem = 0;
+  std::list<PyObject*> temp_inputlist;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+      PyObject * temp = PySequence_GetItem($input, i);
+      temp_inputlist.push_back(temp);
+    }
+  } else {
+    temp_inputlist.push_back($input);
+  }
+
+  for (std::list<PyObject*>::iterator it = temp_inputlist.begin(); it != temp_inputlist.end(); ++it) {
+    PyObject* item = *it;
+
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_selection) {
+        temp_refattr = ModelHighAPI_RefAttr(std::shared_ptr<ModelAPI_Object>(temp_selection->resultSubShapePair().first));
+        if (newmem & SWIG_CAST_NEW_MEMORY) {
+          delete temp_selection;
+        }
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_attribute) {
+        temp_refattr = ModelHighAPI_RefAttr(*temp_attribute);
+        if (newmem & SWIG_CAST_NEW_MEMORY) {
+          delete temp_attribute;
+        }
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_object) {
+        temp_refattr = ModelHighAPI_RefAttr(*temp_object);
+        if (newmem & SWIG_CAST_NEW_MEMORY) {
+          delete temp_object;
+        }
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_interface) {
+        temp_refattr = ModelHighAPI_RefAttr(*temp_interface);
+        if (newmem & SWIG_CAST_NEW_MEMORY) {
+          delete temp_interface;
+        }
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      if (temp_pair) {
+        temp_point = &temp_pair->first;
+        temp_refattr = temp_pair->second;
+        if (newmem & SWIG_CAST_NEW_MEMORY) {
+          delete temp_pair;
+        }
+      }
+    } else
+    if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr<GeomAPI_Pnt2d> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+      // fall through
+    }
+  }
+
+  if (temp_point || !temp_refattr.isEmpty()) {
+    if (temp_point) {
+      temp = std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>(*temp_point, temp_refattr);
+    } else {
+      temp = std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>(std::shared_ptr<GeomAPI_Pnt2d>(), temp_refattr);
+    }
+    if (temp_point && (newmem & SWIG_CAST_NEW_MEMORY)) {
+      delete temp_point;
+    }
+    $1 = &temp;
+  } else {
+    PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
+    return NULL;
+  }
+}
+
+// fix compilarion error: 'res*' was not declared in this scope
+%typemap(freearg) const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & {}
+
 // all supported interfaces (the order is very important according dependencies: base class first)
 %include "SketchAPI_SketchEntity.h"
 %include "SketchAPI_Point.h"
 %include "SketchAPI_MacroCircle.h"
 %include "SketchAPI_Arc.h"
 %include "SketchAPI_MacroArc.h"
+%include "SketchAPI_Ellipse.h"
+%include "SketchAPI_MacroEllipse.h"
+%include "SketchAPI_EllipticArc.h"
+%include "SketchAPI_MacroEllipticArc.h"
 %include "SketchAPI_Projection.h"
 %include "SketchAPI_Mirror.h"
 %include "SketchAPI_Translation.h"
diff --git a/src/SketchAPI/SketchAPI_Ellipse.cpp b/src/SketchAPI/SketchAPI_Ellipse.cpp
new file mode 100644 (file)
index 0000000..19de091
--- /dev/null
@@ -0,0 +1,452 @@
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SketchAPI_Ellipse.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+static const std::string AUXILIARY_VALUE = "aux";
+static const std::string MAJOR_AXIS_ID = "majorAxis";
+static const std::string MINOR_AXIS_ID = "minorAxis";
+
+SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature> & theFeature)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  initialize();
+}
+
+SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     double theCenterX, double theCenterY,
+                                     double theFocusX, double theFocusY,
+                                     double theMinorRadius)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if(initialize()) {
+    setByCenterFocusAndRadius(theCenterX, theCenterY, theFocusX, theFocusY, theMinorRadius);
+  }
+}
+
+SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                                     double theMinorRadius)
+: SketchAPI_SketchEntity(theFeature)
+{
+  if(initialize()) {
+    setByCenterFocusAndRadius(theCenter, theFocus, theMinorRadius);
+  }
+}
+
+SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const ModelHighAPI_Selection& theExternal)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByExternal(theExternal);
+  }
+}
+
+SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::string& theExternalName)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByExternalName(theExternalName);
+  }
+}
+
+SketchAPI_Ellipse::~SketchAPI_Ellipse()
+{
+}
+
+void SketchAPI_Ellipse::setByCenterFocusAndRadius(double theCenterX, double theCenterY,
+                                                  double theFocusX, double theFocusY,
+                                                  double theMinorRadius)
+{
+  fillAttribute(center(), theCenterX, theCenterY);
+  fillAttribute(firstFocus(), theFocusX, theFocusY);
+  fillAttribute(theMinorRadius, myminorRadius);
+
+  execute();
+}
+
+void SketchAPI_Ellipse::setByCenterFocusAndRadius(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                                  const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                                                  double theMinorRadius)
+{
+  fillAttribute(theCenter, mycenter);
+  fillAttribute(theFocus, myfirstFocus);
+  fillAttribute(theMinorRadius, myminorRadius);
+
+  execute();
+}
+
+void SketchAPI_Ellipse::setByExternal(const ModelHighAPI_Selection & theExternal)
+{
+  fillAttribute(theExternal, external());
+  execute();
+}
+
+void SketchAPI_Ellipse::setByExternalName(const std::string & theExternalName)
+{
+  fillAttribute(ModelHighAPI_Selection("EDGE", theExternalName), external());
+  execute();
+}
+
+void SketchAPI_Ellipse::setCenter(double theX, double theY)
+{
+  fillAttribute(center(), theX, theY);
+  execute();
+}
+
+void SketchAPI_Ellipse::setCenter(const std::shared_ptr<GeomAPI_Pnt2d> & theCenter)
+{
+  fillAttribute(theCenter, mycenter);
+  execute();
+}
+
+void SketchAPI_Ellipse::setFocus(double theX, double theY)
+{
+  fillAttribute(firstFocus(), theX, theY);
+  execute();
+}
+
+void SketchAPI_Ellipse::setFocus(const std::shared_ptr<GeomAPI_Pnt2d> & theFocus)
+{
+  fillAttribute(theFocus, myfirstFocus);
+  execute();
+}
+
+void SketchAPI_Ellipse::setMinorRadius(double theMinorRadius)
+{
+  fillAttribute(theMinorRadius, myminorRadius);
+  execute();
+}
+
+static const std::list<PairOfStrings>& ellipseAttrAndDumpNames()
+{
+  static std::list<PairOfStrings> anAttributes;
+  if (anAttributes.empty()) {
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::CENTER_ID(), "center"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::FIRST_FOCUS_ID(), "firstFocus"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::SECOND_FOCUS_ID(), "secondFocus"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(), "majorAxisStart"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID(), "majorAxisEnd"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::MINOR_AXIS_START_ID(), "minorAxisStart"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_Ellipse::MINOR_AXIS_END_ID(), "minorAxisEnd"));
+  }
+  return anAttributes;
+}
+
+static CompositeFeaturePtr sketchForFeature(FeaturePtr theFeature)
+{
+  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
+    if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID())
+      return std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
+  return CompositeFeaturePtr();
+}
+
+static void createInternalConstraint(const CompositeFeaturePtr& theSketch,
+                                     const AttributePoint2DPtr& thePoint1,
+                                     const AttributePoint2DPtr& thePoint2)
+{
+  FeaturePtr aConstraint = theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID());
+  aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint1);
+  aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(thePoint2);
+  aConstraint->execute();
+}
+
+static void createPoint(const CompositeFeaturePtr& theSketch,
+                        const FeaturePtr& theEllipse,
+                        const std::string& theCoincident,
+                        const std::string& theAuxOrName,
+                        std::list<FeaturePtr>& theEntities)
+{
+  if (theAuxOrName.empty())
+    return;
+
+  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theEllipse->attribute(theCoincident));
+
+  FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID());
+  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+  aCoord->setValue(anElPoint->x(), anElPoint->y());
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipse);
+  aPointFeature->execute();
+
+  std::string aName = theEllipse->name() + "_" + theCoincident;
+  aPointFeature->data()->setName(aName);
+  aPointFeature->lastResult()->data()->setName(aName);
+
+  if (theAuxOrName == AUXILIARY_VALUE)
+    aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  else if (!theAuxOrName.empty()) {
+    aPointFeature->data()->setName(theAuxOrName);
+    aPointFeature->lastResult()->data()->setName(theAuxOrName);
+  }
+
+  createInternalConstraint(theSketch, anElPoint, aCoord);
+
+  theEntities.push_back(aPointFeature);
+}
+
+static void createAxis(const CompositeFeaturePtr& theSketch,
+                       const FeaturePtr& theEllipse,
+                       const std::string& theCoincidentStart,
+                       const std::string& theCoincidentEnd,
+                       const std::string& theAuxOrName,
+                       std::list<FeaturePtr>& theEntities)
+{
+  if (theAuxOrName.empty())
+    return;
+
+  AttributePoint2DPtr aStartPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipse->attribute(theCoincidentStart));
+  AttributePoint2DPtr aEndPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipse->attribute(theCoincidentEnd));
+
+  FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID());
+  AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+  aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
+  AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+  aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipse);
+  aLineFeature->execute();
+
+  std::string aName = theEllipse->name() + "_" +
+      (theCoincidentStart == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ?
+       "major_axis" : "minor_axis");
+  aLineFeature->data()->setName(aName);
+  aLineFeature->lastResult()->data()->setName(aName);
+
+  if (theAuxOrName == AUXILIARY_VALUE)
+    aLineFeature->boolean(SketchPlugin_Line::AUXILIARY_ID())->setValue(true);
+  else if (!theAuxOrName.empty()) {
+    aLineFeature->data()->setName(theAuxOrName);
+    aLineFeature->lastResult()->data()->setName(theAuxOrName);
+  }
+
+  createInternalConstraint(theSketch, aStartPoint, aLineStart);
+  createInternalConstraint(theSketch, aEndPoint, aLineEnd);
+
+  theEntities.push_back(aLineFeature);
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Ellipse::construction(
+    const std::string& center,
+    const std::string& firstFocus,
+    const std::string& secondFocus,
+    const std::string& majorAxisStart,
+    const std::string& majorAxisEnd,
+    const std::string& minorAxisStart,
+    const std::string& minorAxisEnd,
+    const std::string& majorAxis,
+    const std::string& minorAxis) const
+{
+  FeaturePtr anEllipse = feature();
+
+  std::list<PairOfStrings> anAttributes = ellipseAttrAndDumpNames();
+  // append start and end attributes for axes
+  anAttributes.push_back(PairOfStrings(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
+                                       SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()));
+  anAttributes.push_back(PairOfStrings(SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
+                                       SketchPlugin_Ellipse::MINOR_AXIS_END_ID()));
+
+  return buildConstructionEntities(anEllipse, anAttributes, center, firstFocus, secondFocus,
+            majorAxisStart, majorAxisEnd, minorAxisStart, minorAxisEnd, majorAxis, minorAxis);
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Ellipse::buildConstructionEntities(
+      const FeaturePtr& theEllipse,
+      const std::list<PairOfStrings>& theAttributes,
+      const std::string& theCenter,
+      const std::string& theFirstFocus,
+      const std::string& theSecondFocus,
+      const std::string& theMajorAxisStart,
+      const std::string& theMajorAxisEnd,
+      const std::string& theMinorAxisStart,
+      const std::string& theMinorAxisEnd,
+      const std::string& theMajorAxis,
+      const std::string& theMinorAxis)
+{
+  CompositeFeaturePtr aSketch = sketchForFeature(theEllipse);
+
+  std::list<FeaturePtr> anEntities;
+  std::list<PairOfStrings>::const_iterator anAttrIt = theAttributes.begin();
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theCenter, anEntities);
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theFirstFocus, anEntities);
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theSecondFocus, anEntities);
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMajorAxisStart, anEntities);
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMajorAxisEnd, anEntities);
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMinorAxisStart, anEntities);
+  createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMinorAxisEnd, anEntities);
+
+  createAxis(aSketch, theEllipse, anAttrIt->first, anAttrIt->second, theMajorAxis, anEntities);
+  ++anAttrIt;
+  createAxis(aSketch, theEllipse, anAttrIt->first, anAttrIt->second, theMinorAxis, anEntities);
+
+  return SketchAPI_SketchEntity::wrap(anEntities);
+}
+
+static void ellipseAttributeAndAuxiliaryFeature(
+    const FeaturePtr& theInternalConstraint,
+    const std::pair<std::string, std::string>& theMajorAxisStartEnd,
+    const std::pair<std::string, std::string>& theMinorAxisStartEnd,
+    std::map<std::string, FeaturePtr>& theAttrToFeature)
+{
+  AttributeRefAttrPtr aRefAttrA =
+      theInternalConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+  AttributeRefAttrPtr aRefAttrB =
+      theInternalConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+  // the first point is usually an ellipse attribute
+  // and the second point is an attribute of the auxiliary feature
+  ObjectPtr anAuxObject;
+  if (aRefAttrB->isObject())
+    anAuxObject = aRefAttrB->object();
+  else
+    anAuxObject = aRefAttrB->attr()->owner();
+
+  FeaturePtr anAuxFeature = ModelAPI_Feature::feature(anAuxObject);
+  if (anAuxFeature->getKind() == SketchPlugin_Point::ID())
+    theAttrToFeature[aRefAttrA->attr()->id()] = anAuxFeature;
+  else {
+    const std::string& anAttrID = aRefAttrA->attr()->id();
+    if (anAttrID == theMajorAxisStartEnd.first || anAttrID == theMajorAxisStartEnd.second)
+      theAttrToFeature[MAJOR_AXIS_ID] = anAuxFeature;
+    else if (anAttrID == theMinorAxisStartEnd.first || anAttrID == theMinorAxisStartEnd.second)
+      theAttrToFeature[MINOR_AXIS_ID] = anAuxFeature;
+  }
+}
+
+void SketchAPI_Ellipse::collectAuxiliaryFeatures(
+    FeaturePtr theEllipse,
+    const std::pair<std::string, std::string>& theMajorAxis,
+    const std::pair<std::string, std::string>& theMinorAxis,
+    std::map<std::string, FeaturePtr>& theAttrToFeature)
+{
+  const std::set<AttributePtr>& aRefs = theEllipse->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+       aRefIt != aRefs.end(); ++aRefIt) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+    if (anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+      // process internal constraints only
+      ellipseAttributeAndAuxiliaryFeature(anOwner, theMajorAxis, theMinorAxis, theAttrToFeature);
+    }
+  }
+}
+
+void SketchAPI_Ellipse::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  if (isCopy())
+    return; // no need to dump copied feature
+
+  FeaturePtr aBase = feature();
+  const std::string& aSketchName = theDumper.parentName(aBase);
+
+  AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
+  if (anExternal->context()) {
+    // circle is external
+    theDumper << aBase << " = " << aSketchName << ".addEllipse(" << anExternal << ")" << std::endl;
+  } else {
+    // ellipse given by center, focus and radius
+    theDumper << aBase << " = " << aSketchName << ".addEllipse("
+              << center() << ", " << firstFocus() << ", " << minorRadius() << ")" << std::endl;
+  }
+  // dump "auxiliary" flag if necessary
+  SketchAPI_SketchEntity::dump(theDumper);
+
+  // dump auxiliary features produced by ellipse
+  std::map<std::string, FeaturePtr> anAuxFeatures;
+  static const std::pair<std::string, std::string> aMajorAxis(
+      SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
+      SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
+  static const std::pair<std::string, std::string> aMinorAxis(
+      SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
+      SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
+  collectAuxiliaryFeatures(aBase, aMajorAxis, aMinorAxis, anAuxFeatures);
+
+  if (!anAuxFeatures.empty()) {
+    // a list of attributes to write features in special order
+    const std::list<PairOfStrings>& anAttributes = ellipseAttrAndDumpNames();
+    dumpConstructionEntities(theDumper, aBase, anAttributes, anAuxFeatures);
+  }
+}
+
+void SketchAPI_Ellipse::dumpConstructionEntities(
+    ModelHighAPI_Dumper& theDumper,
+    const FeaturePtr& theEllipse,
+    const std::list<PairOfStrings>& theAttributes,
+    const std::map<std::string, FeaturePtr>& theAuxFeatures)
+{
+  std::list<PairOfStrings> anAttributes = theAttributes;
+  // append axes
+  anAttributes.push_back(PairOfStrings(MAJOR_AXIS_ID, MAJOR_AXIS_ID));
+  anAttributes.push_back(PairOfStrings(MINOR_AXIS_ID, MINOR_AXIS_ID));
+
+  theDumper << "[";
+  bool isFirst = true;
+  for (std::list<PairOfStrings>::iterator anIt = anAttributes.begin();
+        anIt != anAttributes.end(); ++anIt) {
+    std::map<std::string, FeaturePtr>::const_iterator aFound = theAuxFeatures.find(anIt->first);
+    if (aFound == theAuxFeatures.end())
+      continue;
+    if (!isFirst)
+      theDumper << ", ";
+    theDumper << theDumper.name(aFound->second, false);
+    theDumper.doNotDumpFeature(aFound->second);
+    isFirst = false;
+  }
+  theDumper << "] = " << theDumper.name(theEllipse) << ".construction(";
+  isFirst = true;
+  for (std::list<PairOfStrings>::iterator anIt = anAttributes.begin();
+        anIt != anAttributes.end(); ++anIt) {
+    std::map<std::string, FeaturePtr>::const_iterator aFound = theAuxFeatures.find(anIt->first);
+    if (aFound == theAuxFeatures.end())
+      continue;
+    if (!isFirst)
+      theDumper << ", ";
+    isFirst = false;
+    theDumper << anIt->second << " = \"";
+    if (aFound->second->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value())
+      theDumper << AUXILIARY_VALUE;
+    else
+      theDumper << aFound->second->name();
+    theDumper << "\"";
+  }
+  theDumper << ")" << std::endl;
+}
diff --git a/src/SketchAPI/SketchAPI_Ellipse.h b/src/SketchAPI/SketchAPI_Ellipse.h
new file mode 100644 (file)
index 0000000..598d413
--- /dev/null
@@ -0,0 +1,194 @@
+// 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 SketchAPI_Ellipse_H_
+#define SketchAPI_Ellipse_H_
+
+#include "SketchAPI.h"
+#include "SketchAPI_SketchEntity.h"
+
+#include <SketchPlugin_Ellipse.h>
+
+class ModelHighAPI_Selection;
+
+typedef std::pair<std::string, std::string> PairOfStrings;
+
+/// \class SketchAPI_Ellipse
+/// \ingroup CPPHighAPI
+/// \brief Interface for Ellipse feature.
+class SketchAPI_Ellipse : public SketchAPI_SketchEntity
+{
+public:
+  /// Constructor without values.
+  SKETCHAPI_EXPORT
+  explicit SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT
+  SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                    double theCenterX, double theCenterY,
+                    double theFocusX, double theFocusY,
+                    double theMinorRadius);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT
+  SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                    const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                    const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                    double theMinorRadius);
+
+  /// Constructor with external.
+  SKETCHAPI_EXPORT
+  SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                    const ModelHighAPI_Selection& theExternal);
+
+  /// Constructor with external.
+  SKETCHAPI_EXPORT
+  SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                    const std::string& theExternalName);
+
+  /// Destructor.
+  SKETCHAPI_EXPORT
+  virtual ~SketchAPI_Ellipse();
+
+  INTERFACE_10(SketchPlugin_Ellipse::ID(),
+               center, SketchPlugin_Ellipse::CENTER_ID(),
+               GeomDataAPI_Point2D, /** Center point */,
+               firstFocus, SketchPlugin_Ellipse::FIRST_FOCUS_ID(),
+               GeomDataAPI_Point2D, /** Focus in positive direction of a major axis */,
+               secondFocus, SketchPlugin_Ellipse::SECOND_FOCUS_ID(),
+               GeomDataAPI_Point2D, /** Focus in negative direction of a major axis */,
+               majorAxisNegative, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
+               GeomDataAPI_Point2D, /** Start point of major axis */,
+               majorAxisPositive, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID(),
+               GeomDataAPI_Point2D, /** End point of major axis */,
+               minorAxisNegative, SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
+               GeomDataAPI_Point2D, /** Start point of minor axis */,
+               minorAxisPositive, SketchPlugin_Ellipse::MINOR_AXIS_END_ID(),
+               GeomDataAPI_Point2D, /** End point of minor axis */,
+               majorRadius, SketchPlugin_Ellipse::MAJOR_RADIUS_ID(),
+               ModelAPI_AttributeDouble, /** Major radius */,
+               minorRadius, SketchPlugin_Ellipse::MINOR_RADIUS_ID(),
+               ModelAPI_AttributeDouble, /** Minor radius */,
+               external, SketchPlugin_Ellipse::EXTERNAL_ID(),
+               ModelAPI_AttributeSelection, /** External */)
+
+  /// Set by center, focus and radius.
+  SKETCHAPI_EXPORT
+  void setByCenterFocusAndRadius(double theCenterX, double theCenterY,
+                                 double theFocusX, double theFocusY,
+                                 double theMinorRadius);
+
+  /// Set by center, focus and radius.
+  SKETCHAPI_EXPORT
+  void setByCenterFocusAndRadius(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                 const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                                 double theMinorRadius);
+
+  /// Set by external.
+  SKETCHAPI_EXPORT
+  void setByExternal(const ModelHighAPI_Selection& theExternal);
+
+  /// Set by external name.
+  SKETCHAPI_EXPORT
+  void setByExternalName(const std::string& theExternalName);
+
+  /// Set center.
+  SKETCHAPI_EXPORT
+  void setCenter(double theX, double theY);
+
+  /// Set center.
+  SKETCHAPI_EXPORT
+  void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter);
+
+  /// Set focus.
+  SKETCHAPI_EXPORT
+  void setFocus(double theX, double theY);
+
+  /// Set focus.
+  SKETCHAPI_EXPORT
+  void setFocus(const std::shared_ptr<GeomAPI_Pnt2d>& theFocus);
+
+  /// Set radius.
+  SKETCHAPI_EXPORT
+  void setMinorRadius(double theRadius);
+
+  /// Create construction elements (focuses, axes etc.).
+  /// Empty value for each parameter shows that the corresponding feature has been removed.
+  /// Value "aux" marks this feature as auxiliary.
+  /// And the name of the feature shows that it is a regular feature.
+  SKETCHAPI_EXPORT
+  std::list<std::shared_ptr<SketchAPI_SketchEntity> > construction(
+      const std::string& center = std::string(),
+      const std::string& firstFocus = std::string(),
+      const std::string& secondFocus = std::string(),
+      const std::string& majorAxisStart = std::string(),
+      const std::string& majorAxisEnd = std::string(),
+      const std::string& minorAxisStart = std::string(),
+      const std::string& minorAxisEnd = std::string(),
+      const std::string& majorAxis = std::string(),
+      const std::string& minorAxis = std::string()) const;
+
+  /// Dump wrapped feature
+  SKETCHAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+private:
+  /// Find all features connected with theEllipse by the internal coincidence.
+  /// \param[in]  theEllipse        ellipse or elliptic arc
+  /// \param[in]  theMajorAxis      names of attributes composing a major axis of ellipse
+  /// \param[in]  theMinorAxis      names of attributes composing a minor axis of ellipse
+  /// \param[out] theAttrToFeature  map attribute of ellipse and coincident auxiliary feature
+  static void collectAuxiliaryFeatures(FeaturePtr theEllipse,
+                                       const PairOfStrings& theMajorAxis,
+                                       const PairOfStrings& theMinorAxis,
+                                       std::map<std::string, FeaturePtr>& theAttrToFeature);
+
+  /// \brief Dump the construction features (points, axes) for the ellipse.
+  /// \param[in] theDumper      dumper instance
+  /// \param[in] theAttributes  list of attributes the construction points are
+  ///                           connected with, and their dump names
+  /// \param[in] theAuxFeatures list of construction features
+  static void dumpConstructionEntities(ModelHighAPI_Dumper& theDumper,
+                                       const FeaturePtr& theEllipse,
+                                       const std::list<PairOfStrings>& theAttributes,
+                                       const std::map<std::string, FeaturePtr>& theAuxFeatures);
+
+  /// \brief Create construction features for the ellipse connected
+  ///        with corresponding attribute of ellipse.
+  static std::list<std::shared_ptr<SketchAPI_SketchEntity> > buildConstructionEntities(
+      const FeaturePtr& theEllipse,
+      const std::list<PairOfStrings>& theAttributes,
+      const std::string& theCenter,
+      const std::string& theFirstFocus,
+      const std::string& theSecondFocus,
+      const std::string& theMajorAxisStart,
+      const std::string& theMajorAxisEnd,
+      const std::string& theMinorAxisStart,
+      const std::string& theMinorAxisEnd,
+      const std::string& theMajorAxis,
+      const std::string& theMinorAxis);
+
+  friend class SketchAPI_EllipticArc;
+};
+
+/// Pointer on Ellipse object.
+typedef std::shared_ptr<SketchAPI_Ellipse> EllipsePtr;
+
+#endif // SketchPlugin_Ellipse_H_
diff --git a/src/SketchAPI/SketchAPI_EllipticArc.cpp b/src/SketchAPI/SketchAPI_EllipticArc.cpp
new file mode 100644 (file)
index 0000000..a3e39a2
--- /dev/null
@@ -0,0 +1,245 @@
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SketchAPI_EllipticArc.h"
+#include "SketchAPI_Ellipse.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+
+SketchAPI_EllipticArc::SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature> & theFeature)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  initialize();
+}
+
+SketchAPI_EllipticArc::SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                             double theCenterX, double theCenterY,
+                                             double theFocusX, double theFocusY,
+                                             double theStartX, double theStartY,
+                                             double theEndX, double theEndY,
+                                             bool theInversed)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if(initialize()) {
+    setByCenterFocusAndPoints(theCenterX, theCenterY, theFocusX, theFocusY,
+                              theStartX, theStartY, theEndX, theEndY, theInversed);
+  }
+}
+
+SketchAPI_EllipticArc::SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                             const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                             const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                                             const std::shared_ptr<GeomAPI_Pnt2d>& theStart,
+                                             const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                                             bool theInversed)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if(initialize()) {
+    setByCenterFocusAndPoints(theCenter, theFocus, theStart, theEnd, theInversed);
+  }
+}
+
+SketchAPI_EllipticArc::SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const ModelHighAPI_Selection& theExternal)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByExternal(theExternal);
+  }
+}
+
+SketchAPI_EllipticArc::SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::string& theExternalName)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByExternalName(theExternalName);
+  }
+}
+
+SketchAPI_EllipticArc::~SketchAPI_EllipticArc()
+{
+}
+
+void SketchAPI_EllipticArc::setByCenterFocusAndPoints(double theCenterX, double theCenterY,
+                                                      double theFocusX, double theFocusY,
+                                                      double theStartX, double theStartY,
+                                                      double theEndX, double theEndY,
+                                                      bool theInversed)
+{
+  // the order of attribute initialization is reversed to avoid odd recalculation of an elliptic arc
+  fillAttribute(theInversed, reversed());
+  fillAttribute(endPoint(), theEndX, theEndY);
+  fillAttribute(startPoint(), theStartX, theStartY);
+  fillAttribute(firstFocus(), theFocusX, theFocusY);
+  fillAttribute(center(), theCenterX, theCenterY);
+
+  execute();
+}
+
+void SketchAPI_EllipticArc::setByCenterFocusAndPoints(
+    const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theStart,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+    bool theInversed)
+{
+  // the order of attribute initialization is reversed to avoid odd recalculation of an elliptic arc
+  fillAttribute(theInversed, reversed());
+  fillAttribute(theEnd, endPoint());
+  fillAttribute(theStart, startPoint());
+  fillAttribute(theFocus, firstFocus());
+  fillAttribute(theCenter, center());
+
+  execute();
+}
+
+void SketchAPI_EllipticArc::setByExternal(const ModelHighAPI_Selection & theExternal)
+{
+  fillAttribute(theExternal, external());
+  execute();
+}
+
+void SketchAPI_EllipticArc::setByExternalName(const std::string & theExternalName)
+{
+  fillAttribute(ModelHighAPI_Selection("EDGE", theExternalName), external());
+  execute();
+}
+
+void SketchAPI_EllipticArc::setCenter(double theX, double theY)
+{
+  fillAttribute(center(), theX, theY);
+  execute();
+}
+
+void SketchAPI_EllipticArc::setCenter(const std::shared_ptr<GeomAPI_Pnt2d> & theCenter)
+{
+  fillAttribute(theCenter, mycenter);
+  execute();
+}
+
+void SketchAPI_EllipticArc::setFocus(double theX, double theY)
+{
+  fillAttribute(firstFocus(), theX, theY);
+  execute();
+}
+
+void SketchAPI_EllipticArc::setFocus(const std::shared_ptr<GeomAPI_Pnt2d> & theFocus)
+{
+  fillAttribute(theFocus, myfirstFocus);
+  execute();
+}
+
+static const std::list<PairOfStrings>& ellipticArcAttrAndDumpNames()
+{
+  static std::list<PairOfStrings> anAttributes;
+  if (anAttributes.empty()) {
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::CENTER_ID(), "center"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::FIRST_FOCUS_ID(), "firstFocus"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::SECOND_FOCUS_ID(), "secondFocus"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(), "majorAxisStart"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID(), "majorAxisEnd"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(), "minorAxisStart"));
+    anAttributes.push_back(
+        PairOfStrings(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID(), "minorAxisEnd"));
+  }
+  return anAttributes;
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_EllipticArc::construction(
+    const std::string& center,
+    const std::string& firstFocus,
+    const std::string& secondFocus,
+    const std::string& majorAxisStart,
+    const std::string& majorAxisEnd,
+    const std::string& minorAxisStart,
+    const std::string& minorAxisEnd,
+    const std::string& majorAxis,
+    const std::string& minorAxis) const
+{
+  FeaturePtr anEllipse = feature();
+
+  std::list<PairOfStrings> anAttributes = ellipticArcAttrAndDumpNames();
+  // append start and end attributes for axes
+  anAttributes.push_back(PairOfStrings(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(),
+                                       SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID()));
+  anAttributes.push_back(PairOfStrings(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(),
+                                       SketchPlugin_EllipticArc::MINOR_AXIS_END_ID()));
+
+  return SketchAPI_Ellipse::buildConstructionEntities(anEllipse, anAttributes,
+                                                      center, firstFocus, secondFocus,
+                                                      majorAxisStart, majorAxisEnd,
+                                                      minorAxisStart, minorAxisEnd,
+                                                      majorAxis, minorAxis);
+}
+
+void SketchAPI_EllipticArc::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  if (isCopy())
+    return; // no need to dump copied feature
+
+  FeaturePtr aBase = feature();
+  const std::string& aSketchName = theDumper.parentName(aBase);
+
+  AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
+  if (anExternal->context()) {
+    // circle is external
+    theDumper << aBase << " = " << aSketchName << ".addEllipticArc("
+              << anExternal << ")" << std::endl;
+  } else {
+    // ellipse given by center, focus and radius
+    theDumper << aBase << " = " << aSketchName << ".addEllipticArc("
+              << center() << ", " << firstFocus() << ", "
+              << startPoint() << ", " << endPoint() << ", "
+              << reversed() << ")" << std::endl;
+  }
+  // dump "auxiliary" flag if necessary
+  SketchAPI_SketchEntity::dump(theDumper);
+
+  // dump auxiliary features produced by elliptic arc
+  std::map<std::string, FeaturePtr> anAuxFeatures;
+  static const std::pair<std::string, std::string> aMajorAxis(
+      SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(),
+      SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID());
+  static const std::pair<std::string, std::string> aMinorAxis(
+      SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(),
+      SketchPlugin_EllipticArc::MINOR_AXIS_END_ID());
+  SketchAPI_Ellipse::collectAuxiliaryFeatures(aBase, aMajorAxis, aMinorAxis, anAuxFeatures);
+
+  if (!anAuxFeatures.empty()) {
+    // a list of attributes to write features in special order
+    static std::list<PairOfStrings> anAttributes = ellipticArcAttrAndDumpNames();
+    SketchAPI_Ellipse::dumpConstructionEntities(theDumper, aBase, anAttributes, anAuxFeatures);
+  }
+}
diff --git a/src/SketchAPI/SketchAPI_EllipticArc.h b/src/SketchAPI/SketchAPI_EllipticArc.h
new file mode 100644 (file)
index 0000000..dea0544
--- /dev/null
@@ -0,0 +1,164 @@
+// 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 SketchAPI_EllipticArc_H_
+#define SketchAPI_EllipticArc_H_
+
+#include "SketchAPI.h"
+#include "SketchAPI_SketchEntity.h"
+
+#include <SketchPlugin_EllipticArc.h>
+
+class ModelHighAPI_Selection;
+
+/// \class SketchAPI_EllipticArc
+/// \ingroup CPPHighAPI
+/// \brief Interface for Elliptic Arc feature.
+class SketchAPI_EllipticArc : public SketchAPI_SketchEntity
+{
+public:
+  /// Constructor without values.
+  SKETCHAPI_EXPORT
+  explicit SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT
+  SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                        double theCenterX, double theCenterY,
+                        double theFocusX, double theFocusY,
+                        double theStartX, double theStartY,
+                        double theEndX, double theEndY,
+                        bool theInversed);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT
+  SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theStart,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                        bool theInversed);
+
+  /// Constructor with external.
+  SKETCHAPI_EXPORT
+  SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                        const ModelHighAPI_Selection& theExternal);
+
+  /// Constructor with external.
+  SKETCHAPI_EXPORT
+  SketchAPI_EllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                        const std::string& theExternalName);
+
+  /// Destructor.
+  SKETCHAPI_EXPORT
+  virtual ~SketchAPI_EllipticArc();
+
+  INTERFACE_13(SketchPlugin_EllipticArc::ID(),
+               center, SketchPlugin_EllipticArc::CENTER_ID(),
+               GeomDataAPI_Point2D, /** Center point */,
+               startPoint, SketchPlugin_EllipticArc::START_POINT_ID(),
+               GeomDataAPI_Point2D, /** Start point of elliptic arc */,
+               endPoint, SketchPlugin_EllipticArc::END_POINT_ID(),
+               GeomDataAPI_Point2D, /** End point of elliptic arc */,
+               reversed, SketchPlugin_EllipticArc::REVERSED_ID(),
+               ModelAPI_AttributeBoolean, /** Inversed flag */,
+               firstFocus, SketchPlugin_EllipticArc::FIRST_FOCUS_ID(),
+               GeomDataAPI_Point2D, /** Focus in positive direction of a major axis */,
+               secondFocus, SketchPlugin_EllipticArc::SECOND_FOCUS_ID(),
+               GeomDataAPI_Point2D, /** Focus in negative direction of a major axis */,
+               majorAxisNegative, SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(),
+               GeomDataAPI_Point2D, /** Start point of major axis */,
+               majorAxisPositive, SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID(),
+               GeomDataAPI_Point2D, /** End point of major axis */,
+               minorAxisNegative, SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(),
+               GeomDataAPI_Point2D, /** Start point of minor axis */,
+               minorAxisPositive, SketchPlugin_EllipticArc::MINOR_AXIS_END_ID(),
+               GeomDataAPI_Point2D, /** End point of minor axis */,
+               majorRadius, SketchPlugin_EllipticArc::MAJOR_RADIUS_ID(),
+               ModelAPI_AttributeDouble, /** Major radius */,
+               minorRadius, SketchPlugin_EllipticArc::MINOR_RADIUS_ID(),
+               ModelAPI_AttributeDouble, /** Minor radius */,
+               external, SketchPlugin_EllipticArc::EXTERNAL_ID(),
+               ModelAPI_AttributeSelection, /** External */)
+
+  /// Set by center, focus and radius.
+  SKETCHAPI_EXPORT
+  void setByCenterFocusAndPoints(double theCenterX, double theCenterY,
+                                 double theFocusX, double theFocusY,
+                                 double theStartX, double theStartY,
+                                 double theEndX, double theEndY,
+                                 bool theInversed);
+
+  /// Set by center, focus and radius.
+  SKETCHAPI_EXPORT
+  void setByCenterFocusAndPoints(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                 const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+                                 const std::shared_ptr<GeomAPI_Pnt2d>& theStart,
+                                 const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                                 bool theInversed);
+
+  /// Set by external.
+  SKETCHAPI_EXPORT
+  void setByExternal(const ModelHighAPI_Selection& theExternal);
+
+  /// Set by external name.
+  SKETCHAPI_EXPORT
+  void setByExternalName(const std::string& theExternalName);
+
+  /// Set center.
+  SKETCHAPI_EXPORT
+  void setCenter(double theX, double theY);
+
+  /// Set center.
+  SKETCHAPI_EXPORT
+  void setCenter(const std::shared_ptr<GeomAPI_Pnt2d> & theCenter);
+
+  /// Set focus.
+  SKETCHAPI_EXPORT
+  void setFocus(double theX, double theY);
+
+  /// Set focus.
+  SKETCHAPI_EXPORT
+  void setFocus(const std::shared_ptr<GeomAPI_Pnt2d> & theFocus);
+
+  /// Create construction elements (focuses, axes etc.).
+  /// Empty value for each parameter shows that the corresponding feature has been removed.
+  /// Value "aux" marks this feature as auxiliary.
+  /// And the name of the feature shows that it is a regular feature.
+  SKETCHAPI_EXPORT
+  std::list<std::shared_ptr<SketchAPI_SketchEntity> > construction(
+      const std::string& center = std::string(),
+      const std::string& firstFocus = std::string(),
+      const std::string& secondFocus = std::string(),
+      const std::string& majorAxisStart = std::string(),
+      const std::string& majorAxisEnd = std::string(),
+      const std::string& minorAxisStart = std::string(),
+      const std::string& minorAxisEnd = std::string(),
+      const std::string& majorAxis = std::string(),
+      const std::string& minorAxis = std::string()) const;
+
+  /// Dump wrapped feature
+  SKETCHAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on Ellipse object.
+typedef std::shared_ptr<SketchAPI_EllipticArc> EllipticArcPtr;
+
+#endif // SketchAPI_EllipticArc_H_
index 4bad39fefc6e56952ef3bb263bccb97807fc41a7..67dc5f0c768bcb6063d9cb07566d4cfa7aa4542e 100644 (file)
@@ -201,3 +201,29 @@ void SketchAPI_MacroArc::setByTangent(const ModelHighAPI_RefAttr& theTangentPoin
 
   execute();
 }
+
+//================================================================================================
+void SketchAPI_MacroArc::setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                                          double theEndX, double theEndY,
+                                          bool theInversed)
+{
+  fillAttribute(SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE(), myarcType);
+  fillAttribute(theTransversalPoint, mytangentPoint);
+  fillAttribute(endPoint3(), theEndX, theEndY);
+  fillAttribute(theInversed, myreversed);
+
+  execute();
+}
+
+//================================================================================================
+void SketchAPI_MacroArc::setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                                          const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                                          bool theInversed)
+{
+  fillAttribute(SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE(), myarcType);
+  fillAttribute(theTransversalPoint, mytangentPoint);
+  fillAttribute(theEnd, myendPoint3);
+  fillAttribute(theInversed, myreversed);
+
+  execute();
+}
index a4b51ccec3371c608df32034166edab32e63b50c..3a6ae556604c73c01c28ae6110ae009519603f15 100644 (file)
@@ -114,8 +114,6 @@ public:
                angle, SketchPlugin_MacroArc::ANGLE_ID(),
                ModelAPI_AttributeDouble, /** Angle */)
 
-private:
-
   /// Set by center and start, end point.
   SKETCHAPI_EXPORT
   void setByCenterStartEnd(double theCenterX, double theCenterY,
@@ -153,6 +151,18 @@ private:
   void setByTangent(const ModelHighAPI_RefAttr& theTangentPoint,
                     const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
                     bool theInversed);
+
+  /// Set by tangent and end point.
+  SKETCHAPI_EXPORT
+  void setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                        double theEndX, double theEndY,
+                        bool theInversed);
+
+  /// Set by tangent and end point.
+  SKETCHAPI_EXPORT
+  void setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                        bool theInversed);
 };
 
 /// Pointer on Arc object.
diff --git a/src/SketchAPI/SketchAPI_MacroEllipse.cpp b/src/SketchAPI/SketchAPI_MacroEllipse.cpp
new file mode 100644 (file)
index 0000000..9700e1e
--- /dev/null
@@ -0,0 +1,274 @@
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SketchAPI_MacroEllipse.h"
+#include "SketchAPI_Line.h"
+#include "SketchAPI_Point.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelHighAPI_RefAttr.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_Sketch.h>
+
+#define POINT_ATTR(x) (std::dynamic_pointer_cast<GeomDataAPI_Point2D>(feature()->attribute((x))))
+#define POINT_REF(x)  (feature()->refattr((x)))
+
+
+SketchAPI_MacroEllipse::SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                               bool callInitialize)
+: SketchAPI_SketchEntity(theFeature)
+{
+  if (callInitialize && initialize())
+    storeSketch(theFeature);
+}
+
+SketchAPI_MacroEllipse::SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                               double theX1, double theY1,
+                                               double theX2, double theY2,
+                                               double theX3, double theY3,
+                                               bool byCenter)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    static const ModelHighAPI_RefAttr DUMMY_REF;
+
+    GeomPnt2dPtr aPnt1(new GeomAPI_Pnt2d(theX1, theY1));
+    GeomPnt2dPtr aPnt2(new GeomAPI_Pnt2d(theX2, theY2));
+    GeomPnt2dPtr aPnt3(new GeomAPI_Pnt2d(theX3, theY3));
+
+    if (byCenter)
+      setByCenterAndPassedPoints(aPnt1, DUMMY_REF, aPnt2, DUMMY_REF, aPnt3, DUMMY_REF);
+    else
+      setByMajorAxisAndPassedPoint(aPnt1, DUMMY_REF, aPnt2, DUMMY_REF, aPnt3, DUMMY_REF);
+  }
+}
+
+SketchAPI_MacroEllipse::SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
+                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
+                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3,
+                                               bool byCenter)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    static const ModelHighAPI_RefAttr DUMMY_REF;
+    if (byCenter)
+      setByCenterAndPassedPoints(thePoint1, DUMMY_REF, thePoint2, DUMMY_REF, thePoint3, DUMMY_REF);
+    else {
+      setByMajorAxisAndPassedPoint(thePoint1, DUMMY_REF,
+                                   thePoint2, DUMMY_REF,
+                                   thePoint3, DUMMY_REF);
+    }
+  }
+}
+
+SketchAPI_MacroEllipse::SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
+                                               const ModelHighAPI_RefAttr&           thePoint1Ref,
+                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
+                                               const ModelHighAPI_RefAttr&           thePoint2Ref,
+                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3,
+                                               const ModelHighAPI_RefAttr&           thePoint3Ref,
+                                               bool byCenter)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    if (byCenter) {
+      setByCenterAndPassedPoints(thePoint1, thePoint1Ref,
+                                 thePoint2, thePoint2Ref,
+                                 thePoint3, thePoint3Ref);
+    }
+    else {
+      setByMajorAxisAndPassedPoint(thePoint1, thePoint1Ref,
+                                   thePoint2, thePoint2Ref,
+                                   thePoint3, thePoint3Ref);
+    }
+  }
+}
+
+SketchAPI_MacroEllipse::~SketchAPI_MacroEllipse()
+{
+}
+
+static void fillAttribute(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
+                          const ModelHighAPI_RefAttr& thePointRef,
+                          std::shared_ptr<GeomDataAPI_Point2D> thePointAttr,
+                          AttributeRefAttrPtr thePointRefAttr)
+{
+  GeomPnt2dPtr aPoint = thePoint;
+  if (!thePointRef.isEmpty()) {
+    fillAttribute(thePointRef, thePointRefAttr);
+    std::shared_ptr<GeomDataAPI_Point2D> anAttrPnt =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePointRefAttr->attr());
+    if (anAttrPnt)
+      aPoint = anAttrPnt->pnt();
+  }
+  fillAttribute(aPoint, thePointAttr);
+}
+
+void SketchAPI_MacroEllipse::setByCenterAndPassedPoints(
+    const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+    const ModelHighAPI_RefAttr&           theCenterRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theMajorAxisPoint,
+    const ModelHighAPI_RefAttr&           theMajorAxisPointRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>& thePassedPoint,
+    const ModelHighAPI_RefAttr&           thePassedPointRef)
+{
+  fillAttribute(SketchPlugin_MacroEllipse::ELLIPSE_TYPE_BY_CENTER_AXIS_POINT(), myellipseType);
+
+  AttributePoint2DPtr aCenterAttr = POINT_ATTR(SketchPlugin_MacroEllipse::CENTER_POINT_ID());
+  AttributePoint2DPtr aMajorAxisAttr = POINT_ATTR(SketchPlugin_MacroEllipse::MAJOR_AXIS_POINT_ID());
+  AttributePoint2DPtr aPassedAttr = POINT_ATTR(SketchPlugin_MacroEllipse::PASSED_POINT_ID());
+
+  AttributeRefAttrPtr aCenterRef = POINT_REF(SketchPlugin_MacroEllipse::CENTER_POINT_REF_ID());
+  AttributeRefAttrPtr aMajorAxisRef =
+      POINT_REF(SketchPlugin_MacroEllipse::MAJOR_AXIS_POINT_REF_ID());
+  AttributeRefAttrPtr aPassedRef = POINT_REF(SketchPlugin_MacroEllipse::PASSED_POINT_REF_ID());
+
+  fillAttribute(theCenter, theCenterRef, aCenterAttr, aCenterRef);
+  fillAttribute(theMajorAxisPoint, theMajorAxisPointRef, aMajorAxisAttr, aMajorAxisRef);
+  fillAttribute(thePassedPoint, thePassedPointRef, aPassedAttr, aPassedRef);
+
+  storeSketch(feature());
+  execute();
+}
+
+void SketchAPI_MacroEllipse::setByMajorAxisAndPassedPoint(
+    const std::shared_ptr<GeomAPI_Pnt2d>& theMajorAxisStart,
+    const ModelHighAPI_RefAttr&           theMajorAxisStartRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theMajorAxisEnd,
+    const ModelHighAPI_RefAttr&           theMajorAxisEndRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>& thePassedPoint,
+    const ModelHighAPI_RefAttr&           thePassedPointRef)
+{
+  fillAttribute(SketchPlugin_MacroEllipse::ELLIPSE_TYPE_BY_AXIS_AND_POINT(), myellipseType);
+
+  AttributePoint2DPtr aMajorAxisStartAttr =
+      POINT_ATTR(SketchPlugin_MacroEllipse::MAJOR_AXIS_START_ID());
+  AttributePoint2DPtr aMajorAxisEndAttr =
+      POINT_ATTR(SketchPlugin_MacroEllipse::MAJOR_AXIS_END_ID());
+  AttributePoint2DPtr aPassedAttr = POINT_ATTR(SketchPlugin_MacroEllipse::PASSED_POINT_1_ID());
+
+  AttributeRefAttrPtr aMajorAxisStartRef =
+      POINT_REF(SketchPlugin_MacroEllipse::MAJOR_AXIS_START_REF_ID());
+  AttributeRefAttrPtr aMajorAxisEndRef =
+      POINT_REF(SketchPlugin_MacroEllipse::MAJOR_AXIS_END_REF_ID());
+  AttributeRefAttrPtr aPassedRef = POINT_REF(SketchPlugin_MacroEllipse::PASSED_POINT_1_REF_ID());
+
+  fillAttribute(theMajorAxisStart, theMajorAxisStartRef, aMajorAxisStartAttr, aMajorAxisStartRef);
+  fillAttribute(theMajorAxisEnd, theMajorAxisEndRef, aMajorAxisEndAttr, aMajorAxisEndRef);
+  fillAttribute(thePassedPoint, thePassedPointRef, aPassedAttr, aPassedRef);
+
+  storeSketch(feature());
+  execute();
+}
+
+void SketchAPI_MacroEllipse::storeSketch(const FeaturePtr& theFeature)
+{
+  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
+    if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID()) {
+      mySketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
+      break;
+    }
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::center()
+{
+  if (!myCenter)
+    collectAuxiliary();
+  return myCenter;
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::focus1()
+{
+  if (!myFocus1)
+    collectAuxiliary();
+  return myFocus1;
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::focus2()
+{
+  if (!myFocus2)
+    collectAuxiliary();
+  return myFocus2;
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::majorAxisStart()
+{
+  if (!myMajorAxisStart)
+    collectAuxiliary();
+  return myMajorAxisStart;
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::majorAxisEnd()
+{
+  if (!myMajorAxisEnd)
+    collectAuxiliary();
+  return myMajorAxisEnd;
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::minorAxisStart()
+{
+  if (!myMinorAxisStart)
+    collectAuxiliary();
+  return myMinorAxisStart;
+}
+
+std::shared_ptr<SketchAPI_Point> SketchAPI_MacroEllipse::minorAxisEnd()
+{
+  if (!myMinorAxisEnd)
+    collectAuxiliary();
+  return myMinorAxisEnd;
+}
+
+std::shared_ptr<SketchAPI_Line> SketchAPI_MacroEllipse::majorAxis()
+{
+  if (!myMajorAxis)
+    collectAuxiliary();
+  return myMajorAxis;
+}
+
+std::shared_ptr<SketchAPI_Line> SketchAPI_MacroEllipse::minorAxis()
+{
+  if (!myMinorAxis)
+    collectAuxiliary();
+  return myMinorAxis;
+}
+
+void SketchAPI_MacroEllipse::collectAuxiliary()
+{
+  // collect auxiliary features
+  int aNbSubs = mySketch->numberOfSubs();
+  std::shared_ptr<SketchAPI_Point>* anAuxPoint[] = {
+    &myCenter, &myFocus1, &myFocus2,
+    &myMajorAxisStart, &myMajorAxisEnd,
+    &myMinorAxisStart, &myMinorAxisEnd
+  };
+  std::shared_ptr<SketchAPI_Line>* anAuxLine[] = {&myMajorAxis, &myMinorAxis};
+  for (int aPtInd = 7, aLinInd = 2; (aPtInd > 0 || aLinInd > 0) && aNbSubs >= 0; ) {
+    FeaturePtr aCurFeature = mySketch->subFeature(--aNbSubs);
+    if (aPtInd > 0 && aCurFeature->getKind() == SketchPlugin_Point::ID())
+      anAuxPoint[--aPtInd]->reset(new SketchAPI_Point(aCurFeature));
+    else if (aLinInd > 0 && aCurFeature->getKind() == SketchPlugin_Line::ID())
+      anAuxLine[--aLinInd]->reset(new SketchAPI_Line(aCurFeature));
+  }
+}
diff --git a/src/SketchAPI/SketchAPI_MacroEllipse.h b/src/SketchAPI/SketchAPI_MacroEllipse.h
new file mode 100644 (file)
index 0000000..bc2ab13
--- /dev/null
@@ -0,0 +1,136 @@
+// 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 SketchAPI_MacroEllipse_H_
+#define SketchAPI_MacroEllipse_H_
+
+#include "SketchAPI.h"
+#include "SketchAPI_SketchEntity.h"
+
+#include <SketchPlugin_MacroEllipse.h>
+
+class ModelHighAPI_RefAttr;
+class SketchAPI_Point;
+class SketchAPI_Line;
+
+/// \class SketchAPI_MacroEllipse
+/// \ingroup CPPHighAPI
+/// \brief Interface for Ellipse feature.
+class SketchAPI_MacroEllipse: public SketchAPI_SketchEntity
+{
+public:
+  /// Constructor without values.
+  SKETCHAPI_EXPORT
+  explicit SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                  bool callInitialize = true);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT
+  SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                         double theX1, double theY1,
+                         double theX2, double theY2,
+                         double theX3, double theY3,
+                         bool byCenter = true);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT
+  SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
+                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
+                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3,
+                         bool byCenter = true);
+
+  /// Constructor with values and/or references.
+  SKETCHAPI_EXPORT
+  SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
+                         const ModelHighAPI_RefAttr&           thePoint1Ref,
+                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
+                         const ModelHighAPI_RefAttr&           thePoint2Ref,
+                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3,
+                         const ModelHighAPI_RefAttr&           thePoint3Ref,
+                         bool byCenter = true);
+
+  /// Destructor.
+  SKETCHAPI_EXPORT
+  virtual ~SketchAPI_MacroEllipse();
+
+  INTERFACE_1(SketchPlugin_MacroEllipse::ID(),
+              ellipseType, SketchPlugin_MacroEllipse::ELLIPSE_TYPE(),
+              ModelAPI_AttributeString, /** Ellipse type */)
+
+  /// Return created auxiliary center point
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> center();
+  /// Return created auxiliary focus in the positive direction of major axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> focus1();
+  /// Return created auxiliary focus in the negative direction of major axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> focus2();
+  /// Return created auxiliary point - start of major axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> majorAxisStart();
+  /// Return created auxiliary point - end of major axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> majorAxisEnd();
+  /// Return created auxiliary point - start of minor axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> minorAxisStart();
+  /// Return created auxiliary point - end of minor axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Point> minorAxisEnd();
+  /// Return created auxiliary major axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Line> majorAxis();
+  /// Return created auxiliary minor axis
+  SKETCHAPI_EXPORT std::shared_ptr<SketchAPI_Line> minorAxis();
+
+protected:
+  // find a parent sketch
+  void storeSketch(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+private:
+  /// Set flag of creation by center, major semi-axis and passed point.
+  void setByCenterAndPassedPoints(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                  const ModelHighAPI_RefAttr&           theCenterRef,
+                                  const std::shared_ptr<GeomAPI_Pnt2d>& theMajorAxisPoint,
+                                  const ModelHighAPI_RefAttr&           theMajorAxisPointRef,
+                                  const std::shared_ptr<GeomAPI_Pnt2d>& thePassedPoint,
+                                  const ModelHighAPI_RefAttr&           thePassedPointRef);
+  /// Set flag of creation by major axis and passed point.
+  void setByMajorAxisAndPassedPoint(const std::shared_ptr<GeomAPI_Pnt2d>& theMajorAxisStart,
+                                    const ModelHighAPI_RefAttr&           theMajorAxisStartRef,
+                                    const std::shared_ptr<GeomAPI_Pnt2d>& theMajorAxisEnd,
+                                    const ModelHighAPI_RefAttr&           theMajorAxisEndRef,
+                                    const std::shared_ptr<GeomAPI_Pnt2d>& thePassedPoint,
+                                    const ModelHighAPI_RefAttr&           thePassedPointRef);
+
+  /// Collect auxiliary features
+  void collectAuxiliary();
+
+private:
+  CompositeFeaturePtr mySketch;
+  std::shared_ptr<SketchAPI_Point> myCenter;
+  std::shared_ptr<SketchAPI_Point> myFocus1;
+  std::shared_ptr<SketchAPI_Point> myFocus2;
+  std::shared_ptr<SketchAPI_Point> myMajorAxisStart;
+  std::shared_ptr<SketchAPI_Point> myMajorAxisEnd;
+  std::shared_ptr<SketchAPI_Point> myMinorAxisStart;
+  std::shared_ptr<SketchAPI_Point> myMinorAxisEnd;
+  std::shared_ptr<SketchAPI_Line>  myMajorAxis;
+  std::shared_ptr<SketchAPI_Line>  myMinorAxis;
+};
+
+/// Pointer on Circle object.
+typedef std::shared_ptr<SketchAPI_MacroEllipse> MacroEllipsePtr;
+
+#endif // SketchAPI_MacroEllipse_H_
diff --git a/src/SketchAPI/SketchAPI_MacroEllipticArc.cpp b/src/SketchAPI/SketchAPI_MacroEllipticArc.cpp
new file mode 100644 (file)
index 0000000..2955ac5
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SketchAPI_MacroEllipticArc.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelHighAPI_RefAttr.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_MacroEllipticArc.h>
+
+#define CENTER_POINT (std::dynamic_pointer_cast<GeomDataAPI_Point2D>( \
+                      feature()->attribute(SketchPlugin_MacroEllipticArc::CENTER_ID())))
+#define MAJOR_AXIS_POSITIVE (std::dynamic_pointer_cast<GeomDataAPI_Point2D>( \
+                      feature()->attribute(SketchPlugin_MacroEllipticArc::MAJOR_AXIS_POINT_ID())))
+#define START_POINT (std::dynamic_pointer_cast<GeomDataAPI_Point2D>( \
+                     feature()->attribute(SketchPlugin_MacroEllipticArc::START_POINT_ID())))
+#define END_POINT (std::dynamic_pointer_cast<GeomDataAPI_Point2D>( \
+                   feature()->attribute(SketchPlugin_MacroEllipticArc::END_POINT_ID())))
+
+#define CENTER_POINT_REF (feature()->refattr(SketchPlugin_MacroEllipticArc::CENTER_REF_ID()))
+#define MAJOR_AXIS_POSITIVE_REF (feature()->refattr( \
+                                 SketchPlugin_MacroEllipticArc::MAJOR_AXIS_POINT_REF_ID()))
+#define START_POINT_REF (feature()->refattr(SketchPlugin_MacroEllipticArc::START_POINT_REF_ID()))
+#define END_POINT_REF (feature()->refattr(SketchPlugin_MacroEllipticArc::END_POINT_REF_ID()))
+
+
+static void fillAttribute(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
+                          const ModelHighAPI_RefAttr& thePointRef,
+                          std::shared_ptr<GeomDataAPI_Point2D> thePointAttr,
+                          AttributeRefAttrPtr thePointRefAttr)
+{
+  GeomPnt2dPtr aPoint = thePoint;
+  if (!thePointRef.isEmpty()) {
+    fillAttribute(thePointRef, thePointRefAttr);
+    std::shared_ptr<GeomDataAPI_Point2D> anAttrPnt =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePointRefAttr->attr());
+    if (anAttrPnt)
+      aPoint = anAttrPnt->pnt();
+  }
+  fillAttribute(aPoint, thePointAttr);
+}
+
+SketchAPI_MacroEllipticArc::SketchAPI_MacroEllipticArc(const FeaturePtr& theFeature)
+  : SketchAPI_MacroEllipse(theFeature, false)
+{
+}
+
+SketchAPI_MacroEllipticArc::SketchAPI_MacroEllipticArc(
+    const std::shared_ptr<ModelAPI_Feature>& theFeature,
+    const std::shared_ptr<GeomAPI_Pnt2d>&    theCenter,
+    const ModelHighAPI_RefAttr&              theCenterRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>&    theMajorAxisPoint,
+    const ModelHighAPI_RefAttr&              theMajorAxisPointRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>&    theArcStart,
+    const ModelHighAPI_RefAttr&              theArcStartRef,
+    const std::shared_ptr<GeomAPI_Pnt2d>&    theArcEnd,
+    const ModelHighAPI_RefAttr&              theArcEndRef,
+    const bool                               theReversed)
+  : SketchAPI_MacroEllipse(theFeature, false)
+{
+  if (initialize()) {
+    fillAttribute(theCenter, theCenterRef,
+                  CENTER_POINT, CENTER_POINT_REF);
+    fillAttribute(theMajorAxisPoint, theMajorAxisPointRef,
+                  MAJOR_AXIS_POSITIVE, MAJOR_AXIS_POSITIVE_REF);
+    fillAttribute(theArcStart, theArcStartRef, START_POINT, START_POINT_REF);
+    fillAttribute(theArcEnd, theArcEndRef, END_POINT, END_POINT_REF);
+
+    fillAttribute(theReversed, reversed());
+
+    storeSketch(theFeature);
+    execute();
+  }
+}
+
+SketchAPI_MacroEllipticArc::~SketchAPI_MacroEllipticArc()
+{
+}
diff --git a/src/SketchAPI/SketchAPI_MacroEllipticArc.h b/src/SketchAPI/SketchAPI_MacroEllipticArc.h
new file mode 100644 (file)
index 0000000..51eb3a3
--- /dev/null
@@ -0,0 +1,67 @@
+// 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 SketchAPI_MacroEllipticArc_H_
+#define SketchAPI_MacroEllipticArc_H_
+
+#include "SketchAPI.h"
+#include "SketchAPI_MacroEllipse.h"
+
+#include <SketchPlugin_MacroEllipticArc.h>
+
+/// \class SketchAPI_MacroEllipticArc
+/// \ingroup CPPHighAPI
+/// \brief Interface for Elliptic Arc feature.
+class SketchAPI_MacroEllipticArc: public SketchAPI_MacroEllipse
+{
+public:
+  /// Constructor without values.
+  SKETCHAPI_EXPORT
+  explicit SketchAPI_MacroEllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values and/or references.
+  SKETCHAPI_EXPORT
+  SketchAPI_MacroEllipticArc(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                             const std::shared_ptr<GeomAPI_Pnt2d>&    theCenter,
+                             const ModelHighAPI_RefAttr&              theCenterRef,
+                             const std::shared_ptr<GeomAPI_Pnt2d>&    theMajorAxisPoint,
+                             const ModelHighAPI_RefAttr&              theMajorAxisPointRef,
+                             const std::shared_ptr<GeomAPI_Pnt2d>&    theArcStart,
+                             const ModelHighAPI_RefAttr&              theArcStartRef,
+                             const std::shared_ptr<GeomAPI_Pnt2d>&    theArcEnd,
+                             const ModelHighAPI_RefAttr&              theArcEndRef,
+                             const bool                               theReversed);
+
+  /// Destructor.
+  SKETCHAPI_EXPORT
+  virtual ~SketchAPI_MacroEllipticArc();
+
+  INTERFACE_3(SketchPlugin_MacroEllipticArc::ID(),
+              startPoint, SketchPlugin_MacroEllipticArc::START_POINT_ID(),
+              GeomDataAPI_Point2D, /** Start point of elliptic arc */,
+              endPoint, SketchPlugin_MacroEllipticArc::END_POINT_ID(),
+              GeomDataAPI_Point2D, /** End point of elliptic arc */,
+              reversed, SketchPlugin_MacroEllipticArc::REVERSED_ID(),
+              ModelAPI_AttributeBoolean, /** Reversed flag for elliptic arc*/)
+};
+
+/// Pointer on Elliptic Arc object.
+typedef std::shared_ptr<SketchAPI_MacroEllipticArc> MacroEllipticArcPtr;
+
+#endif // SketchAPI_MacroEllipticArc_H_
index 76fb2dc18b30bedfdea9e9e43fd45daf343a44a0..4baf94150d033d352ab0027122a39bbae3822ffd 100644 (file)
 
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Point.h>
 
-#include <SketchAPI_Line.h>
-#include <SketchAPI_Circle.h>
 #include <SketchAPI_Arc.h>
+#include <SketchAPI_Circle.h>
+#include <SketchAPI_Ellipse.h>
+#include <SketchAPI_EllipticArc.h>
+#include <SketchAPI_Line.h>
 #include <SketchAPI_Point.h>
 
 #include <ModelHighAPI_Dumper.h>
@@ -100,6 +104,10 @@ std::shared_ptr<SketchAPI_SketchEntity> SketchAPI_Projection::createdFeature() c
     anEntity.reset(new SketchAPI_Circle(aProjectedFeature));
   else if (aProjectedFeature->getKind() == SketchPlugin_Arc::ID())
     anEntity.reset(new SketchAPI_Arc(aProjectedFeature));
+  else if (aProjectedFeature->getKind() == SketchPlugin_Ellipse::ID())
+    anEntity.reset(new SketchAPI_Ellipse(aProjectedFeature));
+  else if (aProjectedFeature->getKind() == SketchPlugin_EllipticArc::ID())
+    anEntity.reset(new SketchAPI_EllipticArc(aProjectedFeature));
   else if (aProjectedFeature->getKind() == SketchPlugin_Point::ID())
     anEntity.reset(new SketchAPI_Point(aProjectedFeature));
 
index 722cbbaa77e40782003c6940d9f14d61f867801a..0504e411d9daccf4e2251f6d8ce4e63faaf879a8 100644 (file)
 #include <ModelHighAPI_Tools.h>
 //--------------------------------------------------------------------------------------
 #include "SketchAPI_Arc.h"
-#include "SketchAPI_MacroArc.h"
 #include "SketchAPI_Circle.h"
+#include "SketchAPI_Ellipse.h"
+#include "SketchAPI_EllipticArc.h"
 #include "SketchAPI_IntersectionPoint.h"
 #include "SketchAPI_Line.h"
+#include "SketchAPI_MacroArc.h"
 #include "SketchAPI_MacroCircle.h"
+#include "SketchAPI_MacroEllipse.h"
+#include "SketchAPI_MacroEllipticArc.h"
 #include "SketchAPI_Mirror.h"
 #include "SketchAPI_Point.h"
 #include "SketchAPI_Projection.h"
@@ -466,7 +470,6 @@ std::shared_ptr<SketchAPI_Circle>
 
 std::shared_ptr<SketchAPI_Circle> SketchAPI_Sketch::addCircle(const std::string & theExternalName)
 {
-  // TODO(spo): Add constraint SketchConstraintRigid like in PythonAPI. Is it necessary?
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Circle::ID());
   return CirclePtr(new SketchAPI_Circle(aFeature, theExternalName));
@@ -523,22 +526,33 @@ std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
 std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
                                                 const ModelHighAPI_RefAttr& theTangentPoint,
                                                 double theEndX, double theEndY,
-                                                bool theInversed)
+                                                bool theInversed,
+                                                bool theTransversal)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_MacroArc::ID());
-  return MacroArcPtr(new SketchAPI_MacroArc(
-    aFeature, theTangentPoint, theEndX, theEndY, theInversed));
+  MacroArcPtr aMacroArc(new SketchAPI_MacroArc(aFeature));
+  if (theTransversal)
+    aMacroArc->setByTransversal(theTangentPoint, theEndX, theEndY, theInversed);
+  else
+    aMacroArc->setByTangent(theTangentPoint, theEndX, theEndY, theInversed);
+  return aMacroArc;
 }
 
 std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
                                               const ModelHighAPI_RefAttr& theTangentPoint,
                                               const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
-                                              bool theInversed)
+                                              bool theInversed,
+                                              bool theTransversal)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_MacroArc::ID());
-  return MacroArcPtr(new SketchAPI_MacroArc(aFeature, theTangentPoint, theEnd, theInversed));
+  MacroArcPtr aMacroArc(new SketchAPI_MacroArc(aFeature));
+  if (theTransversal)
+    aMacroArc->setByTransversal(theTangentPoint, theEnd, theInversed);
+  else
+    aMacroArc->setByTangent(theTangentPoint, theEnd, theInversed);
+  return aMacroArc;
 }
 
 std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const ModelHighAPI_Selection & theExternal)
@@ -550,12 +564,137 @@ std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const ModelHighAPI_Selec
 
 std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const std::string & theExternalName)
 {
-  // TODO(spo): Add constraint SketchConstraintRigid like in PythonAPI. Is it necessary?
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Arc::ID());
   return ArcPtr(new SketchAPI_Arc(aFeature, theExternalName));
 }
 
+//--------------------------------------------------------------------------------------
+std::shared_ptr<SketchAPI_Ellipse> SketchAPI_Sketch::addEllipse(
+    double theCenterX, double theCenterY,
+    double theFocusX, double theFocusY,
+    double theMinorRadius)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_Ellipse::ID());
+  return EllipsePtr(new SketchAPI_Ellipse(aFeature,
+      theCenterX, theCenterY, theFocusX, theFocusY, theMinorRadius));
+}
+
+std::shared_ptr<SketchAPI_Ellipse> SketchAPI_Sketch::addEllipse(
+    const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+    double theMinorRadius)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_Ellipse::ID());
+  return EllipsePtr(new SketchAPI_Ellipse(aFeature, theCenter, theFocus, theMinorRadius));
+}
+
+std::shared_ptr<SketchAPI_MacroEllipse> SketchAPI_Sketch::addEllipse(
+    double thePoint1X, double thePoint1Y,
+    double thePoint2X, double thePoint2Y,
+    double thePassedX, double thePassedY,
+    bool isPoint1Center)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_MacroEllipse::ID());
+  return MacroEllipsePtr(new SketchAPI_MacroEllipse(aFeature,
+      thePoint1X, thePoint1Y, thePoint2X, thePoint2Y, thePassedX, thePassedY, isPoint1Center));
+}
+
+std::shared_ptr<SketchAPI_MacroEllipse> SketchAPI_Sketch::addEllipse(
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint1,
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint2,
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePassedPoint,
+    bool isPoint1Center)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_MacroEllipse::ID());
+  MacroEllipsePtr anEllipse;
+  if (thePoint1.second.isEmpty() &&
+      thePoint2.second.isEmpty() &&
+      thePassedPoint.second.isEmpty()) {
+    anEllipse.reset(new SketchAPI_MacroEllipse(aFeature,
+        thePoint1.first, thePoint2.first, thePassedPoint.first, isPoint1Center));
+  }
+  else {
+    anEllipse.reset(new SketchAPI_MacroEllipse(aFeature,
+        thePoint1.first, thePoint1.second,
+        thePoint2.first, thePoint2.second,
+        thePassedPoint.first, thePassedPoint.second,
+        isPoint1Center));
+  }
+  return anEllipse;
+}
+
+std::shared_ptr<SketchAPI_Ellipse> SketchAPI_Sketch::addEllipse(
+    const ModelHighAPI_Selection & theExternal)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_Ellipse::ID());
+  return EllipsePtr(new SketchAPI_Ellipse(aFeature, theExternal));
+}
+
+std::shared_ptr<SketchAPI_Ellipse> SketchAPI_Sketch::addEllipse(
+    const std::string & theExternalName)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_Ellipse::ID());
+  return EllipsePtr(new SketchAPI_Ellipse(aFeature, theExternalName));
+}
+
+//--------------------------------------------------------------------------------------
+std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
+    double theCenterX, double theCenterY,
+    double theFocusX, double theFocusY,
+    double theStartX, double theStartY,
+    double theEndX, double theEndY,
+    bool theInversed)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_EllipticArc::ID());
+  return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature,
+      theCenterX, theCenterY,
+      theFocusX, theFocusY,
+      theStartX, theStartY,
+      theEndX, theEndY,
+      theInversed));
+}
+
+std::shared_ptr<SketchAPI_MacroEllipticArc> SketchAPI_Sketch::addEllipticArc(
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theStartPoint,
+    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theEndPoint,
+    bool theInversed)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_MacroEllipticArc::ID());
+  return MacroEllipticArcPtr(new SketchAPI_MacroEllipticArc(aFeature,
+      theCenter.first, theCenter.second,
+      theMajorAxisPoint.first, theMajorAxisPoint.second,
+      theStartPoint.first, theStartPoint.second,
+      theEndPoint.first, theEndPoint.second,
+      theInversed));
+}
+
+std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
+    const ModelHighAPI_Selection & theExternal)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_EllipticArc::ID());
+  return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature, theExternal));
+}
+
+std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
+    const std::string & theExternalName)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_EllipticArc::ID());
+  return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature, theExternalName));
+}
+
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
     const ModelHighAPI_Selection & theExternalFeature,
@@ -1007,6 +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)
+{
+  AttributePoint2DPtr aMajorAxisEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()));
+  return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
 static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
 {
   std::shared_ptr<GeomAPI_Pnt2d> aMiddlePoint;
@@ -1022,6 +1168,8 @@ static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
       aMiddlePoint = pointOnCircle(aFeature);
     else if (aFeatureKind == SketchPlugin_Arc::ID())
       aMiddlePoint = middlePointOnArc(aFeature);
+    else if (aFeatureKind == SketchPlugin_Ellipse::ID())
+      aMiddlePoint = pointOnEllipse(aFeature);
   }
   return aMiddlePoint;
 }
index c32c88d9daf73dc0980d559d2988f126f56a2f10..a6ce997207990eed4572ad8ec1110b5d09385546 100644 (file)
@@ -42,6 +42,10 @@ class SketchAPI_Arc;
 class SketchAPI_MacroArc;
 class SketchAPI_Circle;
 class SketchAPI_MacroCircle;
+class SketchAPI_Ellipse;
+class SketchAPI_MacroEllipse;
+class SketchAPI_EllipticArc;
+class SketchAPI_MacroEllipticArc;
 class SketchAPI_IntersectionPoint;
 class SketchAPI_Line;
 class SketchAPI_Mirror;
@@ -240,19 +244,21 @@ public:
       const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
       const std::shared_ptr<GeomAPI_Pnt2d>& thePassed);
 
-  /// Add arc
+  /// Add transversal/tangent arc
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroArc> addArc(
-      const ModelHighAPI_RefAttr& theTangentPoint,
+      const ModelHighAPI_RefAttr& theConnectedPoint,
       double theEndX, double theEndY,
-      bool theInversed);
+      bool theInversed,
+      bool theTransversal = false);
 
-  /// Add arc
+  /// Add transversal/tangent arc
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroArc> addArc(
-      const ModelHighAPI_RefAttr& theTangentPoint,
+      const ModelHighAPI_RefAttr& theConnectedPoint,
       const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
-      bool theInversed);
+      bool theInversed,
+      bool theTransversal = false);
 
   /// Add arc
   SKETCHAPI_EXPORT
@@ -262,6 +268,62 @@ public:
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_Arc> addArc(const std::string & theExternalName);
 
+  /// Add ellipse
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_Ellipse> addEllipse(
+      double theCenterX, double theCenterY,
+      double theFocusX, double theFocusY,
+      double theMinorRadius);
+  /// Add ellipse
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_Ellipse> addEllipse(
+      const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+      const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
+      double theRadius);
+  /// Add ellipse
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_MacroEllipse> addEllipse(
+      double thePoint1X, double thePoint1Y,
+      double thePoint2X, double thePoint2Y,
+      double thePassedX, double thePassedY,
+      bool isPoint1Center = true);
+  /// Add ellipse
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_MacroEllipse> addEllipse(
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint1,
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint2,
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePassedPoint,
+      bool isPoint1Center = true);
+  /// Add ellipse
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_Ellipse> addEllipse(const ModelHighAPI_Selection & theExternal);
+  /// Add ellipse
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_Ellipse> addEllipse(const std::string & theExternalName);
+
+  /// Add elliptic arc
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(
+      double theCenterX, double theCenterY,
+      double theFocusX, double theFocusY,
+      double theStartX, double theStartY,
+      double theEndX, double theEndY,
+      bool theInversed = false);
+  /// Add elliptic arc
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_MacroEllipticArc> addEllipticArc(
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theStartPoint,
+      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theEndPoint,
+      bool theInversed = false);
+  /// Add elliptic arc
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(const ModelHighAPI_Selection & theExternal);
+  /// Add elliptic arc
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(const std::string & theExternalName);
+
   /// Add projection
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_Projection> addProjection(
index 808ac012bec5144211356681803c203a2a2fcd9a..467e04349007f9719eb375542bf144417d93f5ea 100644 (file)
@@ -20,6 +20,8 @@
 #include "SketchAPI_SketchEntity.h"
 #include <SketchAPI_Arc.h>
 #include <SketchAPI_Circle.h>
+#include <SketchAPI_Ellipse.h>
+#include <SketchAPI_EllipticArc.h>
 #include <SketchAPI_IntersectionPoint.h>
 #include <SketchAPI_Line.h>
 #include <SketchAPI_Point.h>
@@ -29,6 +31,7 @@
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
@@ -96,6 +99,10 @@ SketchAPI_SketchEntity::wrap(const std::list<std::shared_ptr<ModelAPI_Feature> >
       aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Arc(*anIt)));
     else if ((*anIt)->getKind() == SketchPlugin_Circle::ID())
       aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Circle(*anIt)));
+    else if ((*anIt)->getKind() == SketchPlugin_Ellipse::ID())
+      aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Ellipse(*anIt)));
+    else if ((*anIt)->getKind() == SketchPlugin_EllipticArc::ID())
+      aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_EllipticArc(*anIt)));
     else if ((*anIt)->getKind() == SketchPlugin_Point::ID())
       aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Point(*anIt)));
     else if ((*anIt)->getKind() == SketchPlugin_IntersectionPoint::ID())
index 1f8748712ddff145543c7bf32a1992777962fffc..93788350bae92690c04502d068eb60227b3b250c 100644 (file)
   #include "SketchAPI_MacroArc.h"
   #include "SketchAPI_Circle.h"
   #include "SketchAPI_MacroCircle.h"
+  #include "SketchAPI_Ellipse.h"
+  #include "SketchAPI_MacroEllipse.h"
+  #include "SketchAPI_EllipticArc.h"
+  #include "SketchAPI_MacroEllipticArc.h"
   #include "SketchAPI_Constraint.h"
   #include "SketchAPI_ConstraintAngle.h"
   #include "SketchAPI_IntersectionPoint.h"
index d72e0c56bf28bd1a262e4d8064f2d56425048513..1edde96b787f1727fe859a269003b38860465146 100644 (file)
@@ -28,6 +28,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintAngle.h
     SketchPlugin_ConstraintBase.h
     SketchPlugin_ConstraintCoincidence.h
+    SketchPlugin_ConstraintCoincidenceInternal.h
     SketchPlugin_ConstraintCollinear.h
     SketchPlugin_ConstraintDistance.h
     SketchPlugin_ConstraintDistanceAlongDir.h
@@ -46,6 +47,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintTangent.h
     SketchPlugin_ConstraintVertical.h
     SketchPlugin_Ellipse.h
+    SketchPlugin_EllipticArc.h
     SketchPlugin_ExternalValidator.h
     SketchPlugin_Feature.h
     SketchPlugin_IntersectionPoint.h
@@ -54,6 +56,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_MacroArcReentrantMessage.h
     SketchPlugin_MacroCircle.h
     SketchPlugin_MacroEllipse.h
+    SketchPlugin_MacroEllipticArc.h
     SketchPlugin_MultiRotation.h
     SketchPlugin_MultiTranslation.h
     SketchPlugin_Plugin.h
@@ -74,6 +77,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_Constraint.cpp
     SketchPlugin_ConstraintAngle.cpp
     SketchPlugin_ConstraintCoincidence.cpp
+    SketchPlugin_ConstraintCoincidenceInternal.cpp
     SketchPlugin_ConstraintCollinear.cpp
     SketchPlugin_ConstraintDistance.cpp
     SketchPlugin_ConstraintDistanceAlongDir.cpp
@@ -92,6 +96,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintTangent.cpp
     SketchPlugin_ConstraintVertical.cpp
     SketchPlugin_Ellipse.cpp
+    SketchPlugin_EllipticArc.cpp
     SketchPlugin_ExternalValidator.cpp
     SketchPlugin_Feature.cpp
     SketchPlugin_IntersectionPoint.cpp
@@ -99,6 +104,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_MacroArc.cpp
     SketchPlugin_MacroCircle.cpp
     SketchPlugin_MacroEllipse.cpp
+    SketchPlugin_MacroEllipticArc.cpp
     SketchPlugin_MultiRotation.cpp
     SketchPlugin_MultiTranslation.cpp
     SketchPlugin_Plugin.cpp
@@ -130,6 +136,7 @@ SET(XML_RESOURCES
 
 SET(TEXT_RESOURCES
        SketchPlugin_msg_en.ts
+       SketchPlugin_msg_fr.ts
 )
 
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
@@ -195,36 +202,56 @@ ADD_UNIT_TESTS(
   Test2824.py
   Test2860.py
   Test2894.py
+  Test3019.py
   TestArcBehavior.py
   TestChangeSketchPlane1.py
   TestChangeSketchPlane2.py
   TestChangeSketchPlane3.py
+  TestChangeSketchPlane4.py
   TestConstraintAngle.py
+  TestConstraintAngleEllipse.py
   TestConstraintCoincidence.py
+  TestConstraintCoincidenceEllipse.py
+  TestConstraintCoincidenceEllipticArc.py
   TestConstraintCollinear.py
+  TestConstraintCollinearEllipse.py
   TestConstraintDistance.py
+  TestConstraintDistanceEllipse.py
   TestConstraintDistanceBehavior.py
   TestConstraintDistanceHorizontal.py
   TestConstraintDistanceVertical.py
   TestConstraintEqual.py
+  TestConstraintEqualEllipse.py
   TestConstraintFixed.py
   TestConstraintHorizontal.py
   TestConstraintHorizontalValidator.py
   TestConstraintLength.py
   TestConstraintMiddlePoint.py
+  TestConstraintMiddlePointOnArc.py
+  TestConstraintMiddlePointOnEllipticArc.py
   TestConstraintParallel.py
   TestConstraintPerpendicular.py
+  TestConstraintPerpendicularArcLine.py
+  TestConstraintPerpendicularEllipseLine.py
   TestConstraintRadius.py
   TestConstraintRadiusFailure.py
   TestConstraintTangent.py
+  TestConstraintTangentEllipse.py
+  TestConstraintTangentEllipticArc.py
   TestConstraintVertical.py
   TestCreateArcByCenterStartEnd.py
   TestCreateArcByTangentEdge.py
   TestCreateArcByThreePoints.py
+  TestCreateArcByTransversalLine.py
   TestCreateArcChangeType.py
   TestCreateCircleByCenterAndPassed.py
   TestCreateCircleByThreePoints.py
   TestCreateCircleChangeType.py
+  TestCreateEllipseByCenterSemiaxisAndPassed.py
+  TestCreateEllipseByMajorAxisAndPassed.py
+  TestCreateEllipseByExternal.py
+  TestCreateEllipticArc.py
+  TestCreateEllipticArcByExternal.py
   TestDegeneratedGeometry.py
   TestDistanceDump.py
   TestDistanceSignedVsUnsigned01.py
@@ -252,9 +279,13 @@ ADD_UNIT_TESTS(
   TestMultiTranslation.py
   TestPresentation.py
   TestProjection.py
+  TestProjectionEllipse.py
+  TestProjectionEllipticArc.py
   TestProjectionIntoResult.py
   TestProjectionUpdate.py
   TestRectangle.py
+  TestRemoveEllipse.py
+  TestRemoveEllipticArc.py
   TestRemoveSketch.py
   TestSignedDistancePointLine.py
   TestSignedDistancePointPoint.py
@@ -262,6 +293,7 @@ ADD_UNIT_TESTS(
   TestSketchPointLine.py
   TestSnowflake.py
   TestSplit.py
+  TestSplitEllipse.py
   TestSplitLine.py
   TestSplitPreview.py
   TestTrimArc01.py
@@ -278,6 +310,7 @@ ADD_UNIT_TESTS(
   TestTrimCircle04.py
   TestTrimCircle05.py
   TestTrimCircleAndArc01.py
+  TestTrimEllipse.py
   TestTrimLine01.py
   TestTrimLine02.py
   TestTrimLine03.py
@@ -289,6 +322,7 @@ if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
   ADD_UNIT_TESTS(
     TestMoveArc.py
     TestMoveCircle.py
+    TestMoveEllipse.py
     TestMoveLine.py
     TestMovementComplex.py
     TestMovePoint.py
index 85fb674259d9c577b6dd5a84865f82d85a0e1e38..1cd476011e1bdfd80b334123333b6d1c1ec4f9bc 100644 (file)
@@ -52,9 +52,9 @@
 // for sqrt on Linux
 #include <cmath>
 
-const double tolerance = 1e-7;
-const double paramTolerance = 1.e-4;
-const double PI = 3.141592653589793238463;
+static const double tolerance = 1e-7;
+static const double paramTolerance = 1.e-4;
+static const double PI = 3.141592653589793238463;
 
 
 SketchPlugin_Arc::SketchPlugin_Arc()
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.cpp b/src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.cpp
new file mode 100644 (file)
index 0000000..ccab1cf
--- /dev/null
@@ -0,0 +1,38 @@
+// 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
+//
+
+#include "SketchPlugin_ConstraintCoincidenceInternal.h"
+
+SketchPlugin_ConstraintCoincidenceInternal::SketchPlugin_ConstraintCoincidenceInternal()
+{
+}
+
+void SketchPlugin_ConstraintCoincidenceInternal::initAttributes()
+{
+  SketchPlugin_ConstraintCoincidence::initAttributes();
+}
+
+void SketchPlugin_ConstraintCoincidenceInternal::execute()
+{
+}
+
+AISObjectPtr SketchPlugin_ConstraintCoincidenceInternal::getAISObject(AISObjectPtr thePrevious)
+{
+  return AISObjectPtr();
+}
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.h b/src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.h
new file mode 100644 (file)
index 0000000..fac0060
--- /dev/null
@@ -0,0 +1,59 @@
+// 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
+//
+
+#ifndef SketchPlugin_ConstraintCoincidenceInternal_H_
+#define SketchPlugin_ConstraintCoincidenceInternal_H_
+
+#include "SketchPlugin.h"
+#include "SketchPlugin_ConstraintCoincidence.h"
+
+/** \class SketchPlugin_ConstraintCoincidenceInternal
+ *  \ingroup Plugins
+ *  \brief Internal coincidence constraint not applicable for the end user
+ */
+class SketchPlugin_ConstraintCoincidenceInternal : public SketchPlugin_ConstraintCoincidence
+{
+  public:
+  /// Coincidence constraint kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidenceInternal");
+    return MY_CONSTRAINT_COINCIDENCE_ID;
+  }
+  /// \brief Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_ConstraintCoincidenceInternal::ID();
+    return MY_KIND;
+  }
+
+  /// Returns the AIS preview
+  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// \brief Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintCoincidenceInternal();
+};
+
+#endif
index df323b1674c425972a5fd4967c57130812f71fd3..098951a853abb74c05e7fee006e6a6e83b5b1b8f 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-// File:        SketchPlugin_Ellipse.cpp
-// Created:     26 April 2017
-// Author:      Artem ZHIDKOV
-
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_Sketch.h>
 
 #include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Pnt2d.h>
+
 #include <GeomDataAPI_Point2D.h>
+
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 
+#include <cmath>
+
 static const double tolerance = 1e-7;
 
 
@@ -44,10 +47,22 @@ SketchPlugin_Ellipse::SketchPlugin_Ellipse()
 void SketchPlugin_Ellipse::initDerivedClassAttributes()
 {
   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
-  data()->addAttribute(FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(FIRST_FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(SECOND_FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MINOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MINOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
 
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_FOCUS_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_START_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_END_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_START_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_END_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_RADIUS_ID());
+
   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
 }
@@ -59,46 +74,11 @@ void SketchPlugin_Ellipse::execute()
     return;
   }
 
-  // Compute a ellipse in 3D view.
-  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FOCUS_ID()));
-  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
-  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
-  if (!aCenterAttr->isInitialized() ||
-      !aFocusAttr->isInitialized() ||
-      !aMajorRadiusAttr->isInitialized() ||
-      !aMinorRadiusAttr->isInitialized()) {
-    return;
-  }
-
-  double aMajorRadius = aMajorRadiusAttr->value();
-  double aMinorRadius = aMinorRadiusAttr->value();
-  if(aMajorRadius < tolerance || aMinorRadius < tolerance) {
-    return;
-  }
-
-  // Make a visible point.
-  SketchPlugin_Sketch::createPoint2DResult(this, aSketch, CENTER_ID(), 0);
-
-  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-      aSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+  // Calculate all characteristics of the ellipse.
+  fillCharacteristicPoints();
 
   // Make a visible ellipse.
-  std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
-  std::shared_ptr<GeomAPI_Pnt> aFocus(aSketch->to3D(aFocusAttr->x(), aFocusAttr->y()));
-  std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
-  std::shared_ptr<GeomAPI_Dir> aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
-      aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
-
-  std::shared_ptr<GeomAPI_Shape> anEllipseShape =
-      GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, aMajorRadius, aMinorRadius);
-
-  std::shared_ptr<ModelAPI_ResultConstruction> aResult = document()->createConstruction(data(), 1);
-  aResult->setShape(anEllipseShape);
-  aResult->setIsInHistory(false);
-  setResult(aResult, 1);
+  createEllipse(aSketch, 0);
 }
 
 bool SketchPlugin_Ellipse::isFixed() {
@@ -125,7 +105,7 @@ void SketchPlugin_Ellipse::attributeChanged(const std::string& theID) {
       aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
 
       std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FOCUS_ID()));
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
       aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
 
       real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
@@ -133,3 +113,90 @@ void SketchPlugin_Ellipse::attributeChanged(const std::string& theID) {
     }
   }
 }
+
+bool SketchPlugin_Ellipse::fillCharacteristicPoints()
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+
+  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
+
+  if (!aCenterAttr->isInitialized() ||
+      !aFocusAttr->isInitialized() ||
+      !aMinorRadiusAttr->isInitialized()) {
+    return false;
+  }
+
+  double aMinorRadius = aMinorRadiusAttr->value();
+  if (aMinorRadius < tolerance) {
+    return false;
+  }
+
+  data()->blockSendAttributeUpdated(true);
+  GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
+  GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
+  GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(),
+    aFocus2d->y() - aCenter2d->y()));
+  GeomDir2dPtr aMinorDir2d(new GeomAPI_Dir2d(-aMajorDir2d->y(), aMajorDir2d->x()));
+
+  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
+  double aFocalDist = aCenter2d->distance(aFocus2d);
+  double aMajorRadius = sqrt(aFocalDist * aFocalDist + aMinorRadius * aMinorRadius);
+  aMajorRadiusAttr->setValue(aMajorRadius);
+
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_FOCUS_ID()))
+    ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_START_ID()))
+      ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius,
+                 aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_END_ID()))
+      ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius,
+                 aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_START_ID()))
+      ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius,
+                 aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
+      ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
+                 aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
+  data()->blockSendAttributeUpdated(false);
+
+  return true;
+}
+
+void SketchPlugin_Ellipse::createEllipse(SketchPlugin_Sketch* theSketch, const int theResultIndex)
+{
+  // Compute a ellipse in 3D view.
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+
+  double aMajorRadius = real(MAJOR_RADIUS_ID())->value();
+  double aMinorRadius = real(MINOR_RADIUS_ID())->value();
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+    theSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+
+  GeomPointPtr aCenter(theSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
+  GeomPointPtr aFocus(theSketch->to3D(aFocusAttr->x(), aFocusAttr->y()));
+  GeomDirPtr aNormal = aNDir->dir();
+  std::shared_ptr<GeomAPI_Shape> anEllipseShape;
+  if (aFocus->distance(aCenter) > tolerance) {
+    GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
+        aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
+
+    anEllipseShape =
+        GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, aMajorRadius, aMinorRadius);
+  }
+  else {
+    // build circle instead of ellipse
+    anEllipseShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aMajorRadius);
+  }
+
+  ResultConstructionPtr aResult = document()->createConstruction(data(), theResultIndex);
+  aResult->setShape(anEllipseShape);
+  aResult->setIsInHistory(false);
+  setResult(aResult, theResultIndex);
+}
index e8c0252bdc623132a9a77246e12431636b670a7f..35c88d1110432ea6515fea4bfd63e358a0753926 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-// File:        SketchPlugin_Ellipse.h
-// Created:     26 April 2017
-// Author:      Artem ZHIDKOV
-
 #ifndef SketchPlugin_Ellipse_H_
 #define SketchPlugin_Ellipse_H_
 
@@ -49,9 +45,41 @@ class SketchPlugin_Ellipse: public SketchPlugin_SketchEntity
   }
 
   /// 2D point - focus of the ellipse
-  inline static const std::string& FOCUS_ID()
+  inline static const std::string& FIRST_FOCUS_ID()
+  {
+    static const std::string ID("ellipse_first_focus");
+    return ID;
+  }
+  /// 2D point - second focus of the ellipse
+  inline static const std::string& SECOND_FOCUS_ID()
+  {
+    static const std::string ID("ellipse_second_focus");
+    return ID;
+  }
+
+  /// 2D point - start point of major axis
+  inline static const std::string& MAJOR_AXIS_START_ID()
+  {
+    static const std::string ID("ellipse_major_axis_start_point");
+    return ID;
+  }
+  /// 2D point - end point of major axis
+  inline static const std::string& MAJOR_AXIS_END_ID()
+  {
+    static const std::string ID("ellipse_major_axis_end_point");
+    return ID;
+  }
+
+  /// 2D point - start point of minor axis
+  inline static const std::string& MINOR_AXIS_START_ID()
   {
-    static const std::string ID("ellipse_focus");
+    static const std::string ID("ellipse_minor_axis_start_point");
+    return ID;
+  }
+  /// 2D point - end point of minor axis
+  inline static const std::string& MINOR_AXIS_END_ID()
+  {
+    static const std::string ID("ellipse_minor_axis_end_point");
     return ID;
   }
 
@@ -91,6 +119,11 @@ class SketchPlugin_Ellipse: public SketchPlugin_SketchEntity
 protected:
   /// \brief Initializes attributes of derived class.
   virtual void initDerivedClassAttributes();
+
+private:
+  bool fillCharacteristicPoints();
+
+  void createEllipse(SketchPlugin_Sketch* theSketch, const int theResultIndex);
 };
 
 #endif
diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.cpp b/src/SketchPlugin/SketchPlugin_EllipticArc.cpp
new file mode 100644 (file)
index 0000000..5b8b109
--- /dev/null
@@ -0,0 +1,291 @@
+// Copyright (C) 2017-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <SketchPlugin_EllipticArc.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <cmath>
+
+static const double tolerance = 1e-7;
+static const double paramTolerance = 1.e-4;
+static const double PI = 3.141592653589793238463;
+
+
+SketchPlugin_EllipticArc::SketchPlugin_EllipticArc()
+  : SketchPlugin_SketchEntity(),
+    myParamDelta(0.0)
+{
+}
+
+void SketchPlugin_EllipticArc::initDerivedClassAttributes()
+{
+  data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(FIRST_FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(SECOND_FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MINOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MINOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId());
+
+  data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_FOCUS_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_START_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_END_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_START_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_END_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_RADIUS_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_RADIUS_ID());
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_EllipticArc::execute()
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if(!aSketch) {
+    return;
+  }
+
+  // Calculate all characteristics of the ellipse.
+  fillCharacteristicPoints();
+
+  // Make a visible ellipse.
+  createEllipticArc(aSketch);
+}
+
+bool SketchPlugin_EllipticArc::isFixed() {
+  return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_EllipticArc::attributeChanged(const std::string& theID) {
+  // the second condition for unability to move external segments anywhere
+  if (theID == EXTERNAL_ID() || isFixed()) {
+    std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+    if (!aSelection) {
+      // empty shape in selection shows that the shape is equal to context
+      ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+      if (anExtRes)
+        aSelection = anExtRes->shape();
+    }
+    // update arguments due to the selection value
+    if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
+      std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
+      std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+
+      bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+      std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+      aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
+      aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
+      aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
+      aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
+
+      real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+      real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+
+      double aStartParam, aMidParam, aEndParam;
+      anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
+      anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
+      anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
+      if (aEndParam < aStartParam)
+        aEndParam += 2.0 * PI;
+      if (aMidParam < aStartParam)
+        aMidParam += 2.0 * PI;
+      boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
+
+      data()->blockSendAttributeUpdated(aWasBlocked, false);
+
+      fillCharacteristicPoints();
+    }
+  }
+  else if (theID == CENTER_ID() || theID == FIRST_FOCUS_ID() ||
+           theID == START_POINT_ID() || theID == END_POINT_ID())
+    fillCharacteristicPoints();
+  else if (theID == REVERSED_ID() && myParamDelta == 0.0)
+    myParamDelta = 2.0 * PI;
+}
+
+static void calculateRadii(const GeomPnt2dPtr& theCenter,
+                           const GeomPnt2dPtr& theFocus,
+                           const GeomPnt2dPtr& thePassed,
+                           double& theMajorRadius,
+                           double& theMinorRadius)
+{
+  GeomPnt2dPtr aSecondFocus(new GeomAPI_Pnt2d(
+      theCenter->xy()->multiplied(2.0)->decreased(theFocus->xy())));
+  theMajorRadius = 0.5 * (thePassed->distance(theFocus) + thePassed->distance(aSecondFocus));
+
+  double aFocalDist = theCenter->distance(theFocus);
+  theMinorRadius = sqrt(theMajorRadius * theMajorRadius - aFocalDist * aFocalDist);
+}
+
+bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_POINT_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aEndPointAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
+
+  if (!aCenterAttr->isInitialized() ||
+      !aFocusAttr->isInitialized() ||
+      !aStartPointAttr->isInitialized()) {
+    return false;
+  }
+
+  GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
+  GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
+  GeomPnt2dPtr aStart2d = aStartPointAttr->pnt();
+
+  double aMajorRadius = 0.0, aMinorRadius = 0.0;
+  calculateRadii(aCenter2d, aFocus2d, aStart2d, aMajorRadius, aMinorRadius);
+  if (aMinorRadius < tolerance * aMajorRadius)
+    return false;
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+  real(MAJOR_RADIUS_ID())->setValue(aMajorRadius);
+  real(MINOR_RADIUS_ID())->setValue(aMinorRadius);
+
+  GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(),
+    aFocus2d->y() - aCenter2d->y()));
+  GeomDir2dPtr aMinorDir2d(new GeomAPI_Dir2d(-aMajorDir2d->y(), aMajorDir2d->x()));
+
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_FOCUS_ID()))
+    ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_START_ID()))
+    ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius,
+               aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_END_ID()))
+    ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius,
+               aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_START_ID()))
+    ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius,
+               aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
+    ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
+               aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
+
+  if (aEndPointAttr->isInitialized()) {
+    // recalculate REVERSED flag
+    std::shared_ptr<GeomAPI_Ellipse2d> anEllipseForArc(
+        new GeomAPI_Ellipse2d(aCenter2d, aMajorDir2d, aMajorRadius, aMinorRadius));
+    GeomPnt2dPtr anEnd = aEndPointAttr->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aProjection = anEllipseForArc->project(anEnd);
+    double aParamStart = 0.0, aParamEnd = 0.0;
+    if (aProjection && anEnd->distance(aProjection) <= tolerance &&
+        anEllipseForArc->parameter(anEnd, paramTolerance, aParamEnd)) {
+      // do not recalculate REVERSED flag if the arc is not consistent
+      anEllipseForArc->parameter(aStart2d, paramTolerance, aParamStart);
+      aParamEnd -= aParamStart;
+
+      if (myParamDelta >= 0.0 && myParamDelta <= PI * 0.5 &&
+          aParamEnd < 0.0 && aParamEnd >= -PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(true);
+      }
+      else if (myParamDelta <= 0.0 && myParamDelta >= -PI * 0.5 &&
+               aParamEnd > 0.0 && aParamEnd <= PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(false);
+      }
+      myParamDelta = aParamEnd;
+    }
+  }
+  data()->blockSendAttributeUpdated(aWasBlocked, false);
+
+  return true;
+}
+
+void SketchPlugin_EllipticArc::createEllipticArc(SketchPlugin_Sketch* theSketch)
+{
+  // Compute a ellipse in 3D view.
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+
+  double aMajorRadius = real(MAJOR_RADIUS_ID())->value();
+  double aMinorRadius = real(MINOR_RADIUS_ID())->value();
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+    theSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+
+  GeomPointPtr aCenter(theSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
+  GeomPointPtr aFocus(theSketch->to3D(aFocusAttr->x(), aFocusAttr->y()));
+  GeomDirPtr aNormal = aNDir->dir();
+  std::shared_ptr<GeomAPI_Shape> anEllipseShape;
+  if (aFocus->distance(aCenter) > tolerance) {
+    GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
+        aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
+
+    std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_POINT_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
+
+    GeomPointPtr aStartPnt(theSketch->to3D(aStartAttr->x(), aStartAttr->y()));
+    GeomPointPtr aEndPnt(theSketch->to3D(aEndAttr->x(), aEndAttr->y()));
+    if (boolean(REVERSED_ID())->value())
+      std::swap(aStartPnt, aEndPnt);
+
+    anEllipseShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxis,
+        aMajorRadius, aMinorRadius, aStartPnt, aEndPnt);
+  }
+  else {
+    // build circle instead of ellipse
+    anEllipseShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aMajorRadius);
+  }
+
+  ResultConstructionPtr aResult = document()->createConstruction(data());
+  aResult->setShape(anEllipseShape);
+  aResult->setIsInHistory(false);
+  setResult(aResult);
+}
diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.h b/src/SketchPlugin/SketchPlugin_EllipticArc.h
new file mode 100644 (file)
index 0000000..f3730d1
--- /dev/null
@@ -0,0 +1,152 @@
+// Copyright (C) 2017-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SketchPlugin_EllipticArc_H_
+#define SketchPlugin_EllipticArc_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_EllipticArc
+ * \ingroup Plugins
+ * \brief Feature for creation of the new elliptic arc in Sketch.
+ */
+class SketchPlugin_EllipticArc: public SketchPlugin_SketchEntity
+{
+ public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchEllipticArc");
+    return ID;
+  }
+
+  /// 2D point - center of the ellipse
+  inline static const std::string& CENTER_ID()
+  {
+    static const std::string ID("ellipse_center");
+    return ID;
+  }
+
+  /// 2D point - start point of elliptic arc
+  inline static const std::string& START_POINT_ID()
+  {
+    static const std::string ID("start_point");
+    return ID;
+  }
+  /// 2D point - end point of elliptic arc
+  inline static const std::string& END_POINT_ID()
+  {
+    static const std::string ID("end_point");
+    return ID;
+  }
+
+  /// 2D point - focus of the ellipse
+  inline static const std::string& FIRST_FOCUS_ID()
+  {
+    static const std::string ID("ellipse_first_focus");
+    return ID;
+  }
+  /// 2D point - second focus of the ellipse
+  inline static const std::string& SECOND_FOCUS_ID()
+  {
+    static const std::string ID("ellipse_second_focus");
+    return ID;
+  }
+
+  /// 2D point - start point of major axis
+  inline static const std::string& MAJOR_AXIS_START_ID()
+  {
+    static const std::string ID("ellipse_major_axis_start_point");
+    return ID;
+  }
+  /// 2D point - end point of major axis
+  inline static const std::string& MAJOR_AXIS_END_ID()
+  {
+    static const std::string ID("ellipse_major_axis_end_point");
+    return ID;
+  }
+
+  /// 2D point - start point of minor axis
+  inline static const std::string& MINOR_AXIS_START_ID()
+  {
+    static const std::string ID("ellipse_minor_axis_start_point");
+    return ID;
+  }
+  /// 2D point - end point of minor axis
+  inline static const std::string& MINOR_AXIS_END_ID()
+  {
+    static const std::string ID("ellipse_minor_axis_end_point");
+    return ID;
+  }
+
+  /// Major radius of the ellipse
+  inline static const std::string& MAJOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_major_radius");
+    return ID;
+  }
+
+  /// Minor radius of the ellipse
+  inline static const std::string& MINOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_minor_radius");
+    return ID;
+  }
+
+  /// Flag the arc is reversed
+  inline static const std::string& REVERSED_ID()
+  {
+    static const std::string ID("reversed");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_EllipticArc::ID();
+    return MY_KIND;
+  }
+
+  /// Returns true is sketch element is under the rigid constraint
+  SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Use plugin manager for features creation
+  SketchPlugin_EllipticArc();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+
+private:
+  bool fillCharacteristicPoints();
+
+  void createEllipticArc(SketchPlugin_Sketch* theSketch);
+
+private:
+  double myParamDelta;
+};
+
+#endif
index f68bf346b45bf124b9c24b11e00a60a9c26a675d..e5284719311c0f2beed9b62948160717992e536f 100644 (file)
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
 
-#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Edge.h>
 #include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt.h>
 #include <GeomAPI_Pnt2d.h>
 
-#include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomDataAPI_Point2D.h>
 
 SketchPlugin_Line::SketchPlugin_Line()
@@ -47,6 +47,9 @@ void SketchPlugin_Line::initAttributes()
   /// new attributes should be added to end of the feature in order to provide
   /// correct attribute values in previous saved studies
   data()->addAttribute(LENGTH_ID(), ModelAPI_AttributeDouble::typeId());
+
+  data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID());
 }
 
 void SketchPlugin_Line::initDerivedClassAttributes()
@@ -68,18 +71,7 @@ void SketchPlugin_Line::execute()
     std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
         GeomDataAPI_Point2D>(data()->attribute(END_ID()));
     if (aStartAttr->isInitialized() && anEndAttr->isInitialized()) {
-      std::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
-      std::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
-      //std::cout<<"Execute line "<<aStart->x()<<" "<<aStart->y()<<" "<<aStart->z()<<" - "
-      //  <<anEnd->x()<<" "<<anEnd->y()<<" "<<anEnd->z()<<std::endl;
-      // make linear edge
-      std::shared_ptr<GeomAPI_Edge> anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd);
-      // store the result
-      std::shared_ptr<ModelAPI_ResultConstruction> aConstr = document()->createConstruction(
-          data());
-      aConstr->setShape(anEdge);
-      aConstr->setIsInHistory(false);
-      setResult(aConstr);
+      SketchPlugin_Sketch::createLine2DResult(this, aSketch, START_ID(), END_ID());
 
       static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
       std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage = std::shared_ptr
index 7a23944ae6260d0ab8714a83579e07ea033e931a..73ad4310799662ccbf1bee3177ee8a018e7a3fb9 100644 (file)
@@ -63,6 +63,13 @@ class SketchPlugin_Line : public SketchPlugin_SketchEntity,
     return MY_LENGTH;
   }
 
+  /// Reference to the parent feature
+  inline static const std::string& PARENT_ID()
+  {
+    static const std::string& MY_PARENT_ID("ParentFeature");
+    return MY_PARENT_ID;
+  }
+
   /// Returns the kind of a feature
   SKETCHPLUGIN_EXPORT virtual const std::string& getKind();
 
index 3e6327e08ef04fc5a9bc844f1018048a0014266d..f0379c4618eac92385f15b151b3f1eaedd048e20 100644 (file)
@@ -20,6 +20,7 @@
 #include "SketchPlugin_MacroArc.h"
 
 #include "SketchPlugin_Arc.h"
+#include "SketchPlugin_ConstraintPerpendicular.h"
 #include "SketchPlugin_ConstraintTangent.h"
 #include "SketchPlugin_Sketch.h"
 #include "SketchPlugin_Tools.h"
@@ -209,7 +210,9 @@ void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
   else if(anArcType == ARC_TYPE_BY_THREE_POINTS())
     fillByThreePassedPoints();
   else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE())
-    fillByTangentEdge();
+    fillByEdge(false);
+  else if (anArcType == ARC_TYPE_BY_TRANSVERSAL_LINE())
+    fillByEdge(true);
 
   double aRadius = 0;
   double anAngle = 0;
@@ -339,19 +342,27 @@ void SketchPlugin_MacroArc::execute()
                                          AttributePtr(),
                                          anArcFeature->lastResult(),
                                          true);
-  } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
-    // constraints for tangent arc
+  } else {
+    // coincident with connection point
     SketchPlugin_Tools::createCoincidenceOrTangency(this,
                                          TANGENT_POINT_ID(),
                                          anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
                                          ObjectPtr(),
                                          false);
-    FeaturePtr aTangent = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
-    AttributeRefAttrPtr aRefAttrA = aTangent->refattr(SketchPlugin_Constraint::ENTITY_A());
+    // tangent or perpendicular constraint
+    FeaturePtr aStartPointConstraint;
+    if (anArcType == ARC_TYPE_BY_TANGENT_EDGE())
+      aStartPointConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+    else
+      aStartPointConstraint = sketch()->addFeature(SketchPlugin_ConstraintPerpendicular::ID());
+    // setting attributes of the start point constraint
+    AttributeRefAttrPtr aRefAttrA =
+        aStartPointConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
     AttributeRefAttrPtr aTgPntRefAttr = refattr(TANGENT_POINT_ID());
     FeaturePtr aTgFeature = ModelAPI_Feature::feature(aTgPntRefAttr->attr()->owner());
     aRefAttrA->setObject(aTgFeature->lastResult());
-    AttributeRefAttrPtr aRefAttrB = aTangent->refattr(SketchPlugin_Constraint::ENTITY_B());
+    AttributeRefAttrPtr aRefAttrB =
+        aStartPointConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
     aRefAttrB->setObject(anArcFeature->lastResult());
     // constraint for end point
     SketchPlugin_Tools::createCoincidenceOrTangency(this,
@@ -596,15 +607,15 @@ void SketchPlugin_MacroArc::recalculateReversedFlagByPassed(
   myParamBefore = aEndParam;
 }
 
-void SketchPlugin_MacroArc::fillByTangentEdge()
+void SketchPlugin_MacroArc::fillByEdge(bool theTransversal)
 {
   AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
   if (!aTangentAttr->isInitialized())
     return;
 
-  AttributePoint2DPtr aTangentPointAttr =
+  AttributePoint2DPtr aConnectionPointAttr =
       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
-  if (!aTangentPointAttr->isInitialized())
+  if (!aConnectionPointAttr->isInitialized())
     return;
 
   AttributePoint2DPtr anEndPointAttr =
@@ -612,19 +623,22 @@ void SketchPlugin_MacroArc::fillByTangentEdge()
   if (!anEndPointAttr->isInitialized())
     return;
 
-  myStart = aTangentPointAttr->pnt();
+  myStart = aConnectionPointAttr->pnt();
   myEnd = anEndPointAttr->pnt();
   if (myStart->isEqual(myEnd))
     return;
 
   // obtain a shape the tangent point belongs to
-  FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
-  std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
+  FeaturePtr aConnectedFeature = ModelAPI_Feature::feature(aConnectionPointAttr->owner());
+  std::shared_ptr<GeomAPI_Shape> aTangentShape = aConnectedFeature->lastResult()->shape();
 
   GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
   aCircBuilder.addPassingPoint(myStart);
   aCircBuilder.addPassingPoint(myEnd);
-  aCircBuilder.addTangentCurve(aTangentShape);
+  if (theTransversal)
+    aCircBuilder.setTransversalLine(aTangentShape);
+  else
+    aCircBuilder.addTangentCurve(aTangentShape);
 
   std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
   if (!aCircle)
index 815cd7002fce88c7d4f6f47a28a48734396b6983..886f6efdcb91b8de25eb0e88f30d254c6ddf47c5 100644 (file)
@@ -72,6 +72,12 @@ class SketchPlugin_MacroArc: public SketchPlugin_SketchEntity,
     return ID;
   }
 
+  inline static const std::string& ARC_TYPE_BY_TRANSVERSAL_LINE()
+  {
+    static const std::string ID("by_transversal_line");
+    return ID;
+  }
+
   /// Central 2D point of the circle which contains the arc
   inline static const std::string& CENTER_POINT_ID()
   {
@@ -220,8 +226,9 @@ private:
   void fillByCenterAndTwoPassed();
   /// Set fields for center, start and end points by selected passed points
   void fillByThreePassedPoints();
-  /// Set fields for center, start and end points by selected tangent edge
-  void fillByTangentEdge();
+  /// Set fields for center, start and end points by selected tangent or transversal edge
+  /// \param theTransversal if \c true, builds transversal arc, otherwise builds tangential arc.
+  void fillByEdge(bool theTransversal);
 
   FeaturePtr createArcFeature();
 
index 5bc378e9a05ad01eaaf240eb5ce292bda2adfe3a..e1e79e3aedac61736e6a65b37a920ec6cba00d3e 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-// File:        SketchPlugin_MacroEllipse.cpp
-// Created:     26 April 2017
-// Author:      Artem ZHIDKOV
-
 #include <SketchPlugin_MacroEllipse.h>
 
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_MacroArcReentrantMessage.h>
+#include <SketchPlugin_Point.h>
 #include <SketchPlugin_Tools.h>
 #include <SketchPlugin_Sketch.h>
 
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Events.h>
@@ -37,7 +37,6 @@
 #include <GeomDataAPI_Point2D.h>
 
 #include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Ellipse2d.h>
 #include <GeomAPI_Vertex.h>
 
@@ -55,6 +54,9 @@ SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse()
 
 void SketchPlugin_MacroEllipse::initAttributes()
 {
+  data()->addAttribute(ELLIPSE_TYPE(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(EDIT_ELLIPSE_TYPE(), ModelAPI_AttributeString::typeId());
+
   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId());
@@ -62,24 +64,47 @@ void SketchPlugin_MacroEllipse::initAttributes()
   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
 
+  data()->addAttribute(MAJOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_START_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(MAJOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_END_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(PASSED_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(PASSED_POINT_1_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+
   data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
 
+  string(EDIT_ELLIPSE_TYPE())->setValue("");
+
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
-  ModelAPI_Session::get()->validators()->
-      registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(
+      getKind(), MAJOR_AXIS_POINT_REF_ID());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(
+      getKind(), MAJOR_AXIS_START_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_END_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_1_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_ELLIPSE_TYPE());
 }
 
 void SketchPlugin_MacroEllipse::execute()
 {
   FeaturePtr anEllipse = createEllipseFeature();
-  constraintsForEllipse(anEllipse);
+
+  std::string aType = string(ELLIPSE_TYPE())->value();
+  if (aType == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT())
+    constraintsForEllipseByCenterAxisAndPassed(anEllipse);
+  else if (aType == ELLIPSE_TYPE_BY_AXIS_AND_POINT())
+    constraintsForEllipseByMajoxAxisAndPassed(anEllipse);
 
   // message to init reentrant operation
-  static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
-  ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+  static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
+  std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
+    <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
+
+  std::string anEditType = string(EDIT_ELLIPSE_TYPE())->value();
+  aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
   aMessage->setCreatedFeature(anEllipse);
   Events_Loop::loop()->send(aMessage);
 }
@@ -87,72 +112,109 @@ void SketchPlugin_MacroEllipse::execute()
 void SketchPlugin_MacroEllipse::attributeChanged(const std::string& theID)
 {
   static const int NB_POINTS = 3;
-  std::string aPointAttrName[NB_POINTS] = { CENTER_POINT_ID(),
-                                            MAJOR_AXIS_POINT_ID(),
-                                            PASSED_POINT_ID() };
-  std::string aPointRefName[NB_POINTS] = { CENTER_POINT_REF_ID(),
-                                           MAJOR_AXIS_POINT_REF_ID(),
-                                           PASSED_POINT_REF_ID() };
-
-  int aNbInitialized = 0;
-  std::shared_ptr<GeomAPI_Pnt2d> anEllipsePoints[NB_POINTS];
-
-  for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
-    AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
-    if (!aPointAttr->isInitialized())
-      continue;
-
-    AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
-    // calculate ellipse parameters
-    std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
-    std::shared_ptr<GeomAPI_Shape> aTangentCurve;
-    SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
-        aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
+  std::string aPointAttrName[NB_POINTS];
+  std::string aPointRefName[NB_POINTS];
+  if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT()) {
+    aPointAttrName[0] = CENTER_POINT_ID();
+    aPointAttrName[1] = MAJOR_AXIS_POINT_ID();
+    aPointAttrName[2] = PASSED_POINT_ID();
+    aPointRefName[0] = CENTER_POINT_REF_ID();
+    aPointRefName[1] = MAJOR_AXIS_POINT_REF_ID();
+    aPointRefName[2] = PASSED_POINT_REF_ID();
+  } else if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) {
+    aPointAttrName[0] = MAJOR_AXIS_START_ID();
+    aPointAttrName[1] = MAJOR_AXIS_END_ID();
+    aPointAttrName[2] = PASSED_POINT_1_ID();
+    aPointRefName[0] = MAJOR_AXIS_START_REF_ID();
+    aPointRefName[1] = MAJOR_AXIS_END_REF_ID();
+    aPointRefName[2] = PASSED_POINT_1_REF_ID();
+  }
+  else
+    return;
 
-    anEllipsePoints[aNbInitialized++] = aPassedPoint;
+  // type of ellipse switched, thus reset all attributes
+  if (theID == ELLIPSE_TYPE()) {
+    for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
+      SketchPlugin_Tools::resetAttribute(this, aPointAttrName[aPntIndex]);
+      SketchPlugin_Tools::resetAttribute(this, aPointRefName[aPntIndex]);
+    }
   }
+  else {
+    int aNbInitialized = 0;
+    GeomPnt2dPtr anEllipsePoints[NB_POINTS];
+
+    for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
+      AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
+      if (!aPointAttr->isInitialized())
+        continue;
+
+      AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
+      // calculate ellipse parameters
+      GeomPnt2dPtr aPassedPoint =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr)->pnt();
+      GeomShapePtr aTangentCurve;
+      SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+        aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
+
+      anEllipsePoints[aNbInitialized++] = aPassedPoint;
+    }
 
-  std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
-  if (aNbInitialized == 2) {
-    std::shared_ptr<GeomAPI_Dir2d> aXDir(new GeomAPI_Dir2d(
-        anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
-        anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
-    double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
-    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
-        new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
-  } else if (aNbInitialized == 3) {
-    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+    if (aNbInitialized <= 1)
+      return; // too few points for the ellipse
+
+    if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) {
+      // ellipse is given by major axis and passing point,
+      // recalculate the first point to be a center
+      anEllipsePoints[0]->setX(0.5 * (anEllipsePoints[0]->x() + anEllipsePoints[1]->x()));
+      anEllipsePoints[0]->setY(0.5 * (anEllipsePoints[0]->y() + anEllipsePoints[1]->y()));
+    }
+
+    std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
+    if (aNbInitialized == 2) {
+      GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
+                                           anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
+      double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
+      anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+          new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
+    }
+    else if (aNbInitialized == 3) {
+      anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
         new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
-  }
+    }
 
-  if (!anEllipse || anEllipse->implPtr<void>() == 0)
-    return;
+    if (!anEllipse || anEllipse->implPtr<void>() == 0)
+      return;
 
-  myCenter = anEllipse->center();
-  myFocus = anEllipse->firstFocus();
-  myMajorRadius = anEllipse->majorRadius();
-  myMinorRadius = anEllipse->minorRadius();
+    myCenter = anEllipse->center();
+    myFocus = anEllipse->firstFocus();
+    myMajorRadius = anEllipse->majorRadius();
+    myMinorRadius = anEllipse->minorRadius();
 
-  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
-  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
+    AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
+    AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
 
-  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
-  // center attribute is used in processEvent() to set reference to reentrant arc
-  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))->setValue(myCenter);
-  aMajorRadiusAttr->setValue(myMajorRadius);
-  aMinorRadiusAttr->setValue(myMinorRadius);
-  data()->blockSendAttributeUpdated(aWasBlocked, false);
+    bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+    aMajorRadiusAttr->setValue(myMajorRadius);
+    aMinorRadiusAttr->setValue(myMinorRadius);
+    data()->blockSendAttributeUpdated(aWasBlocked, false);
+  }
 }
 
+// LCOV_EXCL_START
 std::string SketchPlugin_MacroEllipse::processEvent(
                                               const std::shared_ptr<Events_Message>& theMessage)
 {
   std::string aFilledAttributeName;
 
-  ReentrantMessagePtr aReentrantMessage =
-        std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+  std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
+      std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
   if (aReentrantMessage) {
     FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+    std::string anEllipseType = aReentrantMessage->typeOfCreation();
+
+    string(ELLIPSE_TYPE())->setValue(anEllipseType);
+
+    aFilledAttributeName = ELLIPSE_TYPE();
     ObjectPtr anObject = aReentrantMessage->selectedObject();
     AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
@@ -160,6 +222,10 @@ std::string SketchPlugin_MacroEllipse::processEvent(
     if (aClickedPoint && (anObject || anAttribute)) {
       aFilledAttributeName = CENTER_POINT_ID();
       std::string aReferenceAttributeName = CENTER_POINT_REF_ID();
+      if (anEllipseType == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) {
+        aFilledAttributeName = MAJOR_AXIS_START_ID();
+        aReferenceAttributeName = MAJOR_AXIS_START_REF_ID();
+      }
 
       // fill 2d point attribute
       AttributePoint2DPtr aPointAttr =
@@ -172,36 +238,69 @@ std::string SketchPlugin_MacroEllipse::processEvent(
       if (anAttribute) {
         if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
           if (aCreatedFeature && anAttribute->id() == CENTER_POINT_ID())
-            anAttribute = aCreatedFeature->attribute(SketchPlugin_Ellipse::CENTER_ID());
+            anAttribute = aCreatedFeature->attribute(
+                anEllipseType == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT() ?
+                SketchPlugin_Ellipse::CENTER_ID() :
+                SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
         }
         aRefAttr->setAttr(anAttribute);
       }
       else if (anObject.get()) {
-        // if presentation of previous reentrant macro arc is used, the object is invalid,
-        // we should use result of previous feature of the message(Arc)
-        if (!anObject->data()->isValid())
-          anObject = aCreatedFeature->lastResult();
-        aRefAttr->setObject(anObject);
+        // if attribute is NULL, only object is defined, it should be processed outside
+        // the feature because it might be an external feature, that will be
+        // removed/created again after restart operation
+        // #2468 - Crash when sketching circles successively on a repetition
+        aFilledAttributeName = ELLIPSE_TYPE();
       }
     }
     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
   }
   return aFilledAttributeName;
 }
+// LCOV_EXCL_STOP
 
-void SketchPlugin_MacroEllipse::constraintsForEllipse(FeaturePtr theEllipseFeature)
+void SketchPlugin_MacroEllipse::constraintsForEllipseByCenterAxisAndPassed(
+    FeaturePtr theEllipseFeature)
 {
+  // tangency on-the-fly is not applicable for ellipses
+  static const bool isTangencyApplicable = false;
   // Create constraints.
   SketchPlugin_Tools::createCoincidenceOrTangency(
       this, CENTER_POINT_REF_ID(),
       theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
-      ObjectPtr(), false);
+      ObjectPtr(), isTangencyApplicable);
+  SketchPlugin_Tools::createCoincidenceOrTangency(
+      this, MAJOR_AXIS_POINT_REF_ID(),
+      theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+      ObjectPtr(), isTangencyApplicable);
+  // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
+  if (!refattr(PASSED_POINT_REF_ID())->isObject()) {
+    SketchPlugin_Tools::createCoincidenceOrTangency(
+        this, PASSED_POINT_REF_ID(), AttributePtr(),
+        theEllipseFeature->lastResult(), isTangencyApplicable);
+  }
+}
+
+void SketchPlugin_MacroEllipse::constraintsForEllipseByMajoxAxisAndPassed(
+    FeaturePtr theEllipseFeature)
+{
+  // tangency on-the-fly is not applicable for ellipses
+  static const bool isTangencyApplicable = false;
+  // Create constraints.
   SketchPlugin_Tools::createCoincidenceOrTangency(
-      this, MAJOR_AXIS_POINT_REF_ID(), AttributePtr(),
-      theEllipseFeature->lastResult(), true);
+      this, MAJOR_AXIS_START_REF_ID(),
+      theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
+      ObjectPtr(), isTangencyApplicable);
   SketchPlugin_Tools::createCoincidenceOrTangency(
-      this, PASSED_POINT_REF_ID(), AttributePtr(),
-      theEllipseFeature->lastResult(), true);
+      this, MAJOR_AXIS_END_REF_ID(),
+      theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+      ObjectPtr(), isTangencyApplicable);
+  // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
+  if (!refattr(PASSED_POINT_1_REF_ID())->isObject()) {
+    SketchPlugin_Tools::createCoincidenceOrTangency(
+        this, PASSED_POINT_1_REF_ID(), AttributePtr(),
+        theEllipseFeature->lastResult(), isTangencyApplicable);
+  }
 }
 
 FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
@@ -213,7 +312,7 @@ FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
   aCenterAttr->setValue(myCenter->x(), myCenter->y());
 
   AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aEllipseFeature->attribute(SketchPlugin_Ellipse::FOCUS_ID()));
+      aEllipseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
   aFocusAttr->setValue(myFocus->x(), myFocus->y());
 
   aEllipseFeature->real(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
@@ -223,6 +322,30 @@ FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
       boolean(AUXILIARY_ID())->value());
 
   aEllipseFeature->execute();
+
+  // create auxiliary points
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
+  // create auxiliary axes
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
+                      SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
+                      SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
+                      SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
+                      SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
+
   return aEllipseFeature;
 }
 
@@ -236,10 +359,10 @@ AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
       aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
 
   // Compute a ellipse in 3D view.
-  std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
-  std::shared_ptr<GeomAPI_Pnt> aFocus(aSketch->to3D(myFocus->x(), myFocus->y()));
-  std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
-  std::shared_ptr<GeomAPI_Dir> aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
+  GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  GeomPointPtr aFocus(aSketch->to3D(myFocus->x(), myFocus->y()));
+  GeomDirPtr aNormal = aNDir->dir();
+  GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
       aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
 
   std::shared_ptr<GeomAPI_Shape> anEllipseShape =
index 8d374df5c8dbc59c5f057052fac8b2a194ccfc8e..f1a87525757a5f4c5f973c6a88f85fc801ef56c7 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-// File:        SketchPlugin_MacroEllipse.h
-// Created:     26 April 2017
-// Author:      Artem ZHIDKOV
-
 #ifndef SketchPlugin_MacroEllipse_H_
 #define SketchPlugin_MacroEllipse_H_
 
@@ -29,7 +25,6 @@
 #include <SketchPlugin_SketchEntity.h>
 #include <GeomAPI_IPresentable.h>
 
-////class GeomAPI_Circ2d;
 class GeomAPI_Pnt2d;
 
 /**\class SketchPlugin_MacroEllipse
@@ -48,35 +43,58 @@ class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity,
     return ID;
   }
 
-  /// 2D point - center of the ellipse.
+  static const std::string& ELLIPSE_TYPE()
+  {
+    static const std::string ID("ellipse_type");
+    return ID;
+  }
+
+  static const std::string& ELLIPSE_TYPE_BY_CENTER_AXIS_POINT()
+  {
+    static const std::string ID("by_center_axis_point");
+    return ID;
+  }
+  static const std::string& ELLIPSE_TYPE_BY_AXIS_AND_POINT()
+  {
+    static const std::string ID("by_major_axis_and_point");
+    return ID;
+  }
+
+  static const std::string& EDIT_ELLIPSE_TYPE()
+  {
+    static const std::string ID("edit_ellipse_type");
+    return ID;
+  }
+
+  /// Attribute for the first point selected during ellipse creation.
   inline static const std::string& CENTER_POINT_ID()
   {
-    static const std::string ID("center_point");
+    static const std::string ID("first_point");
     return ID;
   }
 
-  /// Reference for center point selection.
+  /// Reference to the first selected point.
   inline static const std::string& CENTER_POINT_REF_ID()
   {
-    static const std::string ID("center_point_ref");
+    static const std::string ID("first_point_ref");
     return ID;
   }
 
-  /// 2D point - major axis point of the ellipse.
+  /// Attribute for the second point selected during ellipse creation.
   inline static const std::string& MAJOR_AXIS_POINT_ID()
   {
-    static const std::string ID("major_axis_point");
+    static const std::string ID("second_point");
     return ID;
   }
 
-  /// Reference for major axis point selection.
+  /// Reference to the second selected point.
   inline static const std::string& MAJOR_AXIS_POINT_REF_ID()
   {
-    static const std::string ID("major_axis_point_ref");
+    static const std::string ID("second_point_ref");
     return ID;
   }
 
-  /// 2D point - passed point of the ellipse
+  /// Attribute for the third point selected during ellipse creation.
   inline static const std::string& PASSED_POINT_ID()
   {
     static const std::string ID("passed_point");
@@ -90,17 +108,59 @@ class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity,
     return ID;
   }
 
+  /// Attribute for the first point selected during ellipse creation.
+  inline static const std::string& MAJOR_AXIS_START_ID()
+  {
+    static const std::string ID("first_point_1");
+    return ID;
+  }
+
+  /// Reference to the first selected point.
+  inline static const std::string& MAJOR_AXIS_START_REF_ID()
+  {
+    static const std::string ID("first_point_ref_1");
+    return ID;
+  }
+
+  /// Attribute for the second point selected during ellipse creation.
+  inline static const std::string& MAJOR_AXIS_END_ID()
+  {
+    static const std::string ID("second_point_1");
+    return ID;
+  }
+
+  /// Reference to the second selected point.
+  inline static const std::string& MAJOR_AXIS_END_REF_ID()
+  {
+    static const std::string ID("second_point_ref_1");
+    return ID;
+  }
+
+  /// Attribute for the third point selected during ellipse creation.
+  inline static const std::string& PASSED_POINT_1_ID()
+  {
+    static const std::string ID("passed_point_1");
+    return ID;
+  }
+
+  /// Reference for passed point selection.
+  inline static const std::string& PASSED_POINT_1_REF_ID()
+  {
+    static const std::string ID("passed_point_ref_1");
+    return ID;
+  }
+
   /// Major radius of the ellipse
   inline static const std::string& MAJOR_RADIUS_ID()
   {
-    static const std::string ID("ellipse_major_radius");
+    static const std::string ID("major_radius");
     return ID;
   }
 
   /// Minor radius of the ellipse
   inline static const std::string& MINOR_RADIUS_ID()
   {
-    static const std::string ID("ellipse_minor_radius");
+    static const std::string ID("minor_radius");
     return ID;
   }
 
@@ -139,7 +199,8 @@ class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity,
   SketchPlugin_MacroEllipse();
 
 private:
-  void constraintsForEllipse(FeaturePtr theEllipseFeature);
+  void constraintsForEllipseByCenterAxisAndPassed(FeaturePtr theEllipseFeature);
+  void constraintsForEllipseByMajoxAxisAndPassed(FeaturePtr theEllipseFeature);
 
   FeaturePtr createEllipseFeature();
 
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp
new file mode 100644 (file)
index 0000000..984a759
--- /dev/null
@@ -0,0 +1,395 @@
+// Copyright (C) 2017-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <SketchPlugin_MacroEllipticArc.h>
+
+#include <SketchPlugin_EllipticArc.h>
+#include <SketchPlugin_MacroArcReentrantMessage.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Events.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Vertex.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+
+const double paramTolerance = 1.e-4;
+const double PI = 3.141592653589793238463;
+
+
+SketchPlugin_MacroEllipticArc::SketchPlugin_MacroEllipticArc()
+  : SketchPlugin_SketchEntity(),
+    myMajorRadius(0.0),
+    myMinorRadius(0.0),
+    myParamDelta(0.0)
+{
+}
+
+void SketchPlugin_MacroEllipticArc::initAttributes()
+{
+  data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(CENTER_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+
+  data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+  data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  boolean(REVERSED_ID())->setValue(false);
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_REF_ID());
+  ModelAPI_Session::get()->validators()
+      ->registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
+}
+
+void SketchPlugin_MacroEllipticArc::execute()
+{
+  FeaturePtr anEllipse = createEllipticArcFeature();
+  constraintsForEllipticArc(anEllipse);
+
+  // message to init reentrant operation
+  static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
+  std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
+    <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
+  aMessage->setCreatedFeature(anEllipse);
+  Events_Loop::loop()->send(aMessage);
+}
+
+void SketchPlugin_MacroEllipticArc::attributeChanged(const std::string& theID)
+{
+  static const int NB_POINTS = 4;
+  std::string aPointAttrName[NB_POINTS] = { CENTER_ID(),
+                                            MAJOR_AXIS_POINT_ID(),
+                                            START_POINT_ID(),
+                                            END_POINT_ID() };
+  std::string aPointRefName[NB_POINTS] = { CENTER_REF_ID(),
+                                           MAJOR_AXIS_POINT_REF_ID(),
+                                           START_POINT_REF_ID(),
+                                           END_POINT_REF_ID() };
+
+  int aNbInitialized = 0;
+  GeomPnt2dPtr anEllipsePoints[NB_POINTS];
+
+  for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
+    AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
+    if (!aPointAttr->isInitialized())
+      continue;
+
+    AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
+    // calculate ellipse parameters
+    GeomPnt2dPtr aPassedPoint =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr)->pnt();
+    GeomShapePtr aTangentCurve;
+    SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+      aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
+
+    anEllipsePoints[aNbInitialized++] = aPassedPoint;
+  }
+
+  if (aNbInitialized <= 1)
+    return; // too few points for the ellipse
+
+  myCenter    = anEllipsePoints[0];
+  myMajorAxis = anEllipsePoints[1];
+  myStartPnt  = anEllipsePoints[2];
+  myEndPnt    = anEllipsePoints[3];
+
+  std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
+  if (aNbInitialized == 2) {
+    GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
+                                         anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
+    double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
+    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+        new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
+  }
+  else if (aNbInitialized >= 3) {
+    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+      new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
+  }
+
+  if (!anEllipse || anEllipse->implPtr<void>() == 0)
+    return;
+
+  myMajorRadius = anEllipse->majorRadius();
+  myMinorRadius = anEllipse->minorRadius();
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+  real(MAJOR_RADIUS_ID())->setValue(myMajorRadius);
+  real(MINOR_RADIUS_ID())->setValue(myMinorRadius);
+  data()->blockSendAttributeUpdated(aWasBlocked, false);
+
+  // update the REVERSED flag
+  if (myEndPnt) {
+    double aParameterEnd = 0.0;
+    GeomPnt2dPtr aEnd = anEllipse->project(myEndPnt);
+    if (anEllipse->parameter(aEnd, paramTolerance, aParameterEnd)) {
+      double aParamStart = 0.0;
+      anEllipse->parameter(myStartPnt, paramTolerance, aParamStart);
+      aParameterEnd -= aParamStart;
+
+      if (myParamDelta > 0.0 && myParamDelta <= PI * 0.5 &&
+          aParameterEnd < 0 && aParameterEnd >= -PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(true);
+      }
+      else if (myParamDelta < 0.0 && myParamDelta >= -PI * 0.5 &&
+               aParameterEnd > 0.0 && aParameterEnd <= PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(false);
+      }
+    }
+    myParamDelta = aParameterEnd;
+  }
+}
+
+// LCOV_EXCL_START
+std::string SketchPlugin_MacroEllipticArc::processEvent(
+                                              const std::shared_ptr<Events_Message>& theMessage)
+{
+  std::string aFilledAttributeName;
+
+  std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
+      std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
+  if (aReentrantMessage) {
+    FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+
+    ObjectPtr anObject = aReentrantMessage->selectedObject();
+    AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+    std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+    if (aClickedPoint && (anObject || anAttribute)) {
+      aFilledAttributeName = CENTER_ID();
+      std::string aReferenceAttributeName = CENTER_REF_ID();
+
+      // fill 2d point attribute
+      AttributePoint2DPtr aPointAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(aFilledAttributeName));
+      aPointAttr->setValue(aClickedPoint);
+
+      // fill reference attribute
+      AttributeRefAttrPtr aRefAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(attribute(aReferenceAttributeName));
+      if (anAttribute) {
+        if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+          if (aCreatedFeature && anAttribute->id() == CENTER_ID())
+            anAttribute = aCreatedFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID());
+        }
+        aRefAttr->setAttr(anAttribute);
+      }
+      else if (anObject.get()) {
+        // if attribute is NULL, only object is defined, it should be processed outside
+        // the feature because it might be an external feature, that will be
+        // removed/created again after restart operation
+        // #2468 - Crash when sketching circles successively on a repetition
+        aFilledAttributeName = "";
+      }
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  }
+  return aFilledAttributeName;
+}
+// LCOV_EXCL_STOP
+
+FeaturePtr SketchPlugin_MacroEllipticArc::createEllipticArcFeature()
+{
+  GeomShapePtr anArc = getArcShape();
+  GeomEllipsePtr anEllipse;
+  GeomPointPtr aStartPoint, aEndPoint;
+  if (anArc->isEdge()) {
+    GeomEdgePtr anArcEdge = anArc->edge();
+    aStartPoint = anArcEdge->firstPoint();
+    aEndPoint = anArcEdge->lastPoint();
+    if (boolean(REVERSED_ID())->value())
+      std::swap(aStartPoint, aEndPoint);
+
+    if (anArcEdge->isEllipse())
+      anEllipse = anArcEdge->ellipse();
+  }
+
+  if (!anEllipse)
+    return FeaturePtr();
+
+  // Create and fill new EllipticArc feature
+  SketchPlugin_Sketch* aSketch = sketch();
+  FeaturePtr aEllipseFeature = aSketch->addFeature(SketchPlugin_EllipticArc::ID());
+
+  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+  aCenterAttr->setValue(aSketch->to2D(anEllipse->center()));
+
+  AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
+  aFocusAttr->setValue(aSketch->to2D(anEllipse->firstFocus()));
+
+  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+  aStartAttr->setValue(aSketch->to2D(aStartPoint));
+
+  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+  aEndAttr->setValue(aSketch->to2D(aEndPoint));
+
+  aEllipseFeature->real(SketchPlugin_EllipticArc::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
+  aEllipseFeature->real(SketchPlugin_EllipticArc::MINOR_RADIUS_ID())->setValue(myMinorRadius);
+
+  aEllipseFeature->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(
+      boolean(REVERSED_ID())->value());
+
+  aEllipseFeature->boolean(SketchPlugin_EllipticArc::AUXILIARY_ID())->setValue(
+      boolean(AUXILIARY_ID())->value());
+
+  aEllipseFeature->execute();
+
+  // create auxiliary points
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::CENTER_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::FIRST_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::SECOND_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MINOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MINOR_AXIS_END_ID());
+  // create auxiliary axes
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
+                      SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(),
+                      SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
+                      SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(),
+                      SketchPlugin_EllipticArc::MINOR_AXIS_END_ID());
+
+  return aEllipseFeature;
+}
+
+void SketchPlugin_MacroEllipticArc::constraintsForEllipticArc(FeaturePtr theEllipticArc)
+{
+  // tangency on-the-fly is not applicable for elliptic arcs
+  static const bool isTangencyApplicable = false;
+  // Create constraints.
+  SketchPlugin_Tools::createCoincidenceOrTangency(
+      this, CENTER_REF_ID(),
+      theEllipticArc->attribute(SketchPlugin_EllipticArc::CENTER_ID()),
+      ObjectPtr(), isTangencyApplicable);
+  // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
+  if (!refattr(MAJOR_AXIS_POINT_REF_ID())->isObject()) {
+    SketchPlugin_Tools::createCoincidenceOrTangency(
+        this, MAJOR_AXIS_POINT_REF_ID(),
+        AttributePtr(),
+        theEllipticArc->lastResult(), isTangencyApplicable);
+  }
+  SketchPlugin_Tools::createCoincidenceOrTangency(
+      this, START_POINT_REF_ID(),
+      theEllipticArc->attribute(SketchPlugin_EllipticArc::START_POINT_ID()),
+      ObjectPtr(), isTangencyApplicable);
+  SketchPlugin_Tools::createCoincidenceOrTangency(
+      this, END_POINT_REF_ID(),
+      theEllipticArc->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+      ObjectPtr(), isTangencyApplicable);
+}
+
+AISObjectPtr SketchPlugin_MacroEllipticArc::getAISObject(AISObjectPtr thePrevious)
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch || !myCenter || !myMajorAxis)
+    return AISObjectPtr();
+
+  // Compute a elliptic arc in 3D view.
+  GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
+  GeomShapePtr anArcShape = getArcShape();
+  if (!anArcShape.get() || !aCenterPointShape.get())
+    return AISObjectPtr();
+
+  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
+  aShapes.push_back(anArcShape);
+  aShapes.push_back(aCenterPointShape);
+
+  std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+  AISObjectPtr anAIS = thePrevious;
+  if (!anAIS)
+    anAIS.reset(new GeomAPI_AISObject());
+  anAIS->createShape(aCompound);
+  return anAIS;
+}
+
+GeomShapePtr SketchPlugin_MacroEllipticArc::getArcShape()
+{
+  if (!myCenter.get() || !myMajorAxis.get())
+    return GeomShapePtr();
+
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch)
+    return GeomShapePtr();
+
+  GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  GeomPointPtr aMajorAxisPnt(aSketch->to3D(myMajorAxis->x(), myMajorAxis->y()));
+  GeomDirPtr aMajorAxisDir(new GeomAPI_Dir(aMajorAxisPnt->x() - aCenter->x(),
+                                           aMajorAxisPnt->y() - aCenter->y(),
+                                           aMajorAxisPnt->z() - aCenter->z()));
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      aSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+  GeomDirPtr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
+
+  GeomPointPtr aStart, anEnd;
+  if (myStartPnt)
+    aStart = aSketch->to3D(myStartPnt->x(), myStartPnt->y());
+  if (myEndPnt)
+    anEnd = aSketch->to3D(myEndPnt->x(), myEndPnt->y());
+
+  GeomShapePtr anArcShape;
+  if (anEnd) {
+    if (boolean(REVERSED_ID())->value())
+      std::swap(aStart, anEnd);
+
+    anArcShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxisDir,
+        myMajorRadius, myMinorRadius, aStart, anEnd);
+  }
+  else {
+    anArcShape = GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxisDir,
+        myMajorRadius, myMinorRadius);
+  }
+
+  return anArcShape;
+}
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h
new file mode 100644 (file)
index 0000000..296d431
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright (C) 2017-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SketchPlugin_MacroEllipticArc_H_
+#define SketchPlugin_MacroEllipticArc_H_
+
+#include <ModelAPI_IReentrant.h>
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Pnt2d;
+class GeomAPI_Shape;
+
+/**\class SketchPlugin_MacroEllipticArc
+ * \ingroup Plugins
+ * \brief Feature for creation of the new elliptic arc in Sketch.
+ */
+class SketchPlugin_MacroEllipticArc: public SketchPlugin_SketchEntity,
+                                     public GeomAPI_IPresentable,
+                                     public ModelAPI_IReentrant
+{
+public:
+  /// Elliptic arc feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchMacroEllipticArc");
+    return ID;
+  }
+
+  /// Attribute for the central point selected during elliptic arc creation.
+  inline static const std::string& CENTER_ID()
+  {
+    static const std::string ID("center");
+    return ID;
+  }
+
+  /// Reference to the first selected point (center of ellipse).
+  inline static const std::string& CENTER_REF_ID()
+  {
+    static const std::string ID("center_ref");
+    return ID;
+  }
+
+  /// Attribute for the point on major semi-axis selected during elliptic arc creation.
+  inline static const std::string& MAJOR_AXIS_POINT_ID()
+  {
+    static const std::string ID("major_axis_point");
+    return ID;
+  }
+
+  /// Reference to the second selected point (major semi-axis of the ellipse).
+  inline static const std::string& MAJOR_AXIS_POINT_REF_ID()
+  {
+    static const std::string ID("major_axis_point_ref");
+    return ID;
+  }
+
+  /// Attribute for the start point of the elliptic arc selected during creation.
+  inline static const std::string& START_POINT_ID()
+  {
+    static const std::string ID("start_point");
+    return ID;
+  }
+
+  /// Reference for the start point selection.
+  inline static const std::string& START_POINT_REF_ID()
+  {
+    static const std::string ID("start_point_ref");
+    return ID;
+  }
+
+  /// Attribute for the end point of the elliptic arc selected during creation.
+  inline static const std::string& END_POINT_ID()
+  {
+    static const std::string ID("end_point");
+    return ID;
+  }
+
+  /// Reference for the end point selection.
+  inline static const std::string& END_POINT_REF_ID()
+  {
+    static const std::string ID("end_point_ref");
+    return ID;
+  }
+
+  /// Major radius of the ellipse
+  inline static const std::string& MAJOR_RADIUS_ID()
+  {
+    static const std::string ID("major_radius");
+    return ID;
+  }
+
+  /// Minor radius of the ellipse
+  inline static const std::string& MINOR_RADIUS_ID()
+  {
+    static const std::string ID("minor_radius");
+    return ID;
+  }
+
+  /// Flag the arc is reversed
+  inline static const std::string& REVERSED_ID()
+  {
+    static const std::string ID("reversed");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_MacroEllipticArc::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes.
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Returns the AIS preview
+  virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const
+  {return true;}
+
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const
+  {return false;}
+
+  /// Apply information of the message to current object. It fills reference object,
+  /// tangent type and tangent point refence in case of tangent arc
+  virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_MacroEllipticArc();
+
+private:
+  std::shared_ptr<GeomAPI_Shape> getArcShape();
+
+  FeaturePtr createEllipticArcFeature();
+  void constraintsForEllipticArc(FeaturePtr theEllipticArc);
+
+private:
+  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+  std::shared_ptr<GeomAPI_Pnt2d> myMajorAxis;
+  std::shared_ptr<GeomAPI_Pnt2d> myStartPnt;
+  std::shared_ptr<GeomAPI_Pnt2d> myEndPnt;
+  double myMajorRadius;
+  double myMinorRadius;
+  double myParamDelta;
+};
+
+#endif
index c9a10a82b2801a132a3c2d12c82d2f3ed35d855c..d9e967e60a7e7f07a18eea5fba7f0de76e47a31d 100644 (file)
@@ -27,6 +27,7 @@
 #include <SketchPlugin_Projection.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintDistanceHorizontal.h>
@@ -53,6 +54,8 @@
 #include <SketchPlugin_ExternalValidator.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_MacroEllipse.h>
+#include <SketchPlugin_EllipticArc.h>
+#include <SketchPlugin_MacroEllipticArc.h>
 #include <SketchPlugin_SketchDrawer.h>
 
 #include <SketcherPrs_Tools.h>
@@ -95,6 +98,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_ExternalValidator);
   aFactory->registerValidator("SketchPlugin_TangentAttr",
                               new SketchPlugin_TangentAttrValidator);
+  aFactory->registerValidator("SketchPlugin_PerpendicularAttr",
+                              new SketchPlugin_PerpendicularAttrValidator);
   aFactory->registerValidator("SketchPlugin_NotFixed",
                               new SketchPlugin_NotFixedValidator);
   aFactory->registerValidator("SketchPlugin_EqualAttr",
@@ -117,6 +122,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_MiddlePointAttrValidator);
   aFactory->registerValidator("SketchPlugin_ArcTangentPoint",
                               new SketchPlugin_ArcTangentPointValidator);
+  aFactory->registerValidator("SketchPlugin_ArcTransversalPoint",
+                              new SketchPlugin_ArcTransversalPointValidator);
   aFactory->registerValidator("SketchPlugin_IntersectionValidator",
                               new SketchPlugin_IntersectionValidator);
   aFactory->registerValidator("SketchPlugin_ProjectionValidator",
@@ -194,6 +201,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_Projection);
   } else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintCoincidence);
+  } else if (theFeatureID == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+    return FeaturePtr(new SketchPlugin_ConstraintCoincidenceInternal);
   } else if (theFeatureID == SketchPlugin_ConstraintCollinear::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintCollinear);
   } else if (theFeatureID == SketchPlugin_ConstraintDistance::ID()) {
@@ -244,6 +253,10 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_Ellipse);
   } else if (theFeatureID == SketchPlugin_MacroEllipse::ID()) {
     return FeaturePtr(new SketchPlugin_MacroEllipse);
+  } else if (theFeatureID == SketchPlugin_EllipticArc::ID()) {
+    return FeaturePtr(new SketchPlugin_EllipticArc);
+  } else if (theFeatureID == SketchPlugin_MacroEllipticArc::ID()) {
+    return FeaturePtr(new SketchPlugin_MacroEllipticArc);
   } else if (theFeatureID == SketchPlugin_SketchDrawer::ID()) {
     return FeaturePtr(new SketchPlugin_SketchDrawer);
   }
@@ -290,8 +303,10 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCoincidence::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_ConstraintCoincidenceInternal::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCollinear::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistance::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintLength::ID(), aHasSketchPlane);
@@ -313,6 +328,8 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistanceHorizontal::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane);
       // SketchRectangle is a python feature, so its ID is passed just as a string
index c53006489726c728a5ac5c6877c996b4b90cc6dd..9a6358053132ae4e99bf59bebef0c80de454c46b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <ModelAPI_Data.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_AttributeReference.h>
 #include <ModelAPI_AttributeSelection.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
@@ -41,6 +42,9 @@ void SketchPlugin_Point::initDerivedClassAttributes()
   data()->addAttribute(SketchPlugin_Point::COORD_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+
+  data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID());
 }
 
 void SketchPlugin_Point::execute()
index 1cdcae05f39ddb505170bedc42e94cb4fe169a23..5111ce0a8922e0e8f47d5a373b89f054efbbfd48 100644 (file)
@@ -44,6 +44,12 @@ class SketchPlugin_Point : public SketchPlugin_SketchEntity
     static const std::string MY_COORD_ID("PointCoordinates");
     return MY_COORD_ID;
   }
+  /// Reference to the parent feature
+  inline static const std::string& PARENT_ID()
+  {
+    static const std::string& MY_PARENT_ID("ParentFeature");
+    return MY_PARENT_ID;
+  }
   /// Returns the kind of a feature
   SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
   {
index 0a1a1b96f1a5d1fe4baab9a5263991b28bbbe717..79eb675ca240ca273480dd8d6d4c92ed3b8f08d9 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 #include <SketchPlugin_Sketch.h>
 
 #include <GeomAPI_Circ.h>
 #include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Vertex.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_Projection.h>
 #include <GeomDataAPI_Point2D.h>
 
 #include <cmath>
@@ -101,21 +105,60 @@ void SketchPlugin_Projection::attributeChanged(const std::string& theID)
   }
 }
 
-static bool isValidProjectionType(FeaturePtr theProjection,
-                                  GeomEdgePtr theEdge,
-                                  GeomVertexPtr theVertex)
+static const std::set<std::string>& POINT_PROJECTION()
 {
-  if (theVertex && theProjection->getKind() == SketchPlugin_Point::ID())
-    return true;
+  static std::set<std::string> aProj;
+  if (aProj.empty())
+    aProj.insert(SketchPlugin_Point::ID());
+  return aProj;
+}
+
+static const std::set<std::string>& LINE_PROJECTION()
+{
+  static std::set<std::string> aProj;
+  if (aProj.empty())
+    aProj.insert(SketchPlugin_Line::ID());
+  return aProj;
+}
+
+static const std::set<std::string>& CIRCLE_ELLIPSE_PROJECTION()
+{
+  static std::set<std::string> aProj;
+  if (aProj.empty()) {
+    aProj.insert(SketchPlugin_Circle::ID());
+    aProj.insert(SketchPlugin_Ellipse::ID());
+  }
+  return aProj;
+}
+
+static const std::set<std::string>& ARC_PROJECTION()
+{
+  static std::set<std::string> aProj;
+  if (aProj.empty()) {
+    aProj.insert(SketchPlugin_Arc::ID());
+    aProj.insert(SketchPlugin_EllipticArc::ID());
+  }
+  return aProj;
+}
+
+
+static const std::set<std::string>& possibleProjectionTypes(GeomEdgePtr theEdge,
+                                                            GeomVertexPtr theVertex)
+{
+  if (theVertex)
+    return POINT_PROJECTION();
   if (theEdge) {
-    if (theEdge->isLine() && theProjection->getKind() == SketchPlugin_Line::ID())
-      return true;
-    else if (theEdge->isCircle() && theProjection->getKind() == SketchPlugin_Circle::ID())
-      return true;
-    else if (theEdge->isArc() && theProjection->getKind() == SketchPlugin_Arc::ID())
-      return true;
+    if (theEdge->isLine())
+      return LINE_PROJECTION();
+    else if (theEdge->isCircle() || theEdge->isArc() || theEdge->isEllipse()) {
+      if (theEdge->isClosed())
+        return CIRCLE_ELLIPSE_PROJECTION();
+      else
+        return ARC_PROJECTION();
+    }
   }
-  return false;
+  static const std::set<std::string> DUMMY;
+  return DUMMY;
 }
 
 void SketchPlugin_Projection::computeProjection(const std::string& theID)
@@ -139,30 +182,21 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
   if (!anEdge && !aVertex)
     return;
 
+  const std::set<std::string>& aProjType = possibleProjectionTypes(anEdge, aVertex);
+
   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
   FeaturePtr aProjection;
   if (aRefAttr && aRefAttr->isInitialized())
     aProjection = ModelAPI_Feature::feature(aRefAttr->object());
 
   // if the type of feature differs with already selected, remove it and create once again
-  bool hasPrevProj = aProjection.get() != 0;
-  if (hasPrevProj && !isValidProjectionType(aProjection, anEdge, aVertex)) {
-    DocumentPtr aDoc = sketch()->document();
-
-    aRefAttr->setObject(data()->owner()); // to not remove of this remove reference to aProjection
-    std::set<FeaturePtr> aFeaturesToBeRemoved;
-    aFeaturesToBeRemoved.insert(aProjection);
-    ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
-    aProjection = FeaturePtr();
-    aRefAttr->setObject(aProjection);
-    hasPrevProj = false;
-  }
+  bool isRebuild = rebuildProjectedFeature(aProjection, aProjType);
 
   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
 
   ResultConstructionPtr aResult =
       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
-  if (aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
+  if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
     aResult->setShape(std::shared_ptr<GeomAPI_Edge>());
     if (aProjection)
       aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
@@ -174,8 +208,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(aVertex->point());
     std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
 
-    if (!hasPrevProj)
-      aProjection = sketch()->addFeature(SketchPlugin_Point::ID());
+    rebuildProjectedFeature(aProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
 
     // update coordinates of projection
     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
@@ -190,8 +223,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     if (aFirstInSketch->distance(aLastInSketch) < tolerance)
       return; // line is semi-orthogonal to the sketch plane
 
-    if (!hasPrevProj)
-      aProjection = sketch()->addFeature(SketchPlugin_Line::ID());
+    rebuildProjectedFeature(aProjection, LINE_PROJECTION(), SketchPlugin_Line::ID());
 
     // update attributes of projection
     std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
@@ -201,64 +233,127 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     aStartPnt->setValue(aFirstInSketch);
     aEndPnt->setValue(aLastInSketch);
   }
-  else if (anEdge->isCircle()) {
-    std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
-    double aRadius = aCircle->radius();
-
-    double aNormalsDot = aCircle->normal()->dot(aSketchPlane->direction());
-    if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
-      return; // circle is not in the plane, parallel to the sketch plane
-
-    std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
-    std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
-
-    if (!hasPrevProj)
-      aProjection = sketch()->addFeature(SketchPlugin_Circle::ID());
-
-    // update attributes of projection
-    std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
-    aCenterPnt->setValue(aCenterInSketch);
-    aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aRadius);
-  }
-  else if (anEdge->isArc()) {
-    std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
-    std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
-    std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
-    std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
-
-    std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
-    std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
-    std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
-
-    double aNormalsDot = aCircle->normal()->dot(aSketchPlane->direction());
-    if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
-      return; // arc is not in the plane, parallel to the sketch plane
-
-    bool isInversed = aNormalsDot < 0.;
-
-    if (!hasPrevProj)
-      aProjection = sketch()->addFeature(SketchPlugin_Arc::ID());
-
-    bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true);
-
-    // update attributes of projection
-    std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
-    std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aProjection->attribute(SketchPlugin_Arc::START_ID()));
-    std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aProjection->attribute(SketchPlugin_Arc::END_ID()));
-    aStartPnt->setValue(aFirstInSketch);
-    aEndPnt->setValue(aLastInSketch);
-    aCenterPnt->setValue(aCenterInSketch);
-    aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
-
-    aProjection->data()->blockSendAttributeUpdated(aWasBlocked);
+  else if (anEdge->isCircle() || anEdge->isArc() || anEdge->isEllipse()) {
+    GeomAlgoAPI_Projection aProjAlgo(aSketchPlane);
+    GeomCurvePtr aProjectedCurve = aProjAlgo.project(anEdge);
+
+    if (aProjectedCurve->isCircle()) {
+      GeomAPI_Circ aCircle(aProjectedCurve);
+      GeomPointPtr aCenter = aSketchPlane->project(aCircle.center());
+      GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
+
+      if (aProjectedCurve->isTrimmed()) {
+        // ARC is a projection
+        rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
+
+        GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam());
+        GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam());
+        GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst));
+        GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast));
+
+        double aNormalsDot = aCircle.normal()->dot(aSketchPlane->direction());
+        if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
+          return; // arc is not in the plane, parallel to the sketch plane
+
+        bool isInversed = aNormalsDot < 0.;
+
+        bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true);
+
+        // update attributes of projection
+        std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
+        std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_Arc::START_ID()));
+        std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_Arc::END_ID()));
+        aStartPnt->setValue(aFirstInSketch);
+        aEndPnt->setValue(aLastInSketch);
+        aCenterPnt->setValue(aCenterInSketch);
+        aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
+
+        aProjection->data()->blockSendAttributeUpdated(aWasBlocked);
+      }
+      else {
+        // CIRCLE is a projection
+        rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(),
+                                SketchPlugin_Circle::ID());
+
+        // update attributes of projection
+        std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
+        aCenterPnt->setValue(aCenterInSketch);
+        aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
+      }
+    }
+    else if (aProjectedCurve->isEllipse()) {
+      GeomAPI_Ellipse anEllipse(aProjectedCurve);
+      GeomPointPtr aCenter = aSketchPlane->project(anEllipse.center());
+      GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
+      GeomPointPtr aFocus = aSketchPlane->project(anEllipse.firstFocus());
+      GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
+
+      if (aProjectedCurve->isTrimmed()) {
+        // ELLIPTIC ARC is a projection
+        rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
+
+        GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam());
+        GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam());
+        GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst));
+        GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast));
+
+        double aNormalsDot = anEllipse.normal()->dot(aSketchPlane->direction());
+        if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
+          return; // arc is not in the plane, parallel to the sketch plane
+
+        bool isInversed = aNormalsDot < 0.;
+
+        bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true);
+
+        // update attributes of projection
+        std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+        std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
+        std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+        std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+        aStartPnt->setValue(aFirstInSketch);
+        aEndPnt->setValue(aLastInSketch);
+        aCenterPnt->setValue(aCenterInSketch);
+        aFocusPnt->setValue(aFocusInSketch);
+        aProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
+
+        aProjection->data()->blockSendAttributeUpdated(aWasBlocked);
+      }
+      else {
+        // ELLIPSE is a projection
+        rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(),
+                                SketchPlugin_Ellipse::ID());
+
+        // update attributes of projection
+        std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
+        aCenterPnt->setValue(aCenterInSketch);
+        std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+            aProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
+        aFocusPnt->setValue(aFocusInSketch);
+        aProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(
+            anEllipse.minorRadius());
+      }
+    }
+    else
+      return;
   } else
     return;
 
@@ -279,3 +374,29 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     }
   }
 }
+
+bool SketchPlugin_Projection::rebuildProjectedFeature(
+    FeaturePtr& theProjection,
+    const std::set<std::string>& theSupportedTypes,
+    const std::string& theRequestedFeature)
+{
+  bool isRebuild = false;
+  if (theProjection &&
+      (theSupportedTypes.find(theProjection->getKind()) == theSupportedTypes.end() ||
+      (!theRequestedFeature.empty() && theProjection->getKind() != theRequestedFeature))) {
+    DocumentPtr aDoc = sketch()->document();
+
+    AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
+    aRefAttr->setObject(data()->owner()); // to not remove of this remove reference to aProjection
+    std::set<FeaturePtr> aFeaturesToBeRemoved;
+    aFeaturesToBeRemoved.insert(theProjection);
+    ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
+    theProjection = FeaturePtr();
+    aRefAttr->setObject(theProjection);
+    isRebuild = true;
+  }
+
+  if (!theProjection && !theRequestedFeature.empty())
+    theProjection = sketch()->addFeature(theRequestedFeature);
+  return isRebuild;
+}
index b928dfabdd5c577428685e3805da92641c5e0b56..40fd6301a6933faafea9675ea4c5b3d8a6a58e5c 100644 (file)
@@ -88,6 +88,16 @@ private:
   /// \brief Find projection of a feature onto sketch plane
   void computeProjection(const std::string& theID);
 
+  /// \brief Delete already calculated projected feature
+  ///        if the selection of the projection is changed
+  /// \param[in/out] theProjection   projected feature
+  /// \param[in] theSupportedTypes   types supported relatively to the base selection
+  /// \param[in] theRequestedFeature type of the new feature to be created
+  ///                                (remove only if empty string).
+  bool rebuildProjectedFeature(FeaturePtr& theProjection,
+                               const std::set<std::string>& theSupportedTypes,
+                               const std::string& theRequestedFeature = std::string());
+
   bool myIsComputing;
 };
 
index 0daeb330d810e76a3eea6ac3d964764e15bc607e..9c247446cfeeebb6d666134c7616727e45c15c1f 100644 (file)
@@ -377,6 +377,35 @@ void SketchPlugin_Sketch::createPoint2DResult(ModelAPI_Feature* theFeature,
   theFeature->setResult(aResult, theIndex);
 }
 
+void SketchPlugin_Sketch::createLine2DResult(ModelAPI_Feature* theFeature,
+                                             SketchPlugin_Sketch* theSketch,
+                                             const std::string& theStartAttrID,
+                                             const std::string& theEndAttrID,
+                                             const int theIndex)
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(theStartAttrID));
+  std::shared_ptr<GeomDataAPI_Point2D> anEndAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(theEndAttrID));
+
+  if (!aStartAttr || !aStartAttr->isInitialized() ||
+      !anEndAttr || !anEndAttr->isInitialized())
+    return;
+
+  std::shared_ptr<GeomAPI_Pnt> aStart(theSketch->to3D(aStartAttr->x(), aStartAttr->y()));
+  std::shared_ptr<GeomAPI_Pnt> anEnd(theSketch->to3D(anEndAttr->x(), anEndAttr->y()));
+  //std::cout<<"Execute line "<<aStart->x()<<" "<<aStart->y()<<" "<<aStart->z()<<" - "
+  //  <<anEnd->x()<<" "<<anEnd->y()<<" "<<anEnd->z()<<std::endl;
+  // make linear edge
+  std::shared_ptr<GeomAPI_Edge> anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd);
+  // store the result
+  std::shared_ptr<ModelAPI_ResultConstruction> aResult =
+      theFeature->document()->createConstruction(theFeature->data(), theIndex);
+  aResult->setShape(anEdge);
+  aResult->setIsInHistory(false);
+  theFeature->setResult(aResult, theIndex);
+}
+
 FeaturePtr SketchPlugin_Sketch::addUniqueNamedCopiedFeature(FeaturePtr theFeature,
                                                             SketchPlugin_Sketch* theSketch,
                                                             const bool theIsCopy)
index 124ff670c0e843d1a9a0fbbc124bb2f4bd0da732..7f63c5bb2ca4643eee898b0878d9ba81f3528389 100644 (file)
@@ -230,6 +230,18 @@ class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICu
                                   SketchPlugin_Sketch* theSketch,
                                   const std::string& theAttributeID, const int theIndex);
 
+  /// \brief Create a result for the segment given by a pair of attributes
+  /// \param theFeature a source feature
+  /// \param theSketch a sketch intance
+  /// \param theStartAttrID an attribute string
+  /// \param theEndAttrID an attribute string
+  /// \param theIndex an index of the result
+  static void createLine2DResult(ModelAPI_Feature* theFeature,
+                                 SketchPlugin_Sketch* theSketch,
+                                 const std::string& theStartAttrID,
+                                 const std::string& theEndAttrID,
+                                 const int theIndex = 0);
+
   /// Add new feature and fill the data of the feature by the data of the parameter feature.
   /// The name of the created feature stays unique.
   /// \param theFeature a source feature
index c207dd72b264b3f279483e3fa17021978e59a006..eb50851fa4b2552de343f896214801e0163c321a 100644 (file)
@@ -156,7 +156,7 @@ class SketchPlugin_SketchEntity : public SketchPlugin_Feature, public GeomAPI_IC
       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 perasentation object
+        // 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]);
       }
index ac6a15d6d78d2094735b93585d9541e29e7ffb9f..a8f054eb8eb5b5948606ac09f3fde632c5f2ab8b 100644 (file)
@@ -27,7 +27,6 @@
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
 #include <GeomAlgoAPI_ShapeTools.h>
-#include <GeomAlgoAPI_CompoundBuilder.h>
 
 #include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeDouble.h>
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMiddle.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintParallel.h>
 #include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
 #include <SketchPlugin_Point.h>
-#include <SketchPlugin_Tools.h>
 
 #include <ModelGeomAlgo_Point2D.h>
 #include <ModelAPI_EventReentrantMessage.h>
@@ -88,11 +89,6 @@ void SketchPlugin_Split::initAttributes()
 
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PREVIEW_POINT());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PREVIEW_OBJECT());
-
-  // TODO: remove
-  //data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
-  //data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
-  //data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
 }
 
 void SketchPlugin_Split::execute()
@@ -102,26 +98,21 @@ void SketchPlugin_Split::execute()
   // Check the base objects are initialized.
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                                            data()->attribute(SELECTED_OBJECT()));
-  //ObjectPtr aBaseObject = anObjectAttr->value();
-  //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-  //                                          aData->attribute(SketchPlugin_Constraint::VALUE()));
   if(!aBaseObjectAttr->isInitialized()) {
     setError("Error: Base object is not initialized.");
     return;
   }
   ObjectPtr aBaseObject = aBaseObjectAttr->value();
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
-  //  getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
-  //  getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
   if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
       !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
     setError("Error: Sub-shape is not initialized.");
     return;
   }
 
-  /// Remove reference of this feature to feature used in preview, it is not necessary anymore
-  /// as trim will be removed after execute
+  // Remove reference of this feature to feature used in preview, it is not necessary anymore
+  // as trim will be removed after execute
   AttributeReferencePtr aPreviewObjectAttr =
                      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                      data()->attribute(PREVIEW_OBJECT()));
@@ -142,17 +133,17 @@ void SketchPlugin_Split::execute()
 
   // Find feature constraints
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
-  ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
+  ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
   std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
 
   //std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
   std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
-  getConstraints(aFeaturesToDelete, aFeaturesToUpdate, /*aTangentFeatures, */
-                 aCoincidenceToFeature);
+  getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aCoincidenceToFeature);
 
   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
   std::list<AttributePtr> aRefsToFeature;
-  getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
+  SketchPlugin_SegmentationTools::getRefAttributes(
+      aBaseFeature, aBaseRefAttributes, aRefsToFeature);
 
   std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
 
@@ -248,18 +239,19 @@ void SketchPlugin_Split::execute()
   else if (aFeatureKind == SketchPlugin_Arc::ID())
     aNewFeature = splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
                            aCreatedFeatures, aModifiedAttributes);
+  else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
+    aNewFeature = splitEllipticArc(aSplitFeature, aBaseFeature, anAfterFeature,
+        aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
 
   restoreCurrentFeature();
 
-  if (aFeatureKind == SketchPlugin_Circle::ID()) {
-    FeaturePtr aCircleFeature = aBaseFeature;
-    aReplacingFeature = splitCircle(aSplitFeature, aBaseFeature, anAfterFeature,
+  if (aFeatureKind == SketchPlugin_Circle::ID() || aFeatureKind == SketchPlugin_Ellipse::ID()) {
+    aFeaturesToDelete.insert(aBaseFeature);
+    aReplacingFeature = splitClosed(aSplitFeature, aBaseFeature, anAfterFeature,
                                     aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
 
-    updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
+    updateRefFeatureConstraints(aBaseFeature->lastResult(), aRefsToFeature);
 
-    AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
-    aFeaturesToDelete.insert(aCircleFeature);
     // as circle is removed, temporary fill this attribute*/
     aBaseObjectAttr->setObject(ResultPtr());
   }
@@ -315,15 +307,15 @@ void SketchPlugin_Split::execute()
 #endif
 
   std::set<ResultPtr> aFeatureResults;
-  aFeatureResults.insert(getFeatureResult(aBaseFeature));
+  aFeatureResults.insert(aBaseFeature->lastResult());
   if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
-    aFeatureResults.insert(getFeatureResult(anAfterFeature));
+    aFeatureResults.insert(anAfterFeature->lastResult());
 
   // coincidence to feature
   updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
                                         aFeatureResults, aSplitFeature, aFeaturesToDelete);
 
-  updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
+  SketchPlugin_SegmentationTools::updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
 
   // delete constraints
 #ifdef DEBUG_SPLIT
@@ -347,7 +339,7 @@ void SketchPlugin_Split::execute()
     std::cout << std::endl;
   }
 #endif
-  updateFeaturesAfterSplit(aFeaturesToUpdate);
+  SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(aFeaturesToUpdate);
 
   // Send events to update the sub-features by the solver.
   if(isUpdateFlushed) {
@@ -360,7 +352,7 @@ void SketchPlugin_Split::execute()
     ResultPtr aReplacingResult;
     if (aReplacingFeature.get()) {
       aReplacingFeature->execute(); // need it to obtain result
-      aReplacingResult = getFeatureResult(aReplacingFeature);
+      aReplacingResult = aReplacingFeature->lastResult();
     }
     if (aReplacingResult.get()) { // base object was removed
       aPreviewObject = aReplacingResult;
@@ -387,7 +379,7 @@ void SketchPlugin_Split::execute()
       aPreviewObject = ObjectPtr();
 
       aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one
-      aBaseObject = getFeatureResult(aBaseFeature);
+      aBaseObject = aBaseFeature->lastResult();
       std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
                                                                 aPreviewPnt2d->y());
       ResultPtr aBaseResult = std::dynamic_pointer_cast<ModelAPI_Result>(aBaseObject);
@@ -398,7 +390,7 @@ void SketchPlugin_Split::execute()
           aPreviewObject = aBaseResult;
       }
       if (!aPreviewObject.get() && aNewFeature.get()) {
-        ResultPtr aNewFeatureResult = getFeatureResult(aNewFeature);
+        ResultPtr aNewFeatureResult = aNewFeature->lastResult();
         if (aNewFeatureResult.get()) {
           GeomShapePtr aShape = aNewFeatureResult->shape();
           std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
@@ -440,10 +432,10 @@ std::string SketchPlugin_Split::processEvent(const std::shared_ptr<Events_Messag
     std::shared_ptr<GeomAPI_Pnt2d> aPoint = aMessage->clickedPoint();
 
     if (anObject.get() && aPoint.get()) {
-      //if (myCashedShapes.find(anObject) == myCashedShapes.end())
-      //  fillObjectShapes(anObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
-      if (myCashedShapes.find(anObject) == myCashedShapes.end())
-        fillObjectShapes(anObject, sketch()->data()->owner());
+      if (myCashedShapes.find(anObject) == myCashedShapes.end()) {
+        SketchPlugin_SegmentationTools::fillObjectShapes(
+            this, anObject, myCashedShapes, myCashedReferences);
+      }
       const std::set<GeomShapePtr>& aShapes = myCashedShapes[anObject];
       if (aShapes.size() > 1) {
         std::shared_ptr<ModelAPI_AttributeReference> aRefSelectedAttr =
@@ -466,7 +458,8 @@ std::string SketchPlugin_Split::processEvent(const std::shared_ptr<Events_Messag
 
         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
 
-        GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
+        GeomShapePtr aSelectedShape = SketchPlugin_SegmentationTools::getSubShape(this,
+            SELECTED_OBJECT(), SELECTED_POINT(), myCashedShapes, myCashedReferences);
         if (aSelectedShape.get()) {
           aFilledAttributeName = SELECTED_OBJECT();
         }
@@ -493,255 +486,11 @@ std::string SketchPlugin_Split::processEvent(const std::shared_ptr<Events_Messag
 
 AISObjectPtr SketchPlugin_Split::getAISObject(AISObjectPtr thePrevious)
 {
-  /*AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                           data()->attribute(SketchPlugin_Constraint::VALUE()));
-  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-
-  AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
-                                        data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
-                                        data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
-
-  if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
-      aFirstPointAttrOfSplit->isInitialized() &&
-      aSecondPointAttrOfSplit->isInitialized()) {
-
-    ResultPtr aResult = getFeatureResult(aBaseFeature);
-    GeomShapePtr aBaseShape = aResult->shape();
-    std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
-
-    std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
-    std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
-    aPoints.push_back(aStartPoint);
-
-    std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
-    std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
-      sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
-    aPoints.push_back(aSecondPoint);
-
-    std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
-
-    GeomAlgoAPI_ShapeTools::splitShape_p(aBaseShape, aPoints, aSplitShapes);
-    std::shared_ptr<GeomAPI_Shape> aShape =
-      GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
-
-    AISObjectPtr anAIS = thePrevious;
-    if (aShape) {
-      if (!anAIS)
-        anAIS = AISObjectPtr(new GeomAPI_AISObject);
-      anAIS->createShape(aShape);
-      std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
-             aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
-
-      bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
-
-      std::vector<int> aColor;
-      double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
-      int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
-      if (isConstruction) {
-        aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
-        aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
-        aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
-      }
-      else {
-        aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
-      }
-      anAIS->setColor(aColor[0], aColor[1], aColor[2]);
-      anAIS->setWidth(aWidth + 1);
-      anAIS->setLineStyle(aLineStyle);
-    }
-    return anAIS;
-  }
-  return AISObjectPtr();*/
-#ifdef DEBUG_SPLIT
-  std::cout << "SketchPlugin_Split::getAISObject: " << data()->name() << std::endl;
-#endif
-
-  AISObjectPtr anAIS = thePrevious;
-
-  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
-  GeomShapePtr aPreviewShape = getSubShape(PREVIEW_OBJECT(), PREVIEW_POINT());
-  if (aPreviewShape.get())
-    aShapes.push_back(aPreviewShape);
-  GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
-  if (aSelectedShape.get())
-    aShapes.push_back(aSelectedShape);
-
-  if (aShapes.empty())
-    return AISObjectPtr();
-
-  GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
-  if (!aBaseShape.get())
-    return AISObjectPtr();
-
-  if (aBaseShape.get()) {
-    if (!anAIS)
-      anAIS = AISObjectPtr(new GeomAPI_AISObject);
-    anAIS->createShape(aBaseShape);
-
-    std::vector<int> aColor;
-    aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
-    double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
-    int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
-    anAIS->setColor(aColor[0], aColor[1], aColor[2]);
-    // width when there is not base object should be extened in several points
-    // in order to see this preview over highlight
-    anAIS->setWidth(aWidth+4);
-    anAIS->setLineStyle(aLineStyle);
-  }
-  else
-    anAIS = AISObjectPtr();
-  return anAIS;
+  return SketchPlugin_SegmentationTools::getAISObject(thePrevious,
+      this, PREVIEW_OBJECT(), PREVIEW_POINT(), SELECTED_OBJECT(), SELECTED_POINT());
 }
 
 //********************************************************************
-void SketchPlugin_Split::fillObjectShapes(const ObjectPtr& theObject,
-                                          const ObjectPtr& theSketch)
-{
-  std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
-  std::map<std::shared_ptr<GeomDataAPI_Point2D>, std::shared_ptr<GeomAPI_Pnt> > aPointToAttributes;
-  std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
-  // current feature
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
-  // edges on feature
-  std::set<ResultPtr> anEdgeResults;
-  ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeResults);
-  if (!anEdgeResults.empty()) {
-    GeomShapePtr aFeatureShape = (*anEdgeResults.begin())->shape();
-
-    // coincidences to the feature
-    ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
-                         aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
-    // layed on feature coincidences to divide it on several shapes
-    std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
-    std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-        aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
-    std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
-    std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
-    ModelGeomAlgo_Point2D::getPointsInsideShape_p(aFeatureShape, aRefAttributes, aC->pnt(),
-                                                aX->dir(), aY, aPoints, aPointToAttributes);
-
-    if (!aPoints.empty())
-      GeomAlgoAPI_ShapeTools::splitShape_p(aFeatureShape, aPoints, aShapes);
-  }
-  myCashedShapes[theObject] = aShapes;
-  myCashedReferences[theObject] = aPointToAttributes;
-}
-
-GeomShapePtr SketchPlugin_Split::getSubShape(const std::string& theObjectAttributeId,
-                                             const std::string& thePointAttributeId)
-{
-  GeomShapePtr aBaseShape;
-
-  AttributeReferencePtr anObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                                       data()->attribute(theObjectAttributeId));
-  ObjectPtr aBaseObject = anObjectAttr->value();
-  if (!aBaseObject.get())
-    return aBaseShape;
-
-  // point on feature
-  AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                           data()->attribute(thePointAttributeId));
-  std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
-  std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
-                                                               anAttributePnt2d->y());
-
-#ifdef TRIM_SHAPE
-  if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
-    fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
-
-  const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
-  if (!aShapes.empty()) {
-    std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
-    for (; anIt != aLast; anIt++) {
-      GeomShapePtr aShape = *anIt;
-      std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
-      if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, anAttributePnt, aProjectedPoint))
-        aBaseShape = aShape;
-    }
-  }
-#else
-  if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
-    fillObjectShapes(aBaseObject, sketch()->data()->owner());
-
-  std::shared_ptr<GeomAPI_Pnt> aStartPoint;
-  std::shared_ptr<GeomAPI_Pnt> aSecondPoint;
-  const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
-  std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
-  for (; anIt != aLast; anIt++) {
-    GeomShapePtr aCurrentShape = *anIt;
-    std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
-    if (ModelGeomAlgo_Point2D::isPointOnEdge(aCurrentShape, anAttributePnt, aProjectedPoint)) {
-      if (aCurrentShape->shapeType() == GeomAPI_Shape::EDGE) {
-        std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aCurrentShape));
-        aStartPoint = anEdge->firstPoint();
-        aSecondPoint = anEdge->lastPoint();
-      }
-      break;
-    }
-  }
-
-  if (!aStartPoint.get() || !aSecondPoint.get())
-    return aBaseShape;
-
-  //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-  //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
-  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject/*aBaseObjectAttr->value()*/);
-
-  //AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
-  //                                      data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  //AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
-  //                                      data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
-  if (anObjectAttr->isInitialized() && aBaseFeature.get() && aPointAttr->isInitialized()) {
-      //aFirstPointAttrOfSplit->isInitialized() &&
-      //aSecondPointAttrOfSplit->isInitialized()) {
-    ResultPtr aResult = getFeatureResult(aBaseFeature);
-    GeomShapePtr aResultShape = aResult->shape();
-    std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
-
-    //std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
-    //std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
-    aPoints.push_back(aStartPoint);
-
-    //std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
-    //std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
-    //  sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
-    aPoints.push_back(aSecondPoint);
-
-    std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
-    GeomAlgoAPI_ShapeTools::splitShape_p(aResultShape, aPoints, aSplitShapes);
-    aBaseShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
-#endif
-  }
-  return aBaseShape;
-}
-
-void SketchPlugin_Split::getFeaturePoints(const FeaturePtr& theFeature,
-                                                    AttributePoint2DPtr& theStartPointAttr,
-                                                    AttributePoint2DPtr& theEndPointAttr)
-{
-  std::string aFeatureKind = theFeature->getKind();
-  std::string aStartAttributeName, anEndAttributeName;
-  if (aFeatureKind == SketchPlugin_Line::ID()) {
-    aStartAttributeName = SketchPlugin_Line::START_ID();
-    anEndAttributeName = SketchPlugin_Line::END_ID();
-  }
-  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
-    aStartAttributeName = SketchPlugin_Arc::START_ID();
-    anEndAttributeName = SketchPlugin_Arc::END_ID();
-  }
-  if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
-    theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                         theFeature->attribute(aStartAttributeName));
-    theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                         theFeature->attribute(anEndAttributeName));
-  }
-}
-
 void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
                                     std::set<FeaturePtr>& theFeaturesToUpdate,
                                     std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
@@ -751,10 +500,8 @@ void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelet
   // Check the base objects are initialized.
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                                            data()->attribute(SELECTED_OBJECT()));
-  //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-  //                                          aData->attribute(SketchPlugin_Constraint::VALUE()));
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
+  ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
 
   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
@@ -772,13 +519,14 @@ void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelet
       theFeaturesToDelete.insert(aRefFeature);
     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
       theFeaturesToUpdate.insert(aRefFeature);
-    else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
+    else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID() ||
+             aRefFeatureKind == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
       std::string anAttributeToBeModified;
       AttributePoint2DPtr aCoincidentPoint;
       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
       AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
       bool isToFeature = false;
-      if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
+      if (anAttrA->isObject() || anAttrB->isObject()) { // coincidence to base feature
         FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
                                                   : FeaturePtr();
         isToFeature = aFeature.get() && aFeature == aBaseFeature;
@@ -792,7 +540,7 @@ void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelet
         if (isToFeature)
           aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
       }
-      if (!isToFeature) { /// coincidence to point on base feature
+      if (!isToFeature) { // coincidence to point on base feature
         AttributePtr anAttribute;
 
         if (!anAttrA->isObject()) {
@@ -825,52 +573,6 @@ void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelet
   }
 }
 
-void SketchPlugin_Split::getRefAttributes(const FeaturePtr& theFeature,
-                                    std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
-                                    std::list<AttributePtr>& theRefsToFeature)
-{
-  theRefs.clear();
-
-  std::list<AttributePtr> aPointAttributes =
-    theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-  std::set<AttributePtr> aPointAttributesSet;
-
-  std::list<AttributePtr>::const_iterator aPIt =
-    aPointAttributes.begin(), aPLast = aPointAttributes.end();
-  for (; aPIt != aPLast; aPIt++)
-    aPointAttributesSet.insert(*aPIt);
-
-  std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
-  std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
-  aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
-
-  std::set<AttributePtr>::const_iterator aIt;
-  for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
-    AttributePtr anAttr = (*aIt);
-    FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
-    if (anAttrFeature.get() != this &&
-        anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
-      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
-      if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
-        AttributePtr anAttrInRef = aRefAttr->attr();
-        if (anAttrInRef.get() &&
-            aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
-          if (theRefs.find(anAttrInRef) != theRefs.end())
-            theRefs[anAttrInRef].push_back(aRefAttr);
-          else {
-            std::list<AttributePtr> anAttrList;
-            anAttrList.push_back(aRefAttr);
-            theRefs[anAttrInRef] = anAttrList;
-          }
-        }
-      }
-      else { /// find attributes referenced to feature itself
-        theRefsToFeature.push_back(anAttr);
-      }
-    }
-  }
-}
-
 void SketchPlugin_Split::updateCoincidenceConstraintsToFeature(
       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
@@ -884,14 +586,15 @@ void SketchPlugin_Split::updateCoincidenceConstraintsToFeature(
   // we should build coincidence constraints to end of the split feature
   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
-  getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      theSplitFeature, aStartPointAttr, anEndPointAttr);
   if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
     aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
   if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
     aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
 
   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
-                                                            aCLast = theCoincidenceToFeature.end();
+                                                      aCLast = theCoincidenceToFeature.end();
 #ifdef DEBUG_SPLIT
   std::cout << std::endl;
   std::cout << "Coincidences to feature(modified):"<< std::endl;
@@ -931,7 +634,7 @@ void SketchPlugin_Split::updateCoincidenceConstraintsToFeature(
       }
     }
     else {
-      /// find feature by shape intersected the point
+      // find feature by shape intersected the point
       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
 
       if (theFeatureResults.size() > 1) { // try to find point on additional feature
@@ -966,45 +669,11 @@ void SketchPlugin_Split::updateRefFeatureConstraints(
   }
 }
 
-void SketchPlugin_Split::updateRefAttConstraints(
-                    const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
-                    const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
-{
-#ifdef DEBUG_SPLIT
-  std::cout << "SketchPlugin_Split::updateRefAttConstraints" << std::endl;
-#endif
-
-  std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
-    anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
-  for (; anIt != aLast; anIt++) {
-    AttributePtr anAttribute = anIt->first;
-
-    /// not found in references
-    if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
-      continue;
-    std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
-    std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
-                                            aRLast = aRefAttributes.end();
-
-    AttributePtr aNewAttribute = anIt->second;
-    for (; aRefIt != aRLast; aRefIt++) {
-      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
-      if (aRefAttr.get()) {
-        aRefAttr->setAttr(aNewAttribute);
-#ifdef DEBUG_SPLIT
-        FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
-        std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
-#endif
-      }
-    }
-  }
-}
-
 FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
-                                             FeaturePtr& theBaseFeatureModified,
-                                             FeaturePtr& theAfterFeature,
-                                             std::set<AttributePoint2DPtr>& thePoints,
-                                             std::set<FeaturePtr>& theCreatedFeatures,
+                                         FeaturePtr& theBaseFeatureModified,
+                                         FeaturePtr& theAfterFeature,
+                                         std::set<AttributePoint2DPtr>& thePoints,
+                                         std::set<FeaturePtr>& theCreatedFeatures,
                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
 {
   FeaturePtr anNewFeature;
@@ -1013,26 +682,16 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
   FeaturePtr aConstraintFeature;
   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
 
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch)
-    return anNewFeature;
-
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                                            data()->attribute(SELECTED_OBJECT()));
-  //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-  //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  std::string aFeatureKind = aBaseFeature->getKind();
-  if (aFeatureKind != SketchPlugin_Line::ID())
-    return anNewFeature;
 
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
-    //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
-    //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
 
-  getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
     setError("Error: Feature has no start and end points.");
     return anNewFeature;
@@ -1053,9 +712,9 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
 #endif
 
-  /// create a split feature
-  theSplitFeature =
-    createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+  // create a split feature
+  theSplitFeature = SketchPlugin_SegmentationTools::createLineFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
   theCreatedFeatures.insert(theSplitFeature);
 
   // before split feature
@@ -1064,20 +723,21 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
                                         theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
   }
   else {
-    theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
-    /// move end arc point to start of split
+    theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
+    // move end arc point to start of split
   }
 
   // after split feature
   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
     FeaturePtr aFeature;
     if (!theBaseFeatureModified.get()) {
-      aFeature = aBaseFeature; ///< use base feature to store all constraints here
+      aFeature = aBaseFeature; // use base feature to store all constraints here
       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
       aFeature->execute(); // to update result
     }
     else {
-      aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
+      aFeature = SketchPlugin_SegmentationTools::createLineFeature(
+          aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
       theCreatedFeatures.insert(aFeature);
       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
                                              aFeature->attribute(SketchPlugin_Line::END_ID())));
@@ -1109,7 +769,7 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
   // (after the after feature creation). Otherwise modified value will be used in after feature
   // before split feature
   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
-    /// move end arc point to start of split
+    // move end arc point to start of split
     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
                                                     aFirstPointAttrOfSplit);
     theBaseFeatureModified->execute(); // to update result
@@ -1132,14 +792,14 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
   // additional constraints between split and base features
   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
           SketchPlugin_ConstraintParallel::ID(),
-          getFeatureResult(aBaseFeature),
-          getFeatureResult(theSplitFeature));
+          aBaseFeature->lastResult(),
+          theSplitFeature->lastResult());
   theCreatedFeatures.insert(aConstraintFeature);
   if (theAfterFeature.get()) {
     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
           SketchPlugin_ConstraintParallel::ID(),
-          getFeatureResult(aBaseFeature),
-          getFeatureResult(theAfterFeature));
+          aBaseFeature->lastResult(),
+          theAfterFeature->lastResult());
     theCreatedFeatures.insert(aConstraintFeature);
   }
 #endif
@@ -1147,10 +807,10 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
 }
 
 FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
-                                            FeaturePtr& theBaseFeatureModified,
-                                            FeaturePtr& theAfterFeature,
-                                            std::set<AttributePoint2DPtr>& thePoints,
-                                            std::set<FeaturePtr>& theCreatedFeatures,
+                                        FeaturePtr& theBaseFeatureModified,
+                                        FeaturePtr& theAfterFeature,
+                                        std::set<AttributePoint2DPtr>& thePoints,
+                                        std::set<FeaturePtr>& theCreatedFeatures,
                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
 {
   FeaturePtr anNewFeature;
@@ -1159,25 +819,14 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
   FeaturePtr aConstraintFeature;
   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
 
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch)
-    return anNewFeature;
-
-  AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                                           data()->attribute(SELECTED_OBJECT()));
-  //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-  //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  std::string aFeatureKind = aBaseFeature->getKind();
-  if (aFeatureKind != SketchPlugin_Arc::ID())
-    return anNewFeature;
 
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
-    //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
-    //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
-  getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
     setError("Error: Feature has no start and end points.");
     return anNewFeature;
@@ -1197,8 +846,9 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
 #endif
 
-  /// split feature
-  theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+  // split feature
+  theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
   theCreatedFeatures.insert(theSplitFeature);
 
   // before split feature
@@ -1207,20 +857,21 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
                                   theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
   }
   else {
-    theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
-    /// move end arc point to start of split
+    theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
+    // move end arc point to start of split
   }
 
   // after split feature
   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
     FeaturePtr aFeature;
     if (!theBaseFeatureModified.get()) {
-      aFeature = aBaseFeature; ///< use base feature to store all constraints here
+      aFeature = aBaseFeature; // use base feature to store all constraints here
       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
       aFeature->execute(); // to update result
     }
     else {
-      aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
+      aFeature = SketchPlugin_SegmentationTools::createArcFeature(
+          aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
       theCreatedFeatures.insert(aFeature);
       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
@@ -1252,7 +903,7 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
   // (after the after feature creation). Otherwise modified value will be used in after feature
   // before split feature
   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
-    /// move end arc point to start of split
+    // move end arc point to start of split
     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
                                                     aFirstPointAttrOfSplit);
     theBaseFeatureModified->execute(); // to update result
@@ -1275,31 +926,175 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
 #ifdef CREATE_CONSTRAINTS
   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
           SketchPlugin_ConstraintEqual::ID(),
-          getFeatureResult(aBaseFeature),
-          getFeatureResult(theSplitFeature));
+          aBaseFeature->lastResult(),
+          theSplitFeature->lastResult());
+  theCreatedFeatures.insert(aConstraintFeature);
+  aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+          SketchPlugin_ConstraintTangent::ID(),
+          theSplitFeature->lastResult(),
+          aBaseFeature->lastResult());
+  theCreatedFeatures.insert(aConstraintFeature);
+  if (theAfterFeature.get()) {
+    aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+                SketchPlugin_ConstraintEqual::ID(),
+                aBaseFeature->lastResult(),
+                theAfterFeature->lastResult());
+    theCreatedFeatures.insert(aConstraintFeature);
+    aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+                SketchPlugin_ConstraintTangent::ID(),
+                theSplitFeature->lastResult(),
+                theAfterFeature->lastResult());
+    theCreatedFeatures.insert(aConstraintFeature);
+  }
+#endif
+  return anNewFeature;
+}
+
+FeaturePtr SketchPlugin_Split::splitEllipticArc(FeaturePtr& theSplitFeature,
+                                                FeaturePtr& theBaseFeatureModified,
+                                                FeaturePtr& theAfterFeature,
+                                                std::set<AttributePoint2DPtr>& thePoints,
+                                                std::set<FeaturePtr>& theCreatedFeatures,
+                 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
+{
+  FeaturePtr anNewFeature;
+
+  std::set<FeaturePtr> aCreatedFeatures;
+  FeaturePtr aConstraintFeature;
+  theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
+
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
+  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
+
+  AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
+  AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
+  AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
+    setError("Error: Feature has no start and end points.");
+    return anNewFeature;
+  }
+
+  arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
+                     aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+#ifdef DEBUG_SPLIT
+  std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
+  std::cout << "Start point: " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
+  std::cout << "1st point:   " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
+  std::cout << "2nd point:   " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
+  std::cout << "End point:   " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
+#endif
+
+  // split feature
+  theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
+  theCreatedFeatures.insert(theSplitFeature);
+
+  // before split feature
+  if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
+    theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
+        theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+  }
+  else {
+    theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
+    // move end arc point to start of split
+  }
+
+  // after split feature
+  if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
+    FeaturePtr aFeature;
+    if (!theBaseFeatureModified.get()) {
+      aFeature = aBaseFeature; // use base feature to store all constraints here
+      fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
+      aFeature->execute(); // to update result
+    }
+    else {
+      aFeature = SketchPlugin_SegmentationTools::createArcFeature(
+          aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
+      theCreatedFeatures.insert(aFeature);
+      theModifiedAttributes.insert(std::make_pair(
+          anEndPointAttrOfBase, aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+      anNewFeature = aFeature;
+    }
+    aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
+                     SketchPlugin_ConstraintCoincidence::ID(),
+                     theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+                     aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+    theCreatedFeatures.insert(aConstraintFeature);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                                (aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                                (aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+
+    if (!theBaseFeatureModified.get())
+      theBaseFeatureModified = aFeature;
+    else
+      theAfterFeature = aFeature;
+  }
+  else {
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+    theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
+        theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+  }
+  // base split, that is defined before split feature should be changed at end
+  // (after the after feature creation). Otherwise modified value will be used in after feature
+  // before split feature
+  if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
+    // move end arc point to start of split
+    fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+                  aFirstPointAttrOfSplit);
+    theBaseFeatureModified->execute(); // to update result
+    aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
+                     SketchPlugin_ConstraintCoincidence::ID(),
+                     theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+                     theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+    theCreatedFeatures.insert(aConstraintFeature);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+  }
+  else
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                     theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+
+  // additional constraints between split and base features
+#ifdef CREATE_CONSTRAINTS
+  aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+          SketchPlugin_ConstraintEqual::ID(),
+          aBaseFeature->lastResult(),
+          theSplitFeature->lastResult());
   theCreatedFeatures.insert(aConstraintFeature);
   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
           SketchPlugin_ConstraintTangent::ID(),
-          getFeatureResult(theSplitFeature),
-          getFeatureResult(aBaseFeature));
+          theSplitFeature->lastResult(),
+          aBaseFeature->lastResult());
   theCreatedFeatures.insert(aConstraintFeature);
   if (theAfterFeature.get()) {
     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
                 SketchPlugin_ConstraintEqual::ID(),
-                getFeatureResult(aBaseFeature),
-                getFeatureResult(theAfterFeature));
+                aBaseFeature->lastResult(),
+                theAfterFeature->lastResult());
     theCreatedFeatures.insert(aConstraintFeature);
     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
                 SketchPlugin_ConstraintTangent::ID(),
-                getFeatureResult(theSplitFeature),
-                getFeatureResult(theAfterFeature));
+                theSplitFeature->lastResult(),
+                theAfterFeature->lastResult());
     theCreatedFeatures.insert(aConstraintFeature);
   }
 #endif
   return anNewFeature;
 }
 
-FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature,
+FeaturePtr SketchPlugin_Split::splitClosed(FeaturePtr& theSplitFeature,
                                                FeaturePtr& theBaseFeatureModified,
                                                FeaturePtr& theAfterFeature,
                                                std::set<AttributePoint2DPtr>& thePoints,
@@ -1312,66 +1107,97 @@ FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature,
   FeaturePtr aConstraintFeature;
   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
 
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch)
-    return anNewFeature;
-
-  AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                                           data()->attribute(SELECTED_OBJECT()));
-  //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-  //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  std::string aFeatureKind = aBaseFeature->getKind();
-  if (aFeatureKind != SketchPlugin_Circle::ID())
-    return anNewFeature;
 
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
-    //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
-    //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
 
-  /// split feature
-  theSplitFeature =
-    createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
-  bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
+  // split feature
+  theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
+  const std::string& aReversedAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+  bool aSplitReversed = theSplitFeature->boolean(aReversedAttrName)->value();
   theCreatedFeatures.insert(theSplitFeature);
 
-  /// base feature is a left part of the circle
-  theBaseFeatureModified = createArcFeature(aBaseFeature,
-    aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+  // base feature is a left part of the circle
+  theBaseFeatureModified = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
   anNewFeature = theBaseFeatureModified;
-  std::dynamic_pointer_cast<SketchPlugin_Arc>(
-    theBaseFeatureModified)->setReversed(!aSplitReversed);
+  theBaseFeatureModified->boolean(aReversedAttrName)->setValue(!aSplitReversed);
   theBaseFeatureModified->execute();
 
-  theModifiedAttributes.insert(
-    std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
-                  theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
+  if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
+  }
+  else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) {
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::CENTER_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID())));
+
+    // update the PARENT_ID reference for all the features created by the ellipse
+    const std::set<AttributePtr>& aRefs = aBaseFeature->data()->refsToMe();
+    std::list<AttributePtr> aRefsToParent;
+    for (std::set<AttributePtr>::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) {
+      if ((*aRef)->id() == SketchPlugin_Line::PARENT_ID() ||
+          (*aRef)->id() == SketchPlugin_Point::PARENT_ID())
+        aRefsToParent.push_back(*aRef);
+    }
+    for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
+         aRef != aRefsToParent.end(); ++aRef)
+      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(theSplitFeature);
+  }
 
   theCreatedFeatures.insert(theBaseFeatureModified);
 
+  const std::string& aStartAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID();
+  const std::string& aEndAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID();
+
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
+                             (theBaseFeatureModified->attribute(aStartAttrName)));
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
+                             (theBaseFeatureModified->attribute(aEndAttrName)));
 
   // additional constraints between split and base features
   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
                      SketchPlugin_ConstraintCoincidence::ID(),
-                     theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
-                     theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
+                     theBaseFeatureModified->attribute(aEndAttrName),
+                     theSplitFeature->attribute(aEndAttrName));
   theCreatedFeatures.insert(aConstraintFeature);
   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
                      SketchPlugin_ConstraintCoincidence::ID(),
-                     theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
-                     theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
+                     theBaseFeatureModified->attribute(aStartAttrName),
+                     theSplitFeature->attribute(aStartAttrName));
   theCreatedFeatures.insert(aConstraintFeature);
 
 #ifdef CREATE_CONSTRAINTS
   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
                      SketchPlugin_ConstraintTangent::ID(),
-                     getFeatureResult(theSplitFeature),
-                     getFeatureResult(theBaseFeatureModified));
+                     theSplitFeature->lastResult(),
+                     theBaseFeatureModified->lastResult());
   theCreatedFeatures.insert(aConstraintFeature);
 #endif
   return anNewFeature;
@@ -1401,9 +1227,14 @@ void SketchPlugin_Split::arrangePointsOnArc(
 {
   static const double anAngleTol = 1.e-12;
 
+  const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID();
+  const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+
   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-  bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
+      theArc->attribute(aCenterAttrName))->pnt();
+  bool isReversed = theArc->boolean(aReversedAttrName)->value();
 
   // collect directions to each point
   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
@@ -1453,109 +1284,6 @@ void SketchPlugin_Split::fillAttribute(const AttributePtr& theModifiedAttribute,
   }
 }
 
-FeaturePtr SketchPlugin_Split::createLineFeature(const FeaturePtr& theBaseFeature,
-                                                           const AttributePtr& theFirstPointAttr,
-                                                           const AttributePtr& theSecondPointAttr)
-{
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
-
-  fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
-  fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  aFeature->execute(); // to obtain result
-
-  return aFeature;
-}
-
-FeaturePtr SketchPlugin_Split::createArcFeature(const FeaturePtr& theBaseFeature,
-                                                          const AttributePtr& theFirstPointAttr,
-                                                          const AttributePtr& theSecondPointAttr)
-{
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  std::string aCenterAttributeId;
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
-    aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
-  else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
-    aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
-
-  if (aCenterAttributeId.empty())
-    return aFeature;
-
-  aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
-  // update fillet arc: make the arc correct for sure, so, it is not needed to process
-  // the "attribute updated"
-  // by arc; moreover, it may cause cyclicity in hte mechanism of updater
-  bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
-                theBaseFeature->attribute(aCenterAttributeId));
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  /// fill referersed state of created arc as it is on the base arc
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-    bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
-    aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed);
-  }
-  aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
-  aFeature->execute(); // to obtain result
-
-  return aFeature;
-}
-
-void SketchPlugin_Split::updateFeaturesAfterSplit(
-                                                   const std::set<FeaturePtr>& theFeaturesToUpdate)
-{
-  std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
-                                       aLast = theFeaturesToUpdate.end();
-  for (; anIt != aLast; anIt++) {
-    FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
-    std::string aRefFeatureKind = aRefFeature->getKind();
-    if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
-      std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
-                              std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
-      if (aLenghtFeature.get()) {
-        std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
-            ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
-        double aValue;
-        if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
-          aValueAttr->setValue(aValue);
-      }
-    }
-  }
-}
-
-std::shared_ptr<ModelAPI_Result> SketchPlugin_Split::getFeatureResult(
-                                    const std::shared_ptr<ModelAPI_Feature>& theFeature)
-{
-  std::shared_ptr<ModelAPI_Result> aResult;
-
-  std::string aFeatureKind = theFeature->getKind();
-  if (aFeatureKind == SketchPlugin_Line::ID())
-    aResult = theFeature->firstResult();
-  else if (aFeatureKind == SketchPlugin_Arc::ID())
-    aResult = theFeature->lastResult();
-  else if (aFeatureKind == SketchPlugin_Circle::ID())
-    aResult = theFeature->lastResult();
-
-  return aResult;
-}
-
 #ifdef _DEBUG
 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_Split::getEdgeAttributes(
                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
@@ -1571,6 +1299,10 @@ std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_Split::getEdgeAttrib
     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
   }
+  else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) {
+    anAttributes.insert(theFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+    anAttributes.insert(theFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+  }
   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
   }
 
@@ -1583,7 +1315,8 @@ std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_Split::getPointAttribute
 {
   std::shared_ptr<GeomDataAPI_Point2D> anAttribute;
 
-  GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
+  GeomShapePtr aSelectedShape = SketchPlugin_SegmentationTools::getSubShape(this,
+      SELECTED_OBJECT(), SELECTED_POINT(), myCashedShapes, myCashedReferences);
   if (!aSelectedShape.get())
     return anAttribute;
 
@@ -1602,7 +1335,7 @@ std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_Split::getPointAttribute
   std::shared_ptr<GeomAPI_Pnt> aLastPnt = anEdge->lastPoint();
 
   std::shared_ptr<GeomDataAPI_Point2D> aFirstPointAttr, aLastPointAttr;
-  /// find the points in feature attributes
+  // find the points in feature attributes
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
   std::list<AttributePtr> a2DPointAttributes = aBaseFeature->data()->attributes(
                                                     GeomDataAPI_Point2D::typeId());
@@ -1619,17 +1352,17 @@ std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_Split::getPointAttribute
       aLastPointAttr = anAttributePoint;
   }
 
-  /// find the points in coincident features
-  PntToAttributesMap aRefAttributes = myCashedReferences[aBaseObject];
-  PntToAttributesMap::const_iterator
+  // find the points in coincident features
+  const GeomAlgoAPI_ShapeTools::PointToRefsMap& aRefAttributes = myCashedReferences.at(aBaseObject);
+  GeomAlgoAPI_ShapeTools::PointToRefsMap::const_iterator
     aRIt = aRefAttributes.begin(), aRLast = aRefAttributes.end();
   for (; aRIt != aRLast; aRIt++) {
-    std::shared_ptr<GeomDataAPI_Point2D> anAttribute = aRIt->first;
-    std::shared_ptr<GeomAPI_Pnt> aPoint = aRIt->second;
+    const std::list<AttributePoint2DPtr>& anAttributes = aRIt->second.first;
+    GeomPointPtr aPoint = aRIt->first;
     if (!aFirstPointAttr.get() && aFirstPnt->isEqual(aPoint))
-      aFirstPointAttr = anAttribute;
+      aFirstPointAttr = anAttributes.front();
     if (!aLastPointAttr.get() && aLastPnt->isEqual(aPoint))
-      aLastPointAttr = anAttribute;
+      aLastPointAttr = anAttributes.front();
     if (aFirstPointAttr.get() && aLastPointAttr.get())
       break;
   }
@@ -1654,13 +1387,13 @@ std::string SketchPlugin_Split::getFeatureInfo(const std::shared_ptr<ModelAPI_Fe
   if (isUseAttributesInfo) {
     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
                                                              getEdgeAttributes(theFeature));
-    /// processing of feature with point 2d attributes, like line, arc, circle
+    // processing of feature with point 2d attributes, like line, arc, circle
     if (!aPointsInfo.empty()) {
       anInfo += ": ";
       anInfo += "\n";
       anInfo += aPointsInfo;
     }
-    else { /// process constraint coincidence, find points in ref attr attributes
+    else { // process constraint coincidence, find points in ref attr attributes
       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
                                                        ModelAPI_AttributeRefAttr::typeId());
       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
index 01d153e76871e51037b29b4a367dc0e3189a365a..1c8273b6e245cd8f5dd689777edc7eafb2348435 100644 (file)
@@ -21,8 +21,9 @@
 #define SketchPlugin_Split_H_
 
 #include "SketchPlugin.h"
+#include "SketchPlugin_Tools.h"
 
-#include "GeomAPI_IPresentable.h"
+#include <GeomAPI_IPresentable.h>
 #include <ModelAPI_IReentrant.h>
 
 #include <SketchPlugin_Sketch.h>
@@ -37,13 +38,14 @@ typedef std::pair<std::string, std::shared_ptr<GeomDataAPI_Point2D> > IdToPointP
  *  \ingroup Plugins
  *  \brief Feature for creation of a new constraint splitting object. Entities for split:
  * - Linear segment by point(s) on this line
- * - Arc by point(s) on this arc
- * - Circle by at least 2 split-points on this circle
+ * - Circular/elliptic arc by point(s) on this arc
+ * - Circle/ellipse by at least 2 split-points on it
  *
  * The following constraints will be applied after split to keep the divided segments geometry:
  * - Coincident constraints for both parts of created segments in the point of splitting
- * - For linear segments parallel, for circles - tangent constraint, for arc - tangent and equal
- *   constraints. In case of three segments in result two couple of constraints are created
+ * - For linear segments parallel, for circles/ellipses - tangent constraint,
+ *   for arc - tangent and equal constraints. In case of three segments in result
+ *   two couple of constraints are created
  *    - parallel and equal constraints: the first is between 1st and middle entity, the second is
  *      between 1st and 3rd.
  *    - tangency constraints: the first between 1st and 2nd, the second between 2nd and 3rd.
@@ -57,11 +59,6 @@ typedef std::pair<std::string, std::shared_ptr<GeomDataAPI_Point2D> > IdToPointP
  *      start point of arc/line.
  *    - Replication constraint used split feature will be deleted in the same way as it is deleted
  *      by any of entity delete in sketch which is used in this constraint.
- *
- *  This constraint has three attributes:
- *  SketchPlugin_Constraint::VALUE() contains reference object to be splitted
- *  SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B() for the points of split;
- *
  */
 class SketchPlugin_Split : public SketchPlugin_Feature, public GeomAPI_IPresentable,
                            public ModelAPI_IReentrant
@@ -131,23 +128,6 @@ class SketchPlugin_Split : public SketchPlugin_Feature, public GeomAPI_IPresenta
   virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
 private:
-  /// Fulfill an internal container by shapes obtained from the parameter object
-  /// Shapes are result of split operation by points coincident to shape of the object
-  /// \param theObject a source object (will be splitted)
-  /// \param theSketch a sketch object
-  void fillObjectShapes(const ObjectPtr& theObject, const ObjectPtr& theSketch);
-
-  GeomShapePtr getSubShape(const std::string& theObjectAttributeId,
-                           const std::string& thePointAttributeId);
-  /// Returns geom point attribute of the feature bounds. It processes line or arc.
-  /// For circle feature, the result attributes are null
-  /// \param theFeature a source feature
-  /// \param theStartPointAttr an out attribute to start point
-  /// \param theStartPointAttr an out attribute to end point
-  void getFeaturePoints(const FeaturePtr& theFeature,
-                        std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
-                        std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr);
-
   /// Obtains those constraints of the feature that should be modified. output maps contain
   /// point of coincidence and attribute id to be modified after split
   /// \param theFeaturesToDelete [out] constrains that will be deleted after split
@@ -159,17 +139,6 @@ private:
               std::set<std::shared_ptr<ModelAPI_Feature>>& theFeaturesToUpdate,
               std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature);
 
-  /// Obtains references to feature point attributes and to feature,
-  /// e.g. for feature line: 1st container is
-  ///             <1st line point, list<entity_a in distance, entity_b in parallel> >
-  ///             <2nd line point, list<> >
-  ///      for feature circle 2nd container is <entity_a in Radius, entity_b in equal, ...>
-  /// \param theFeature an investigated feature
-  /// \param theRefs a container of list of referenced attributes
-  void getRefAttributes(const FeaturePtr& theFeature,
-                        std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
-                        std::list<AttributePtr>& theRefsToFeature);
-
   /// Move coincidence constraint from feature to point if it is found
   /// \param theCoincidenceToFeature coincidence to feature to be connected to new feature
   /// \param theFurtherCoincidences a list of points where coincidences will be build
@@ -191,14 +160,6 @@ private:
   void updateRefFeatureConstraints(const std::shared_ptr<ModelAPI_Result>& theFeatureBaseResult,
                                    const std::list<AttributePtr>& theRefsToFeature);
 
-  /// Move constraints from attribute of base feature to attribute after modification
-  /// \param theBaseRefAttributes container of references to the attributes of base feature
-  /// \param theModifiedAttributes container of attributes placed instead of base attributes
-  /// at the same place
-  void updateRefAttConstraints(
-               const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
-               const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes);
-
   /// Make the base object is splitted by the point attributes
   /// \param theSplitFeature a result split feature
   /// \param theBeforeFeature a feature between start point and the 1st point of split feature
@@ -229,6 +190,20 @@ private:
                 std::set<std::shared_ptr<ModelAPI_Feature>>& theCreatedFeatures,
                 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
 
+  /// Make the base object is splitted by the point attributes
+  /// \param theSplitFeature a result split feature
+  /// \param theBeforeFeature a feature between start point and the 1st point of split feature
+  /// \param theAfterFeature a feature between last point of split feature and the end point
+  /// \param thePoints a list of points where coincidences will be build
+  /// \param theCreatedFeatures a container of created features
+  /// \return new elliptic arc if it was created
+  FeaturePtr splitEllipticArc(std::shared_ptr<ModelAPI_Feature>& theSplitFeature,
+                std::shared_ptr<ModelAPI_Feature>& theBeforeFeature,
+                std::shared_ptr<ModelAPI_Feature>& theAfterFeature,
+                std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
+                std::set<std::shared_ptr<ModelAPI_Feature>>& theCreatedFeatures,
+                std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
+
   /// Make the base object is splitted by the point attributes
   /// \param theSplitFeature a result split feature
   /// \param theBeforeFeature a feature between start point and the 1st point of split feature
@@ -236,7 +211,7 @@ private:
   /// \param thePoints a list of points where coincidences will be build
   /// \param theCreatedFeatures a container of created features
   /// \return new arc if it was created
-  FeaturePtr splitCircle(std::shared_ptr<ModelAPI_Feature>& theSplitFeature,
+  FeaturePtr splitClosed(std::shared_ptr<ModelAPI_Feature>& theSplitFeature,
                    std::shared_ptr<ModelAPI_Feature>& theBeforeFeature,
                    std::shared_ptr<ModelAPI_Feature>& theAfterFeature,
                    std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
@@ -275,32 +250,6 @@ private:
   void fillAttribute(const AttributePtr& theModifiedAttribute,
                      const AttributePtr& theSourceAttribute);
 
-  /// Creates a line feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature,
-                               const AttributePtr& theFirstPointAttr,
-                               const AttributePtr& theSecondPointAttr);
-
-  /// Creates an arc feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature,
-                              const AttributePtr& theFirstPointAttr,
-                              const AttributePtr& theSecondPointAttr);
-
-  /// Add feature coincidence constraint between given attributes
-  /// \param theFeaturesToUpdate a constraint index
-  void updateFeaturesAfterSplit(const std::set<FeaturePtr>& theFeaturesToUpdate);
-
-  /// Result result of the feature to build constraint with. For arc, circle it is an edge result.
-  /// \param theFeature a feature
-  /// \return result object
-  std::shared_ptr<ModelAPI_Result> getFeatureResult(
-                                    const std::shared_ptr<ModelAPI_Feature>& theFeature);
-
   /// Returns attributes of the feature, used in edge build, for arc it is end and start points
   /// \param theFeature a feature
   /// \return container of attributes
@@ -320,11 +269,10 @@ private:
                              const bool isUseAttributesInfo = true);
 #endif
 private:
-  typedef std::map<std::shared_ptr<GeomDataAPI_Point2D>,
-                   std::shared_ptr<GeomAPI_Pnt> > PntToAttributesMap;
 
   std::map<std::shared_ptr<ModelAPI_Object>, std::set<GeomShapePtr> > myCashedShapes;
-  std::map<std::shared_ptr<ModelAPI_Object>, PntToAttributesMap> myCashedReferences;
+  std::map<std::shared_ptr<ModelAPI_Object>,
+           GeomAlgoAPI_ShapeTools::PointToRefsMap> myCashedReferences;
 };
 
 #endif
index 4f55be24d485ffb1d9997890f99f5da42e708fcd..a285ea2431c1e7b8a2364b91047292a88f43e56e 100644 (file)
 
 #include "SketchPlugin_Tools.h"
 
+#include "SketchPlugin_Arc.h"
+#include "SketchPlugin_Circle.h"
 #include "SketchPlugin_ConstraintCoincidence.h"
+#include "SketchPlugin_ConstraintCoincidenceInternal.h"
 #include "SketchPlugin_ConstraintLength.h"
 #include "SketchPlugin_ConstraintTangent.h"
+#include "SketchPlugin_Ellipse.h"
+#include "SketchPlugin_EllipticArc.h"
 #include "SketchPlugin_Line.h"
 #include "SketchPlugin_Point.h"
+#include "SketchPlugin_Projection.h"
 #include "SketchPlugin_SketchEntity.h"
+#include "SketchPlugin_Split.h"
+#include "SketchPlugin_Trim.h"
 
 #include <SketcherPrs_Tools.h>
 
 #include <ModelAPI_AttributeDouble.h>
 
+#include <ModelGeomAlgo_Point2D.h>
+#include <ModelGeomAlgo_Shape.h>
+
 #include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Edge.h>
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
 
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 
@@ -429,6 +444,68 @@ FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
   return aConstraint;
 }
 
+void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
+                                   const std::string& theEllipsePoint)
+{
+  SketchPlugin_Sketch* aSketch =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
+
+  FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
+  aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
+
+  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theEllipseFeature->attribute(theEllipsePoint));
+
+  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+  aCoord->setValue(anElPoint->x(), anElPoint->y());
+
+  aPointFeature->execute();
+  std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
+  aPointFeature->data()->setName(aName);
+  aPointFeature->lastResult()->data()->setName(aName);
+
+  createConstraintAttrAttr(aSketch,
+      SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord);
+}
+
+void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
+                                  const std::string& theStartPoint,
+                                  const std::string& theEndPoint)
+{
+  SketchPlugin_Sketch* aSketch =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
+
+  FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+  aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
+
+  AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theEllipseFeature->attribute(theStartPoint));
+  AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theEllipseFeature->attribute(theEndPoint));
+
+  AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+  aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
+
+  AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+  aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
+
+  aLineFeature->execute();
+  std::string aName = theEllipseFeature->name() + "_" +
+    (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
+  aLineFeature->data()->setName(aName);
+  aLineFeature->lastResult()->data()->setName(aName);
+
+  createConstraintAttrAttr(aSketch,
+      SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart);
+  createConstraintAttrAttr(aSketch,
+      SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd);
+}
+
 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
 {
   // currently process Length constraints only
@@ -461,3 +538,426 @@ GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
 }
 
 } // namespace SketchPlugin_Tools
+
+
+// =================================================================================================
+//                 namespace SketchPlugin_SegmentationTools
+// =================================================================================================
+
+void SketchPlugin_SegmentationTools::getFeaturePoints(const FeaturePtr& theFeature,
+                                                      AttributePoint2DPtr& theStartPointAttr,
+                                                      AttributePoint2DPtr& theEndPointAttr)
+{
+  std::string aFeatureKind = theFeature->getKind();
+  std::string aStartAttributeName, anEndAttributeName;
+  if (aFeatureKind == SketchPlugin_Line::ID()) {
+    aStartAttributeName = SketchPlugin_Line::START_ID();
+    anEndAttributeName = SketchPlugin_Line::END_ID();
+  }
+  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+    aStartAttributeName = SketchPlugin_Arc::START_ID();
+    anEndAttributeName = SketchPlugin_Arc::END_ID();
+  }
+  else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) {
+    aStartAttributeName = SketchPlugin_EllipticArc::START_POINT_ID();
+    anEndAttributeName = SketchPlugin_EllipticArc::END_POINT_ID();
+  }
+  if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
+    theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(aStartAttributeName));
+    theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(anEndAttributeName));
+  }
+}
+
+
+void SketchPlugin_SegmentationTools::getRefAttributes(
+    const FeaturePtr& theFeature,
+    std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
+    std::list<AttributePtr>& theRefsToFeature)
+{
+  theRefs.clear();
+
+  std::list<AttributePtr> aPointAttributes =
+    theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+  std::set<AttributePtr> aPointAttributesSet;
+
+  std::list<AttributePtr>::const_iterator aPIt =
+    aPointAttributes.begin(), aPLast = aPointAttributes.end();
+  for (; aPIt != aPLast; aPIt++)
+    aPointAttributesSet.insert(*aPIt);
+
+  std::set<AttributePtr> aRefsAttributes = theFeature->lastResult()->data()->refsToMe();
+  std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
+  aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
+
+  std::set<AttributePtr>::const_iterator aIt;
+  for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
+    AttributePtr anAttr = (*aIt);
+    FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
+    if (!anAttrFeature->isMacro() && // <- skip reference from Trim or Split feature
+        anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
+      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
+      if (!aRefAttr->isObject()) { // find attributes referenced to feature point attributes
+        AttributePtr anAttrInRef = aRefAttr->attr();
+        if (anAttrInRef.get() &&
+            aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
+          if (theRefs.find(anAttrInRef) != theRefs.end())
+            theRefs[anAttrInRef].push_back(aRefAttr);
+          else {
+            std::list<AttributePtr> anAttrList;
+            anAttrList.push_back(aRefAttr);
+            theRefs[anAttrInRef] = anAttrList;
+          }
+        }
+      }
+      else { // find attributes referenced to feature itself
+        theRefsToFeature.push_back(anAttr);
+      }
+    }
+  }
+}
+
+GeomShapePtr SketchPlugin_SegmentationTools::getSubShape(
+    SketchPlugin_Feature* theFeature,
+    const std::string& theObjectAttributeId,
+    const std::string& thePointAttributeId,
+    std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
+    std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
+{
+  GeomShapePtr aBaseShape;
+
+  AttributeReferencePtr anObjectAttr = theFeature->reference(theObjectAttributeId);
+  ObjectPtr aBaseObject = anObjectAttr->value();
+  if (!aBaseObject.get())
+    return aBaseShape;
+
+  // point on feature
+  AttributePoint2DPtr aPointAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(thePointAttributeId));
+  std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
+  std::shared_ptr<GeomAPI_Pnt> anAttributePnt =
+      theFeature->sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y());
+
+  if (theCashedShapes.find(aBaseObject) == theCashedShapes.end())
+    fillObjectShapes(theFeature, aBaseObject, theCashedShapes, theObjectToPoints);
+
+  std::shared_ptr<GeomAPI_Pnt> aStartPoint;
+  std::shared_ptr<GeomAPI_Pnt> aSecondPoint;
+  const std::set<GeomShapePtr>& aShapes = theCashedShapes[aBaseObject];
+  std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
+  for (; anIt != aLast; anIt++) {
+    GeomShapePtr aCurrentShape = *anIt;
+    std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
+    if (ModelGeomAlgo_Point2D::isPointOnEdge(aCurrentShape, anAttributePnt, aProjectedPoint)) {
+      if (theFeature->getKind() == SketchPlugin_Split::ID()) {
+        // for Split operation collect start and end points of the shape
+        if (aCurrentShape->shapeType() == GeomAPI_Shape::EDGE) {
+          std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aCurrentShape));
+          aStartPoint = anEdge->firstPoint();
+          aSecondPoint = anEdge->lastPoint();
+        }
+      }
+      else
+        aBaseShape = aCurrentShape;
+      break;
+    }
+  }
+
+  if (!aStartPoint.get() || !aSecondPoint.get())
+    return aBaseShape;
+
+  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
+  if (anObjectAttr->isInitialized() && aBaseFeature.get() && aPointAttr->isInitialized()) {
+    ResultPtr aResult = aBaseFeature->lastResult();
+    GeomShapePtr aResultShape = aResult->shape();
+    std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
+
+    aPoints.push_back(aStartPoint);
+    aPoints.push_back(aSecondPoint);
+
+    std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
+    GeomAlgoAPI_ShapeTools::splitShape_p(aResultShape, aPoints, aSplitShapes);
+    aBaseShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
+  }
+  return aBaseShape;
+}
+
+void SketchPlugin_SegmentationTools::fillObjectShapes(
+    SketchPlugin_Feature* theOpFeature,
+    const ObjectPtr& theObject,
+    std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
+    std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
+{
+  SketchPlugin_Sketch* aSketch = theOpFeature->sketch();
+
+  GeomAlgoAPI_ShapeTools::PointToRefsMap aPoints;
+  std::set<GeomShapePtr> aShapes;
+
+  std::set<AttributePoint2DPtr > aRefAttributes;
+  // current feature
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  std::set<ResultPtr> anEdgeShapes;
+  // edges on feature
+  ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
+  if (!anEdgeShapes.empty()) {
+    GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
+
+    // coincidences to the feature
+    ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
+                         aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+    // layed on feature coincidences to divide it on several shapes
+    std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
+    std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+        aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+    std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+        aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
+    std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
+    std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
+
+    ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
+                                                  aX->dir(), aY, aPoints);
+
+    if (theOpFeature->getKind() == SketchPlugin_Trim::ID()) {
+      // collect all intersection points with other edges for Trim operation only
+      std::list<FeaturePtr> aFeatures;
+      for (int i = 0; i < aSketch->numberOfSubs(); i++) {
+        FeaturePtr aFeature = aSketch->subFeature(i);
+        if (aFeature.get() && aFeature->getKind() != SketchPlugin_Projection::ID())
+          aFeatures.push_back(aFeature);
+      }
+      ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPoints);
+    }
+
+    if (!aPoints.empty())
+      GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes);
+  }
+  theObjectToPoints[theObject] = aPoints;
+  theCashedShapes[theObject] = aShapes;
+}
+
+void SketchPlugin_SegmentationTools::updateRefAttConstraints(
+    const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
+    const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
+{
+#if defined DEBUG_SPLIT || defined DEBUG_TRIM
+  std::cout << "updateRefAttConstraints" << std::endl;
+#endif
+
+  std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
+    anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
+  for (; anIt != aLast; anIt++) {
+    AttributePtr anAttribute = anIt->first;
+    AttributePtr aNewAttribute = anIt->second;
+
+    // not found in references
+    if (!aNewAttribute.get() ||
+        theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
+      continue;
+    std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
+    std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
+                                            aRLast = aRefAttributes.end();
+
+    for (; aRefIt != aRLast; aRefIt++) {
+      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
+      if (aRefAttr.get()) {
+        aRefAttr->setAttr(aNewAttribute);
+#ifdef DEBUG_SPLIT
+        FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
+        std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
+#endif
+      }
+    }
+  }
+}
+
+void SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(
+    const std::set<FeaturePtr>& theFeaturesToUpdate)
+{
+  std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
+                                       aLast = theFeaturesToUpdate.end();
+  for (; anIt != aLast; anIt++) {
+    FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
+    std::string aRefFeatureKind = aRefFeature->getKind();
+    if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
+      std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
+                              std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
+      if (aLenghtFeature.get()) {
+        std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
+            ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
+        double aValue;
+        if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
+          aValueAttr->setValue(aValue);
+      }
+    }
+  }
+}
+
+AISObjectPtr SketchPlugin_SegmentationTools::getAISObject(
+    AISObjectPtr thePrevious,
+    SketchPlugin_Feature* theOpFeature,
+    const std::string& thePreviewObjectAttrName,
+    const std::string& thePreviewPointAttrName,
+    const std::string& theSelectedObjectAttrName,
+    const std::string& theSelectedPointAttrName)
+{
+#if defined DEBUG_SPLIT || defined DEBUG_TRIM_METHODS
+  std::cout << "getAISObject: " << theOpFeature->data()->name() << std::endl;
+#endif
+
+  AISObjectPtr anAIS = thePrevious;
+
+  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
+  std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
+  std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap> aObjectToPoints;
+  GeomShapePtr aPreviewShape = getSubShape(theOpFeature,
+      thePreviewObjectAttrName, thePreviewPointAttrName, aCashedShapes, aObjectToPoints);
+  if (aPreviewShape.get())
+    aShapes.push_back(aPreviewShape);
+  GeomShapePtr aSelectedShape = getSubShape(theOpFeature,
+      theSelectedObjectAttrName, theSelectedPointAttrName, aCashedShapes, aObjectToPoints);
+  if (aSelectedShape.get())
+    aShapes.push_back(aSelectedShape);
+
+  if (aShapes.empty())
+    return AISObjectPtr();
+
+  GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+  if (!aBaseShape.get())
+    return AISObjectPtr();
+
+  if (aBaseShape.get()) {
+    if (!anAIS)
+      anAIS = AISObjectPtr(new GeomAPI_AISObject);
+    anAIS->createShape(aBaseShape);
+
+    std::vector<int> aColor;
+    aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
+    double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
+    int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
+    anAIS->setColor(aColor[0], aColor[1], aColor[2]);
+    // width when there is not base object should be extened in several points
+    // in order to see this preview over highlight
+    anAIS->setWidth(aWidth+4);
+    anAIS->setLineStyle(aLineStyle);
+  }
+  else
+    anAIS = AISObjectPtr();
+  return anAIS;
+}
+
+#define GEOM_DATA_POINT2D(f, a) std::dynamic_pointer_cast<GeomDataAPI_Point2D>((f)->attribute(a))
+
+FeaturePtr SketchPlugin_SegmentationTools::createLineFeature(
+    const FeaturePtr& theBaseFeature,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
+{
+  FeaturePtr aFeature;
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
+  SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
+  if (!aSketch || !theBaseFeature.get())
+    return aFeature;
+
+  aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+
+  GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::START_ID())->setValue(theFirstPoint);
+  GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::END_ID())->setValue(theSecondPoint);
+
+  aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+      theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
+  aFeature->execute(); // to obtain result
+
+  return aFeature;
+}
+
+struct ArcAttributes
+{
+  std::string myKind;
+  std::string myCenter;
+  std::string myFocus;
+  std::string myStart;
+  std::string myEnd;
+  std::string myReversed;
+
+  ArcAttributes() {}
+
+  ArcAttributes(const std::string& theKind) : myKind(theKind)
+  {
+    if (myKind == SketchPlugin_Arc::ID()) {
+      myCenter = SketchPlugin_Arc::CENTER_ID();
+      myStart = SketchPlugin_Arc::START_ID();
+      myEnd = SketchPlugin_Arc::END_ID();
+      myReversed = SketchPlugin_Arc::REVERSED_ID();
+    }
+    else if (myKind == SketchPlugin_Circle::ID()) {
+      myCenter = SketchPlugin_Circle::CENTER_ID();
+    }
+    else if (myKind == SketchPlugin_Ellipse::ID()) {
+      myCenter = SketchPlugin_Ellipse::CENTER_ID();
+      myFocus = SketchPlugin_Ellipse::FIRST_FOCUS_ID();
+    }
+    else if (myKind == SketchPlugin_EllipticArc::ID()) {
+      myCenter = SketchPlugin_EllipticArc::CENTER_ID();
+      myFocus = SketchPlugin_EllipticArc::FIRST_FOCUS_ID();
+      myStart = SketchPlugin_EllipticArc::START_POINT_ID();
+      myEnd = SketchPlugin_EllipticArc::END_POINT_ID();
+      myReversed = SketchPlugin_EllipticArc::REVERSED_ID();
+    }
+  }
+};
+
+FeaturePtr SketchPlugin_SegmentationTools::createArcFeature(
+    const FeaturePtr& theBaseFeature,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
+{
+  FeaturePtr aFeature;
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
+  SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
+  if (!aSketch || !theBaseFeature.get())
+    return aFeature;
+
+  ArcAttributes aBaseAttrs(theBaseFeature->getKind());
+  ArcAttributes aTargetAttrs;
+  if (aBaseAttrs.myKind == SketchPlugin_Arc::ID() ||
+      aBaseAttrs.myKind == SketchPlugin_Circle::ID())
+    aTargetAttrs = ArcAttributes(SketchPlugin_Arc::ID());
+  else if (aBaseAttrs.myKind == SketchPlugin_Ellipse::ID() ||
+           aBaseAttrs.myKind == SketchPlugin_EllipticArc::ID())
+    aTargetAttrs = ArcAttributes(SketchPlugin_EllipticArc::ID());
+
+  if (aTargetAttrs.myKind.empty())
+    return aFeature;
+
+  aFeature = aSketch->addFeature(aTargetAttrs.myKind);
+  // update fillet arc: make the arc correct for sure, so, it is not needed to process
+  // the "attribute updated"
+  // by arc; moreover, it may cause cyclicity in hte mechanism of updater
+  bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
+
+  GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myCenter)->setValue(
+      GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myCenter)->pnt());
+  if (!aTargetAttrs.myFocus.empty()) {
+    GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myFocus)->setValue(
+        GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myFocus)->pnt());
+  }
+  GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myStart)->setValue(theFirstPoint);
+  GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myEnd)->setValue(theSecondPoint);
+
+  aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+      theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
+
+  /// fill referersed state of created arc as it is on the base arc
+  bool aReversed = aBaseAttrs.myReversed.empty() ? false :
+                   theBaseFeature->boolean(aBaseAttrs.myReversed)->value();
+  aFeature->boolean(aTargetAttrs.myReversed)->setValue(aReversed);
+
+  aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update)
+  aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+
+  return aFeature;
+}
index 730d865b9127c4c9eee76c2995c18a862cd4bc01..f29e192dffa83622bd7b849635dd80738fe1c194 100644 (file)
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Attribute.h>
 #include <ModelAPI_AttributeRefAttr.h>
+#include <GeomAPI_Shape.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <list>
+#include <map>
+
+class GeomAPI_AISObject;
 
 class SketchPlugin_Constraint;
 class SketchPlugin_Feature;
@@ -103,6 +110,21 @@ void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
                                  const ObjectPtr theObject,
                                  const bool theIsCanBeTangent);
 
+/// Creates auxiliary point for ellipse and corresponding internal constraint.
+/// \param[in] theEllipse   base ellipse feature
+/// \param[in] theAttrName  name of the attribute of the ellipse,
+///                         the new point should be constrained
+void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
+                                   const std::string& theAttrName);
+
+/// Creates auxiliary axis for ellipse and corresponding internal constraints.
+/// \param[in] theEllipse   base ellipse feature
+/// \param[in] theStartAttr name of the attribute of the ellipse, the line is started
+/// \param[in] theEndAttr   name of the attribute of the ellipse, the line is ended
+void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
+                                  const std::string& theStartAttr,
+                                  const std::string& theEndAttr);
+
 /// Creates passing point or tangent curve basing on the given attributes are initialized.
 /// \param[in]  theRefAttr       prefered attribute to be converted
 /// \param[in]  theDefaultAttr   default attribute if theRefAttr is not initialized
@@ -118,4 +140,91 @@ void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr&      theRefA
 GeomPnt2dPtr flyoutPointCoordinates(const std::shared_ptr<SketchPlugin_Constraint>& theConstraint);
 }; // namespace SketchPlugin_Tools
 
+namespace SketchPlugin_SegmentationTools
+{
+  /// Returns geom point attribute of the feature bounds. It processes line or arc.
+  /// For circle/ellipse feature, the result attributes are null
+  /// \param theFeature        a source feature
+  /// \param theStartPointAttr an out attribute to start point
+  /// \param theEndPointAttr   an out attribute to end point
+  void getFeaturePoints(const FeaturePtr& theFeature,
+                        std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
+                        std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr);
+
+  /// Obtains references to feature point attributes and to feature,
+  /// e.g. for feature line: 1st container is
+  ///             <1st line point, list<entity_a in distance, entity_b in parallel> >
+  ///             <2nd line point, list<> >
+  ///      for feature circle 2nd container is <entity_a in Radius, entity_b in equal, ...>
+  /// \param theFeature an investigated feature
+  /// \param theRefs a container of list of referenced attributes
+  /// \param theRefsToFeature references to the feature result
+  void getRefAttributes(const FeaturePtr& theFeature,
+                        std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
+                        std::list<AttributePtr>& theRefsToFeature);
+
+  /// Obtains a part of shape selected/highlighted in the viewer for Split/Trim operation
+  /// \param[in] theFeature            Split/Trim feature
+  /// \param[in] theObjectAttributeId  name of attribute containing selected object
+  /// \param[in] thePointAttributeId   name of attribute containing point selected on the object
+  GeomShapePtr getSubShape(
+      SketchPlugin_Feature* theFeature,
+      const std::string& theObjectAttributeId,
+      const std::string& thePointAttributeId,
+      std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
+      std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints);
+
+  /// Fulfill an internal containers by shapes obtained from the parameter object
+  /// Shapes are results of Split/Trim operation by points coincident to shape of the object
+  /// \param theOpFeture an operation feature (Split/Trim)
+  /// \param theObject a source object (will be splitted)
+  void fillObjectShapes(
+      SketchPlugin_Feature* theOpFeature,
+      const ObjectPtr& theObject,
+      std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
+      std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints);
+
+  /// AIS object for selected/highlighted part of splitting/triming feature
+  /// \param[in] thePrevious  previous presentation
+  /// \param[in] theOpFeture  an operation feature (Split/Trim)
+  std::shared_ptr<GeomAPI_AISObject> getAISObject(std::shared_ptr<GeomAPI_AISObject> thePrevious,
+                                                  SketchPlugin_Feature* theOpFeature,
+                                                  const std::string& thePreviewObjectAttrName,
+                                                  const std::string& thePreviewPointAttrName,
+                                                  const std::string& theSelectedObjectAttrName,
+                                                  const std::string& theSelectedPointAttrName);
+
+  /// Move constraints from attribute of base feature to attribute after modification
+  /// \param theBaseRefAttributes container of references to the attributes of base feature
+  /// \param theModifiedAttributes container of attributes placed instead of base attributes
+  /// at the same place
+  void updateRefAttConstraints(
+      const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
+      const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes);
+
+  /// Updates line length if it exist in the list
+  /// \param theFeaturesToUpdate a constraint index
+  void updateFeaturesAfterOperation(const std::set<FeaturePtr>& theFeaturesToUpdate);
+
+
+  /// Creates a line feature filled by center of base feature and given points
+  /// \param theBaseFeature another arc feature
+  /// \param theFirstAttribute an attribute with coordinates for the start point
+  /// \param theSecondAttribute an attribute with coordinates for the end point
+  FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature,
+                               const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
+
+  /// Creates a circular/elliptic arc feature filled by center
+  /// (or by center and focus for elliptic arc) of base feature and given points
+  /// \param theBaseFeature     another circle or ellipse or circular/elliptic arc
+  /// \param theFirstAttribute  an attribute with coordinates for the start point
+  /// \param theSecondAttribute an attribute with coordinates for the end point
+  FeaturePtr createArcFeature(
+      const FeaturePtr& theBaseFeature,
+      const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+      const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
+
+}; // namespace SketchPlugin_SegmentationTools
+
 #endif // SKETCHPLUGIN_TOOLS_H_
\ No newline at end of file
index 66d7157c1abb0fb372a78cb862de0585aa19a9be..33ff36ab46b71cc56dd2d72fac4bcc3fc47d65ba 100644 (file)
@@ -25,7 +25,6 @@
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
 #include <GeomAlgoAPI_ShapeTools.h>
-#include <GeomAlgoAPI_CompoundBuilder.h>
 
 #include <ModelAPI_AttributeReference.h>
 #include <ModelAPI_AttributeString.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintCollinear.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
 #include <SketchPlugin_Point.h>
-#include <SketchPlugin_Projection.h>
-#include <SketchPlugin_Tools.h>
 
 #include <ModelAPI_EventReentrantMessage.h>
 
@@ -115,8 +114,10 @@ void SketchPlugin_Trim::findShapePoints(const std::string& theObjectAttributeId,
   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
                                                                anAttributePnt2d->y());
 
-  if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
-    fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
+  if (myCashedShapes.find(aBaseObject) == myCashedShapes.end()) {
+    SketchPlugin_SegmentationTools::fillObjectShapes(
+        this, aBaseObject, myCashedShapes, myObjectToPoints);
+  }
 
   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
   if (!aShapes.empty()) {
@@ -163,12 +164,14 @@ std::shared_ptr<GeomAPI_Pnt2d> SketchPlugin_Trim::convertPoint(
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                         data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
   ObjectPtr aBaseObject = aBaseObjectAttr->value();
-  if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end())
-    fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
+  if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end()) {
+    SketchPlugin_SegmentationTools::fillObjectShapes(
+        this, aBaseObject, myCashedShapes, myObjectToPoints);
+  }
 
   bool aFound = false;
-  const PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
-  for (PointToRefsMap::const_iterator aPointIt = aRefsMap.begin();
+  const GeomAlgoAPI_ShapeTools::PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
+  for (GeomAlgoAPI_ShapeTools::PointToRefsMap::const_iterator aPointIt = aRefsMap.begin();
        aPointIt != aRefsMap.end() && !aFound; aPointIt++) {
     if (aPointIt->first->isEqual(thePoint)) {
       const std::pair<std::list<AttributePoint2DPtr >,
@@ -252,7 +255,8 @@ void SketchPlugin_Trim::execute()
   // find references(attributes and features) to the base feature
   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
   std::list<AttributePtr> aRefsToFeature;
-  getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
+  SketchPlugin_SegmentationTools::getRefAttributes(
+      aBaseFeature, aBaseRefAttributes, aRefsToFeature);
 #ifdef DEBUG_TRIM
   std::cout << "---- getRefAttributes ----" << std::endl;
   std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
@@ -302,8 +306,9 @@ void SketchPlugin_Trim::execute()
   std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
   const std::string& aKind = aBaseFeature->getKind();
   FeaturePtr aReplacingFeature, aNewFeature;
-  if (aKind == SketchPlugin_Circle::ID()) {
-    aReplacingFeature = trimCircle(aStartShapePoint2d, aLastShapePoint2d,
+  if (aKind == SketchPlugin_Circle::ID() ||
+      aKind == SketchPlugin_Ellipse::ID()) {
+    aReplacingFeature = trimClosed(aStartShapePoint2d, aLastShapePoint2d,
                aFurtherCoincidences, aModifiedAttributes);
 
     aFeaturesToDelete.insert(aBaseFeature);
@@ -320,15 +325,21 @@ void SketchPlugin_Trim::execute()
     aNewFeature = trimArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
                           aFurtherCoincidences, aModifiedAttributes);
   }
+  else if (aKind == SketchPlugin_EllipticArc::ID()) {
+    aNewFeature = trimEllipticArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
+                          aFurtherCoincidences, aModifiedAttributes);
+  }
 
   restoreCurrentFeature();
 
   // constraints to end points of trim feature
-  if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end())
-    fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
+  if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end()) {
+    SketchPlugin_SegmentationTools::fillObjectShapes(
+        this, aBaseObject, myCashedShapes, myObjectToPoints);
+  }
 
   // create coincidence to objects, intersected the base object
-  const PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
+  const GeomAlgoAPI_ShapeTools::PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
   for (std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
                                                      aLast = aFurtherCoincidences.end();
        anIt != aLast; anIt++) {
@@ -356,8 +367,8 @@ void SketchPlugin_Trim::execute()
       continue;
 
     std::pair<std::list<AttributePoint2DPtr >, std::list<ObjectPtr > > anInfo;
-    for (PointToRefsMap::const_iterator aRefIt = aRefsMap.begin(); aRefIt != aRefsMap.end();
-         aRefIt++)
+    for (GeomAlgoAPI_ShapeTools::PointToRefsMap::const_iterator aRefIt = aRefsMap.begin();
+         aRefIt != aRefsMap.end(); aRefIt++)
     {
       if (aRefIt->first->isEqual(aPoint)) {
         anInfo = aRefIt->second;
@@ -378,7 +389,7 @@ void SketchPlugin_Trim::execute()
   ResultPtr aReplacingResult;
   if (aReplacingFeature.get()) {
     aReplacingFeature->execute(); // need it to obtain result
-    aReplacingResult = getFeatureResult(aReplacingFeature);
+    aReplacingResult = aReplacingFeature->lastResult();
   }
   for(std::list<AttributePtr>::const_iterator anIt = aRefsToFeature.begin(),
                                           aLast = aRefsToFeature.end();
@@ -406,7 +417,7 @@ void SketchPlugin_Trim::execute()
     }
   }
 
-  updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes, aFeaturesToDelete);
+  SketchPlugin_SegmentationTools::updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
 
   // Wait all constraints being created, then send update events
   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
@@ -429,7 +440,7 @@ void SketchPlugin_Trim::execute()
   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
 
-  updateFeaturesAfterTrim(aFeaturesToUpdate);
+  SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(aFeaturesToUpdate);
 
   // Send events to update the sub-features by the solver.
   if(isUpdateFlushed) {
@@ -453,7 +464,7 @@ void SketchPlugin_Trim::execute()
       aPreviewObject = ObjectPtr();
 
       aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one
-      aBaseObject = getFeatureResult(aBaseFeature);
+      aBaseObject = aBaseFeature->lastResult();
       std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
                                                                 aPreviewPnt2d->y());
       ResultPtr aBaseResult = std::dynamic_pointer_cast<ModelAPI_Result>(aBaseObject);
@@ -464,7 +475,7 @@ void SketchPlugin_Trim::execute()
           aPreviewObject = aBaseResult;
       }
       if (!aPreviewObject.get() && aNewFeature.get()) {
-        ResultPtr aNewFeatureResult = getFeatureResult(aNewFeature);
+        ResultPtr aNewFeatureResult = aNewFeature->lastResult();
         if (aNewFeatureResult.get()) {
           GeomShapePtr aShape = aNewFeatureResult->shape();
           std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
@@ -501,8 +512,10 @@ std::string SketchPlugin_Trim::processEvent(const std::shared_ptr<Events_Message
     std::shared_ptr<GeomAPI_Pnt2d> aPoint = aMessage->clickedPoint();
 
     if (anObject.get() && aPoint.get()) {
-      if (myCashedShapes.find(anObject) == myCashedShapes.end())
-        fillObjectShapes(anObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
+      if (myCashedShapes.find(anObject) == myCashedShapes.end()) {
+        SketchPlugin_SegmentationTools::fillObjectShapes(
+            this, anObject, myCashedShapes, myObjectToPoints);
+      }
       const std::set<GeomShapePtr>& aShapes = myCashedShapes[anObject];
       if (aShapes.size() > 1) {
         std::shared_ptr<ModelAPI_AttributeReference> aRefSelectedAttr =
@@ -525,7 +538,8 @@ std::string SketchPlugin_Trim::processEvent(const std::shared_ptr<Events_Message
 
         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
 
-        GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
+        GeomShapePtr aSelectedShape = SketchPlugin_SegmentationTools::getSubShape(this,
+            SELECTED_OBJECT(), SELECTED_POINT(), myCashedShapes, myObjectToPoints);
   #ifdef DEBUG_TRIM_METHODS
         if (!aSelectedShape.get())
           std::cout << "Set empty selected object" << std::endl;
@@ -593,7 +607,7 @@ bool SketchPlugin_Trim::moveTangency(const AttributePtr& theAttribute,
   // get shape of the feature of the attribute
   FeaturePtr anAttributeFeature = ModelAPI_Feature::feature(aRefAttr->object());
   anAttributeFeature->execute(); // the modified value should be applyed to recompute shape
-  PointToRefsMap aPointToAttributeOrObject;
+  GeomAlgoAPI_ShapeTools::PointToRefsMap aPointToAttributeOrObject;
   std::list<FeaturePtr> aFeatures;
   aFeatures.push_back(anAttributeFeature);
   ModelGeomAlgo_Point2D::getPointsIntersectedShape(aTangentFeature, aFeatures,
@@ -623,102 +637,8 @@ bool SketchPlugin_Trim::moveTangency(const AttributePtr& theAttribute,
 
 AISObjectPtr SketchPlugin_Trim::getAISObject(AISObjectPtr thePrevious)
 {
-#ifdef DEBUG_TRIM_METHODS
-  std::cout << "SketchPlugin_Trim::getAISObject: " << data()->name() << std::endl;
-#endif
-
-  AISObjectPtr anAIS = thePrevious;
-
-  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
-  GeomShapePtr aPreviewShape = getSubShape(PREVIEW_OBJECT(), PREVIEW_POINT());
-  if (aPreviewShape.get())
-    aShapes.push_back(aPreviewShape);
-  GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
-  if (aSelectedShape.get())
-    aShapes.push_back(aSelectedShape);
-
-  if (aShapes.empty())
-    return AISObjectPtr();
-
-  GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
-  if (!aBaseShape.get())
-    return AISObjectPtr();
-
-  if (aBaseShape.get()) {
-    if (!anAIS)
-      anAIS = AISObjectPtr(new GeomAPI_AISObject);
-    anAIS->createShape(aBaseShape);
-
-    std::vector<int> aColor;
-    aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
-    double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
-    int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
-    anAIS->setColor(aColor[0], aColor[1], aColor[2]);
-    // width when there is not base object should be extened in several points
-    // in order to see this preview over highlight
-    anAIS->setWidth(aWidth+4);
-    anAIS->setLineStyle(aLineStyle);
-  }
-  else
-    anAIS = AISObjectPtr();
-
-  return anAIS;
-}
-
-GeomShapePtr SketchPlugin_Trim::getSubShape(const std::string& theObjectAttributeId,
-                                            const std::string& thePointAttributeId)
-{
-  GeomShapePtr aBaseShape;
-
-  AttributeReferencePtr anObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                                       data()->attribute(theObjectAttributeId));
-  ObjectPtr aBaseObject = anObjectAttr->value();
-  if (!aBaseObject.get())
-    return aBaseShape;
-
-  // point on feature
-  AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                           data()->attribute(thePointAttributeId));
-  std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
-  std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
-                                                               anAttributePnt2d->y());
-
-  if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
-    fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
-
-  const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
-  if (!aShapes.empty()) {
-    std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
-    for (; anIt != aLast; anIt++) {
-      GeomShapePtr aShape = *anIt;
-      std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
-      if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, anAttributePnt, aProjectedPoint))
-        aBaseShape = aShape;
-    }
-  }
-  return aBaseShape;
-}
-
-void SketchPlugin_Trim::getFeaturePoints(const FeaturePtr& theFeature,
-                                         AttributePoint2DPtr& theStartPointAttr,
-                                         AttributePoint2DPtr& theEndPointAttr)
-{
-  std::string aFeatureKind = theFeature->getKind();
-  std::string aStartAttributeName, anEndAttributeName;
-  if (aFeatureKind == SketchPlugin_Line::ID()) {
-    aStartAttributeName = SketchPlugin_Line::START_ID();
-    anEndAttributeName = SketchPlugin_Line::END_ID();
-  }
-  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
-    aStartAttributeName = SketchPlugin_Arc::START_ID();
-    anEndAttributeName = SketchPlugin_Arc::END_ID();
-  }
-  if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
-    theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                         theFeature->attribute(aStartAttributeName));
-    theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                         theFeature->attribute(anEndAttributeName));
-  }
+  return SketchPlugin_SegmentationTools::getAISObject(thePrevious,
+      this, PREVIEW_OBJECT(), PREVIEW_POINT(), SELECTED_OBJECT(), SELECTED_POINT());
 }
 
 void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
@@ -730,7 +650,7 @@ void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                          aData->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
+  ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
 
   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
@@ -755,86 +675,6 @@ void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete
   }
 }
 
-void SketchPlugin_Trim::getRefAttributes(const FeaturePtr& theFeature,
-                                    std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
-                                    std::list<AttributePtr>& theRefsToFeature)
-{
-  theRefs.clear();
-
-  std::list<AttributePtr> aPointAttributes =
-    theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-  std::set<AttributePtr> aPointAttributesSet;
-
-  std::list<AttributePtr>::const_iterator aPIt =
-    aPointAttributes.begin(), aPLast = aPointAttributes.end();
-  for (; aPIt != aPLast; aPIt++)
-    aPointAttributesSet.insert(*aPIt);
-
-  std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
-  std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
-  aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
-
-  std::set<AttributePtr>::const_iterator aIt;
-  for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
-    AttributePtr anAttr = (*aIt);
-    FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
-    if (anAttrFeature.get() != this &&
-        anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
-      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
-      if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
-        AttributePtr anAttrInRef = aRefAttr->attr();
-        if (anAttrInRef.get() &&
-            aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
-          if (theRefs.find(anAttrInRef) != theRefs.end())
-            theRefs[anAttrInRef].push_back(aRefAttr);
-          else {
-            std::list<AttributePtr> anAttrList;
-            anAttrList.push_back(aRefAttr);
-            theRefs[anAttrInRef] = anAttrList;
-          }
-        }
-      }
-      else { /// find attributes referenced to feature itself
-        theRefsToFeature.push_back(anAttr);
-      }
-    }
-  }
-}
-
-void SketchPlugin_Trim::updateRefAttConstraints(
-                    const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
-                    const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes,
-                    std::set<FeaturePtr>& theFeaturesToDelete)
-{
-#ifdef DEBUG_TRIM
-  std::cout << "SketchPlugin_Trim::updateRefAttConstraints" << std::endl;
-#endif
-
-  std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
-    anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
-  for (; anIt != aLast; anIt++) {
-    AttributePtr anAttribute = anIt->first;
-
-    /// not found in references
-    if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
-      continue;
-    std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
-    std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
-                                            aRLast = aRefAttributes.end();
-
-    AttributePtr aNewAttribute = anIt->second;
-    if (aNewAttribute.get()) {
-      for (; aRefIt != aRLast; aRefIt++) {
-        AttributeRefAttrPtr aRefAttr =
-                        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
-        if (aRefAttr.get()) {
-            aRefAttr->setAttr(aNewAttribute);
-        }
-      }
-    }
-  }
-}
-
 void SketchPlugin_Trim::removeReferencesToAttribute(const AttributePtr& theAttribute,
                   std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes)
 {
@@ -870,27 +710,6 @@ void SketchPlugin_Trim::removeReferencesToAttribute(const AttributePtr& theAttri
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
 }
 
-void SketchPlugin_Trim::updateFeaturesAfterTrim(const std::set<FeaturePtr>& theFeaturesToUpdate)
-{
-  std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
-                                       aLast = theFeaturesToUpdate.end();
-  for (; anIt != aLast; anIt++) {
-    FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
-    std::string aRefFeatureKind = aRefFeature->getKind();
-    if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
-      std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
-                              std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
-      if (aLenghtFeature.get()) {
-        std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
-            ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
-        double aValue;
-        if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
-          aValueAttr->setValue(aValue);
-      }
-    }
-  }
-}
-
 FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
                   const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
                   std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
@@ -907,7 +726,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& the
 
   /// points of trim
   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
-  getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
 
   std::shared_ptr<GeomAPI_Pnt2d> aStartFeaturePoint = aStartPointAttrOfBase->pnt();
   std::shared_ptr<GeomAPI_Pnt2d> aLastFeaturePoint = anEndPointAttrOfBase->pnt();
@@ -958,7 +778,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& the
     // result is two lines: start line point - start shape point,
     // last shape point - last line point
     // create second line
-    anNewFeature = createLineFeature(aBaseFeature, aLastShapePoint, aLastFeaturePoint);
+    anNewFeature = SketchPlugin_SegmentationTools::createLineFeature(
+        aBaseFeature, aLastShapePoint, aLastFeaturePoint);
     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
                                (anNewFeature->attribute(SketchPlugin_Line::START_ID())));
 
@@ -976,8 +797,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& the
     // Collinear constraint for lines
     SketchPlugin_Tools::createConstraintObjectObject(sketch(),
                                          SketchPlugin_ConstraintCollinear::ID(),
-                                         getFeatureResult(aBaseFeature),
-                                         getFeatureResult(anNewFeature));
+                                         aBaseFeature->lastResult(),
+                                         anNewFeature->lastResult());
   }
   return anNewFeature;
 }
@@ -997,7 +818,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
 
   /// points of trim
   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
-  getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
 
   std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
   std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
@@ -1043,7 +865,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
   else {
     // result is two arcs: start arc point - start shape point, last shape point - last arc point
     // create second arc
-    anNewFeature = createArcFeature(aBaseFeature, aLastShapePoint, aLastArcPoint);
+    anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
+        aBaseFeature, aLastShapePoint, aLastArcPoint);
     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
                                (anNewFeature->attribute(SketchPlugin_Arc::START_ID())));
 
@@ -1061,8 +884,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
     // equal Radius constraint for arcs
     SketchPlugin_Tools::createConstraintObjectObject(sketch(),
                                          SketchPlugin_ConstraintEqual::ID(),
-                                         getFeatureResult(aBaseFeature),
-                                         getFeatureResult(anNewFeature));
+                                         aBaseFeature->lastResult(),
+                                         anNewFeature->lastResult());
     // coincident centers constraint
     SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
                                          SketchPlugin_ConstraintCoincidence::ID(),
@@ -1078,34 +901,172 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
   return anNewFeature;
 }
 
-FeaturePtr SketchPlugin_Trim::trimCircle(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
-                                   const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
-                                   std::set<AttributePoint2DPtr>& thePoints,
+FeaturePtr SketchPlugin_Trim::trimEllipticArc(
+                 const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+                 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+                 std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
+                 std::set<AttributePoint2DPtr>& thePoints,
                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
 {
+  FeaturePtr anNewFeature;
   // Check the base objects are initialized.
-  AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                        data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
   ObjectPtr aBaseObject = aBaseObjectAttr->value();
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
 
-  /// points of trim
-  //AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
-  //getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  // points of trim
+  AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+
+  std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
+  std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
+  arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
+                     aStartShapePoint, aLastShapePoint);
+#ifdef DEBUG_TRIM
+  std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
+  if (aStartShapePoint.get())
+    std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
+                                       aStartShapePoint->y() << "]" << std::endl;
+  std::cout << "Start arc attribute point:   [" << aStartArcPoint->x() << ", " <<
+                                   aStartArcPoint->y() << "]" << std::endl;
+  if (aLastShapePoint.get())
+    std::cout << "Last shape point:   [" << aLastShapePoint->x() << ", " <<
+                                     aLastShapePoint->y() << "]" << std::endl;
+  std::cout << "Last arc attribute point:   [" << aLastArcPoint->x() << ", " <<
+                                   aLastArcPoint->y() << "]" << std::endl;
+#endif
+
+  bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint);
+  bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint);
+  if (isStartPoint || isLastPoint) {
+    // result is one arc: changed existing arc
+    std::string aModifiedAttribute = isStartPoint ? SketchPlugin_EllipticArc::START_POINT_ID()
+                                                  : SketchPlugin_EllipticArc::END_POINT_ID();
+    std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+    if (aStartShapePoint.get() && aLastShapePoint.get())
+      aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
+    else
+      aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
+
+    removeReferencesToAttribute(aBaseFeature->attribute(aModifiedAttribute),
+                                theBaseRefAttributes);
+
+    fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                               (aBaseFeature->attribute(aModifiedAttribute)));
+  }
+  else {
+    // result is two arcs: start arc point - start shape point, last shape point - last arc point
+    // create second arc
+    anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
+        aBaseFeature, aLastShapePoint, aLastArcPoint);
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                     anNewFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+
+    std::string aModifiedAttribute = SketchPlugin_EllipticArc::END_POINT_ID();
+    theModifiedAttributes.insert(
+      std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
+                     anNewFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+
+    // modify base arc
+    fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
 
-  /// trim feature
-  FeaturePtr anNewFeature = createArcFeature(aBaseFeature, theStartShapePoint, theLastShapePoint);
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                               (aBaseFeature->attribute(aModifiedAttribute)));
+
+    // make elliptic arcs equal
+    SketchPlugin_Tools::createConstraintObjectObject(sketch(),
+                                         SketchPlugin_ConstraintEqual::ID(),
+                                         aBaseFeature->lastResult(),
+                                         anNewFeature->lastResult());
+    // coincident centers constraint
+    SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
+        SketchPlugin_ConstraintCoincidence::ID(),
+        aBaseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+
+#ifdef DEBUG_TRIM
+    std::cout << "Created arc on points:" << std::endl;
+    std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
+                                           aStartShapePoint->y() << "]" << std::endl;
+#endif
+  }
+  return anNewFeature;
+}
+
+FeaturePtr SketchPlugin_Trim::trimClosed(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+                                         const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+                                         std::set<AttributePoint2DPtr>& thePoints,
+                           std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
+{
+  // Check the base objects are initialized.
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
+  ObjectPtr aBaseObject = aBaseObjectAttr->value();
+  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
+
+  // trim feature
+  FeaturePtr anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, theStartShapePoint, theLastShapePoint);
   // arc created by trim of circle is always correct, that means that it is not inversed
-  anNewFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(false);
+  const std::string& aReversedAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+  anNewFeature->boolean(aReversedAttrName)->setValue(false);
+
+  if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+    theModifiedAttributes.insert(
+      std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
+                     anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
+  }
+  else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) {
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID())));
+
+    // update the PARENT_ID reference for all the features created by the ellipse
+    const std::set<AttributePtr>& aRefs = aBaseFeature->data()->refsToMe();
+    std::list<AttributePtr> aRefsToParent;
+    for (std::set<AttributePtr>::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) {
+      if ((*aRef)->id() == SketchPlugin_Line::PARENT_ID() ||
+          (*aRef)->id() == SketchPlugin_Point::PARENT_ID())
+        aRefsToParent.push_back(*aRef);
+    }
+    for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
+         aRef != aRefsToParent.end(); ++aRef)
+      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(anNewFeature);
+  }
 
-  theModifiedAttributes.insert(
-    std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
-                   anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
+  const std::string& aStartAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID();
+  const std::string& aEndAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID();
 
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (anNewFeature->attribute(SketchPlugin_Arc::START_ID())));
+                             (anNewFeature->attribute(aStartAttrName)));
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (anNewFeature->attribute(SketchPlugin_Arc::END_ID())));
+                             (anNewFeature->attribute(aEndAttrName)));
 
   return anNewFeature;
 }
@@ -1138,9 +1099,14 @@ void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc,
 
   static const double anAngleTol = 1.e-12;
 
+  const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID();
+  const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+
   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-  bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
+      theArc->attribute(aCenterAttrName))->pnt();
+  bool isReversed = theArc->boolean(aReversedAttrName)->value();
 
   // collect directions to each point
   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
@@ -1184,7 +1150,6 @@ void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttrib
   }
 }
 
-
 void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
                                       const AttributePtr& theSourceAttribute)
 {
@@ -1208,155 +1173,3 @@ void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
       aModifiedAttribute->setValue(aSourceAttribute->value());
   }
 }
-
-FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature,
-                                        const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                                        const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
-{
-#ifdef DEBUG_TRIM
-  std::cout << "---- createLineFeature ---" << std::endl;
-#endif
-
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
-
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint);
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  aFeature->execute(); // to obtain result
-
-#ifdef DEBUG_TRIM
-  std::cout << "---- createLineFeature:end ---" << std::endl;
-#endif
-
-  return aFeature;
-}
-
-FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature,
-                                               const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
-{
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  std::string aCenterAttributeId;
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
-    aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
-  else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
-    aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
-
-  if (aCenterAttributeId.empty())
-    return aFeature;
-
-#ifdef DEBUG_TRIM
-  std::cout << "---- createArcFeature ---" << std::endl;
-#endif
-
-  aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
-  // update fillet arc: make the arc correct for sure, so, it is not needed to process
-  // the "attribute updated"
-  // by arc; moreover, it may cause cyclicity in hte mechanism of updater
-  bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
-                theBaseFeature->attribute(aCenterAttributeId));
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint);
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  /// fill referersed state of created arc as it is on the base arc
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-    bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
-    aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed);
-  }
-  aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update)
-  aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
-
-  #ifdef DEBUG_TRIM
-  std::cout << "---- createArcFeature:end ---" << std::endl;
-  #endif
-
-  return aFeature;
-}
-
-std::shared_ptr<ModelAPI_Result> SketchPlugin_Trim::getFeatureResult(
-                                    const std::shared_ptr<ModelAPI_Feature>& theFeature)
-{
-  std::shared_ptr<ModelAPI_Result> aResult;
-
-  std::string aFeatureKind = theFeature->getKind();
-  if (aFeatureKind == SketchPlugin_Line::ID())
-    aResult = theFeature->firstResult();
-  else if (aFeatureKind == SketchPlugin_Arc::ID())
-    aResult = theFeature->lastResult();
-  else if (aFeatureKind == SketchPlugin_Circle::ID())
-    aResult = theFeature->lastResult();
-
-  return aResult;
-}
-
-//********************************************************************
-void SketchPlugin_Trim::fillObjectShapes(const ObjectPtr& theObject,
-                const ObjectPtr& theSketch,
-                std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
-                std::map<ObjectPtr, PointToRefsMap>& theObjectToPoints)
-{
-  PointToRefsMap aPointsInfo;
-
-  std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
-  std::map<std::shared_ptr<GeomAPI_Pnt>,
-                           std::list< AttributePoint2DPtr > > aPointToAttributes;
-  std::map<std::shared_ptr<GeomAPI_Pnt>,
-                           std::list< ObjectPtr > > aPointToObjects;
-
-  std::set<AttributePoint2DPtr > aRefAttributes;
-  // current feature
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
-  std::set<ResultPtr> anEdgeShapes;
-  // edges on feature
-  ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
-  if (!anEdgeShapes.empty()) {
-    GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
-
-    // coincidences to the feature
-    ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
-                         aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
-    // layed on feature coincidences to divide it on several shapes
-    std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
-    std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-        aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
-    std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
-
-    ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
-                                                aX->dir(), aY, aPointsInfo);
-
-    std::list<FeaturePtr> aFeatures;
-    CompositeFeaturePtr aSketchComposite =
-                         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theSketch);
-    for (int i = 0; i < aSketchComposite->numberOfSubs(); i++) {
-      FeaturePtr aFeature = aSketchComposite->subFeature(i);
-      if (aFeature.get() && aFeature->getKind() != SketchPlugin_Projection::ID())
-        aFeatures.push_back(aFeature);
-    }
-    ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPointsInfo);
-
-    GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPointsInfo, aShapes);
-  }
-  theObjectToPoints[theObject] = aPointsInfo;
-  theCashedShapes[theObject] = aShapes;
-}
index 90bbf7434287ccc569b500efebb80cbd849e74cc..365cda33cec49e576cd12bce33e628361c374b8d 100644 (file)
@@ -21,8 +21,9 @@
 #define SketchPlugin_Trim_H_
 
 #include "SketchPlugin.h"
+#include <SketchPlugin_Tools.h>
 
-#include "GeomAPI_IPresentable.h"
+#include <GeomAPI_IPresentable.h>
 #include <ModelAPI_IReentrant.h>
 #include <SketchPlugin_Sketch.h>
 
@@ -105,15 +106,6 @@ class SketchPlugin_Trim : public SketchPlugin_Feature, public GeomAPI_IPresentab
   /// Apply information of the message to current object. It fills selected point and object
   virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
-  typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
-                   std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
-                             std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
-
-  static void fillObjectShapes(const std::shared_ptr<ModelAPI_Object>& theObject,
-    const std::shared_ptr<ModelAPI_Object>& theSketch,
-    std::map<std::shared_ptr<ModelAPI_Object>, std::set<GeomShapePtr> >& theCashedShapes,
-    std::map<std::shared_ptr<ModelAPI_Object>, PointToRefsMap>& theObjectToPoints);
-
 private:
   bool setCoincidenceToAttribute(const AttributePtr& theAttribute,
             const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
@@ -123,18 +115,6 @@ private:
   /// \param theFeature a feature that can be set into the attribute
   bool moveTangency(const AttributePtr& theAttribute, const FeaturePtr& theFeature);
 
-  GeomShapePtr getSubShape(const std::string& theObjectAttributeId,
-                           const std::string& thePointAttributeId);
-
-  /// Returns geom point attribute of the feature bounds. It processes line or arc.
-  /// For circle feature, the result attributes are null
-  /// \param theFeature a source feature
-  /// \param theStartPointAttr an out attribute to start point
-  /// \param theStartPointAttr an out attribute to end point
-  void getFeaturePoints(const FeaturePtr& theFeature,
-                        std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
-                        std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr);
-
   /// Obtains those constraints of the feature that should be modified. output maps contain
   /// point of coincidence and attribute id to be modified after split
   /// \param theFeaturesToDelete [out] constrains that will be deleted after split
@@ -142,36 +122,12 @@ private:
   void getConstraints(std::set<std::shared_ptr<ModelAPI_Feature>>& theFeaturesToDelete,
                       std::set<FeaturePtr>& theFeaturesToUpdate);
 
-  /// Obtains references to feature point attributes and to feature,
-  /// e.g. for feature line: 1st container is
-  ///             <1st line point, list<entity_a in distance, entity_b in parallel> >
-  ///             <2nd line point, list<> >
-  ///      for feature circle 2nd container is <entity_a in Radius, entity_b in equal, ...>
-  /// \param theFeature an investigated feature
-  /// \param theRefs a container of list of referenced attributes
-  void getRefAttributes(const FeaturePtr& theFeature,
-                        std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
-                        std::list<AttributePtr>& theRefsToFeature);
-
-  /// Move constraints from attribute of base feature to attribute after modification
-  /// \param theBaseRefAttributes container of references to the attributes of base feature
-  /// \param theModifiedAttributes container of attributes placed instead of base attributes
-  /// at the same place
-  void updateRefAttConstraints(
-               const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
-               const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes,
-               std::set<std::shared_ptr<ModelAPI_Feature>>& theFeaturesToDelete);
-
   /// Remove references constraints from attribute of base feature refer to the given attribute
   /// \param theAttribute an attribute
   /// \param theModifiedAttributes modifiable container of attributes
   void removeReferencesToAttribute(const AttributePtr& theAttribute,
                   std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes);
 
-   /// Updates line length if it exist in the list
-  /// \param theFeaturesToUpdate a constraints container
-  void updateFeaturesAfterTrim(const std::set<FeaturePtr>& theFeaturesToUpdate);
-
   /// Make the base object is splitted by the point attributes
   /// \param theBaseRefAttributes container of references to the attributes of base feature
   /// \param thePoints a list of points where coincidences will be build
@@ -195,10 +151,19 @@ private:
 
   /// Make the base object is splitted by the point attributes
   /// \param thePoints a list of points where coincidences will be build
-  FeaturePtr trimCircle(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
-                  const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
-                  std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
-                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
+  /// \return new elliptic arc if it was created
+  FeaturePtr trimEllipticArc(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+               const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+               std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
+               std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
+               std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
+
+  /// Make the base object is splitted by the point attributes
+  /// \param thePoints a list of points where coincidences will be build
+  FeaturePtr trimClosed(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+                        std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
+                        std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
 
   /// Correct the first and the second point to provide condition that the first is closer to
   /// the start point and the second point - to the last end of current segment. To rearrange
@@ -238,28 +203,6 @@ private:
   void fillPointAttribute(const AttributePtr& theModifiedAttribute,
                           const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
 
-  /// Creates a line feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature,
-                               const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
-
-  /// Creates an arc feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature,
-                              const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                              const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
-
-  /// Result result of the feature to build constraint with. For arc, circle it is an edge result.
-  /// \param theFeature a feature
-  /// \return result object
-  std::shared_ptr<ModelAPI_Result> getFeatureResult(
-                                    const std::shared_ptr<ModelAPI_Feature>& theFeature);
-
 private:
   void findShapePoints(const std::string& theObjectAttributeId,
                        const std::string& thePointAttributeId,
@@ -270,7 +213,8 @@ private:
 
 private:
   std::map<std::shared_ptr<ModelAPI_Object>, std::set<GeomShapePtr> > myCashedShapes;
-  std::map<std::shared_ptr<ModelAPI_Object>, PointToRefsMap> myObjectToPoints;
+  std::map<std::shared_ptr<ModelAPI_Object>,
+           GeomAlgoAPI_ShapeTools::PointToRefsMap> myObjectToPoints;
 };
 
 #endif
index 8962cf083547a98ea3e05ad598b70b4bd22fafb9..454a476ee2a6498ceaad57ed083b46071744b8c5 100644 (file)
@@ -25,6 +25,8 @@
 #include "SketchPlugin_ConstraintDistance.h"
 #include "SketchPlugin_ConstraintRigid.h"
 #include "SketchPlugin_ConstraintTangent.h"
+#include "SketchPlugin_Ellipse.h"
+#include "SketchPlugin_EllipticArc.h"
 #include "SketchPlugin_Fillet.h"
 #include "SketchPlugin_Line.h"
 #include "SketchPlugin_MacroArc.h"
@@ -59,6 +61,7 @@
 
 #include <GeomAPI_Circ.h>
 #include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Ellipse.h>
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Vertex.h>
@@ -161,31 +164,9 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute
     if (!aOtherFea)
       return true;
 
-    if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
-      if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
-          aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
-        theError = "It refers to a %1, but %2 is neither an %3 nor %4";
-        theError.arg(SketchPlugin_Line::ID()).arg(aParamA)
-            .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
-        return false;
-      }
-    }
-    else if (aRefFea->getKind() == SketchPlugin_Arc::ID() ||
-             aRefFea->getKind() == SketchPlugin_Circle::ID()) {
-      if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
-          aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
-          aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
-        theError = "It refers to an %1, but %2 is not a %3 or an %4 or a %5";
-        theError.arg(SketchPlugin_Arc::ID()).arg(aParamA)
-            .arg(SketchPlugin_Line::ID()).arg(SketchPlugin_Arc::ID())
-            .arg(SketchPlugin_Circle::ID());
-        return false;
-      }
-    }
-    else {
-      theError = "It refers to %1, but should refer to %2 or %3 or %4";
-      theError.arg(aRefFea->getKind()).arg(SketchPlugin_Line::ID())
-          .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
+    if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
+        aOtherFea->getKind() == SketchPlugin_Line::ID()) {
+      theError = "Two segments cannot be tangent";
       return false;
     }
     return true;
@@ -198,6 +179,50 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute
   return true;
 }
 
+bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
+                                                      const std::list<std::string>& theArguments,
+                                                      Events_InfoMessage& theError) const
+{
+  if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
+    theError = "The attribute with the %1 type is not processed";
+    theError.arg(theAttribute->attributeType());
+    return false;
+  }
+
+  std::string aParamA = theArguments.front();
+  SessionPtr aMgr = ModelAPI_Session::get();
+  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+
+  FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+  AttributeRefAttrPtr aRefAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+
+  bool isObject = aRefAttr->isObject();
+  ObjectPtr anObject = aRefAttr->object();
+  if (isObject && anObject.get()) {
+    FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
+
+    AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
+    ObjectPtr aOtherObject = aOtherAttr->object();
+    FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
+    if (!aOtherFea)
+      return true;
+
+    // at least one feature should be a line
+    if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
+        aOtherFea->getKind() != SketchPlugin_Line::ID()) {
+      theError = "At least one feature should be a line";
+      return false;
+    }
+  }
+  else {
+    theError = "It uses an empty object";
+    return false;
+  }
+
+  return true;
+}
+
 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
                                              const std::list<std::string>& theArguments,
                                              Events_InfoMessage& theError) const
@@ -282,18 +307,29 @@ bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
     aType[i] = aFeature->getKind();
     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
         aFeature->getKind() != SketchPlugin_Circle::ID() &&
-        aFeature->getKind() != SketchPlugin_Arc::ID()) {
-      theError = "The %1 feature kind of attribute is wrong. It should be %2 or %3 or %4";
-      theError.arg(aFeature->getKind()).arg(SketchPlugin_Line::ID())
-          .arg(SketchPlugin_Circle::ID()).arg(SketchPlugin_Arc::ID());
+        aFeature->getKind() != SketchPlugin_Arc::ID() &&
+        aFeature->getKind() != SketchPlugin_Ellipse::ID() &&
+        aFeature->getKind() != SketchPlugin_EllipticArc::ID()) {
+      theError = "The %1 feature is not supported by the Equal constraint.";
+      theError.arg(aFeature->getKind());
       // wrong type of attribute
       return false;
     }
   }
 
-  if ((aType[0] == SketchPlugin_Line::ID() || aType[1] == SketchPlugin_Line::ID()) &&
-      aType[0] != aType[1]) {
-    theError = "Feature with kinds %1 and %2 can not be equal.";
+  bool isOk = aType[0] == aType[1];
+  if (!isOk) {
+    // circle and arc may be equal
+    isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID())
+        || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID());
+  }
+  if (!isOk) {
+    // ellipse and elliptic arc may be equal
+    isOk = (aType[0] == SketchPlugin_EllipticArc::ID() && aType[1] == SketchPlugin_Ellipse::ID())
+        || (aType[0] == SketchPlugin_Ellipse::ID() && aType[1] == SketchPlugin_EllipticArc::ID());
+  }
+  if (!isOk) {
+    theError = "Features with kinds %1 and %2 can not be equal.";
     theError.arg(aType[0]).arg(aType[1]);
     return false;
   }
@@ -570,7 +606,7 @@ bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribut
   }
 
   if(!aConstraintCoincidence.get()) {
-    theError = "Error: one of the selected point does not have coicidence.";
+    theError = "Error: one of the selected point does not have coincidence.";
     return false;
   }
 
@@ -734,7 +770,9 @@ bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttri
 
       if (aFeature->getKind() == SketchPlugin_Point::ID())
         ++aNbPoints;
-      else if (aFeature->getKind() == SketchPlugin_Line::ID())
+      else if (aFeature->getKind() == SketchPlugin_Line::ID() ||
+               aFeature->getKind() == SketchPlugin_Arc::ID() ||
+               aFeature->getKind() == SketchPlugin_EllipticArc::ID())
         ++aNbLines;
     }
   }
@@ -755,6 +793,11 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri
     theError.arg(theAttribute->attributeType());
     return false;
   }
+  FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+  AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
+  if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE())
+    return true; // not applicable for non-tangent arcs
+
   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
   AttributePtr anAttr = aRefAttr->attr();
   if (!anAttr) {
@@ -792,6 +835,50 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri
   return true;
 }
 
+bool SketchPlugin_ArcTransversalPointValidator::isValid(
+    const AttributePtr& theAttribute,
+    const std::list<std::string>& /*theArguments*/,
+    Events_InfoMessage& theError) const
+{
+  if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
+    theError = "The attribute with the %1 type is not processed";
+    theError.arg(theAttribute->attributeType());
+    return false;
+  }
+  FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+  AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
+  if (anArcTypeAttr &&
+      anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE())
+    return true; // not applicable for non-transversal arcs
+
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  AttributePtr anAttr = aRefAttr->attr();
+  if (!anAttr) {
+    theError = "The attribute %1 should be a point";
+    theError.arg(theAttribute->id());
+    return false;
+  }
+
+  FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+  const std::string& aFeatureType = anAttrFeature->getKind();
+  if (aFeatureType == SketchPlugin_Line::ID()) {
+    // selected point should be bound point of line
+    const std::string& aPntId = anAttr->id();
+    if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
+      theError = "The attribute %1 is not supported";
+      theError.arg(aPntId);
+      return false;
+    }
+  }
+  else {
+    theError = "Unable to build perpendicular arc on %1";
+    theError.arg(anAttrFeature->getKind());
+    return false;
+  }
+
+  return true;
+}
+
 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
                                                  const std::list<std::string>& theArguments,
                                                  Events_InfoMessage& theError) const
@@ -865,49 +952,46 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
   if (!anAttrFeature)
     return aValid;
 
-  std::string aKind = anAttrFeature->getKind();
-  if (aKind == SketchPlugin_Line::ID() ||
-      aKind == SketchPlugin_Arc::ID() ||
-      aKind == SketchPlugin_Circle::ID()) {
-
-    std::set<ResultPtr> anEdgeShapes;
-    ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
-    if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
-      return aValid;
-
-    // coincidences to the feature
-    std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
-    ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
-                        SketchPlugin_ConstraintCoincidence::ID(),
-                        aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
-
-    GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
-    std::shared_ptr<SketchPlugin_Feature> aSFeature =
-                                 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
-    SketchPlugin_Sketch* aSketch = aSFeature->sketch();
-
-    std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
-    std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-        aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
-    std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
-
-    typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
-                     std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
-                               std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
-    PointToRefsMap aPointsInfo;
-
-    ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
-                                                aX->dir(), aDirY, aPointsInfo);
-    int aCoincidentToFeature = (int)aPointsInfo.size();
-    if (aKind == SketchPlugin_Circle::ID())
-      aValid = aCoincidentToFeature >= 2;
-    else
-      aValid = aCoincidentToFeature >= 1;
-  }
+  std::set<ResultPtr> anEdgeShapes;
+  ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
+  if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
+    return aValid;
+
+  // coincidences to the feature
+  std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
+  ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
+                      SketchPlugin_ConstraintCoincidence::ID(),
+                      aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+
+  GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
+  std::shared_ptr<SketchPlugin_Feature> aSFeature =
+                                std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
+  if (!aSFeature)
+    return false;
+  SketchPlugin_Sketch* aSketch = aSFeature->sketch();
+
+  std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
+  std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+      aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+  std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
+  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      aData->attribute(SketchPlugin_Sketch::NORM_ID()));
+  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
+
+  typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
+                    std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
+                              std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
+  PointToRefsMap aPointsInfo;
+
+  ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
+                                              aX->dir(), aDirY, aPointsInfo);
+  int aCoincidentToFeature = (int)aPointsInfo.size();
+  if (anAttrFeature->getKind() == SketchPlugin_Circle::ID() ||
+      anAttrFeature->getKind() == SketchPlugin_Ellipse::ID())
+    aValid = aCoincidentToFeature >= 2;
+  else
+    aValid = aCoincidentToFeature >= 1;
 
   return aValid;
 }
@@ -945,12 +1029,6 @@ bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
   if (!aSketchFeature.get() || aSketchFeature->isCopy())
     return aValid;
 
-  std::string aKind = aBaseFeature->getKind();
-  if (aKind != SketchPlugin_Line::ID() &&
-      aKind != SketchPlugin_Arc::ID() &&
-      aKind != SketchPlugin_Circle::ID())
-    return aValid;
-
   // point on feature
   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
                        aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
@@ -965,8 +1043,8 @@ bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
   std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
            std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
                      std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
-  SketchPlugin_Trim::fillObjectShapes(aBaseObject, aSketch->data()->owner(),
-                                      aCashedShapes, anObjectToPoints);
+  SketchPlugin_SegmentationTools::fillObjectShapes(
+      aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints);
   const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
 
   return aShapes.size() > 1;
@@ -1043,21 +1121,31 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
     double aDot = fabs(aNormal->dot(aLineDir));
     bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
     if (!aValid)
-      theError = "Error: Edge is already in the sketch plane.";
+      theError = "Error: Line is orthogonal to the sketch plane.";
     return aValid;
   }
   else if (anEdge->isCircle() || anEdge->isArc()) {
     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
     double aDot = fabs(aNormal->dot(aCircNormal));
-    bool aValid = fabs(aDot - 1.0) < tolerance * tolerance;
+    bool aValid = aDot >= tolerance * tolerance;
+    if (!aValid)
+      theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
+                                      : "Error: Arc is orthogonal to the sketch plane.");
+    return aValid;
+  }
+  else if (anEdge->isEllipse()) {
+    std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+    std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
+    double aDot = fabs(aNormal->dot(anEllipseNormal));
+    bool aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
     if (!aValid)
-      theError.arg(anEdge->isCircle() ? "Error: Cirlce is already in the sketch plane."
-                                      : "Error: Arc is already in the sketch plane.");
+      theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
+                                      : "Error: Elliptic Arc is orthogonal to the sketch plane.");
     return aValid;
   }
 
-  theError = "Error: Selected object is not line, circle or arc.";
+  theError = "Error: Selected object is not supported for projection.";
   return false;
 }
 
index 4a7bd052576a7952bb799ef1c3169c1a83e380c5..b3fe8f57464ee41781dcfe9d114f9caaac735a89 100644 (file)
@@ -60,6 +60,24 @@ class SketchPlugin_TangentAttrValidator : public ModelAPI_AttributeValidator
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_PerpendicularAttrValidator
+ * \ingroup Validators
+ * \brief Validator for the perpendicular constraint input.
+ *
+ * Checks that two arcs are not selected for perpendicular.
+ */
+class SketchPlugin_PerpendicularAttrValidator : public ModelAPI_AttributeValidator
+{
+ public:
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 
 /**\class SketchPlugin_NotFixedValidator
  * \ingroup Validators
@@ -231,6 +249,25 @@ class SketchPlugin_ArcTangentPointValidator : public ModelAPI_AttributeValidator
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_ArcTransversalPointValidator
+ * \ingroup Validators
+ * \brief Validator for the point where the transversal arc is building.
+ *
+ * Checks that the point is a start or end point just on line or arc.
+ */
+class SketchPlugin_ArcTransversalPointValidator : public ModelAPI_AttributeValidator
+{
+ public:
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
+
 /**\class SketchPlugin_SplitValidator
  * \ingroup Validators
  * \brief Validator for the entity of the following type:
index 35073532a9aa0da21eb161a7c403823d2c46033c..3a5255ce5a4e9d144f64359858ffba8e6f8eb4f7 100644 (file)
@@ -4,14 +4,14 @@
   <context>
     <name>Sketch:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "DirX" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select a plane for the sketch</translation>
     </message>
   </context>
   <context>
     <name>Sketch:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "Features" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Sketch objects are not defined</translation>
     </message>
   </context>
   <context>
     <name>Sketch:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "External" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select the sketch plane</translation>
     </message>
   </context>
   <context>
     <name>Sketch:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "SolverDOF" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Can not compute degrees of freedom</translation>
     </message>
   </context>
   <context>
     <name>Sketch:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "SolverError" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Can not compute the solver error</translation>
     </message>
   </context>
   
+  <context>
+    <name>SketchMacroCircle:center_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a point in the viewer</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a point in the viewer</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroCircle:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a point in the viewer</translation>
+    </message>
+  </context>
   <context>
     <name>SketchMacroCircle:CircleRadius:GeomValidators_Positive</name>
     <message>
   <context>
     <name>SketchMacroCircle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "circle_center" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>A center point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMacroCircle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "FirstPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>A first point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMacroCircle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "SecondPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>A second point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMacroCircle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ThirdPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>A third point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMacroCircle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "circle_radius" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the circle radius</translation>
     </message>
   </context>
+
+  <context>
+    <name>SketchMacroArc:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:center_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a center point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_1</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an end point in the viewer.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_2</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an end point in the viewer.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:end_point_3</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an end point in the viewer.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select an end point in the viewer.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an passed point in the viewer.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_1</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a start point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroArc:start_point_2</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a start point.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroEllipse:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:first_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a first point in the viewer.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:passed_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a passed point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipse:second_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a second point.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchMacroEllipticArc:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:center</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a point.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a center point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:end_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an end point.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select an end point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchMacroEllipticArc:major_axis_point</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a major axis point.</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a major axis point.</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>SketchSplit:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a segment to split in the viewer.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchSplit:SelectedObject:SketchPlugin_SplitValidator</name>
+    <message>
+      <source>Select a segment to split in the viewer.</source>
+      <translation></translation>
+    </message>
+  </context>
   
   <context>
     <name>SketchConstraintHorizontal:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintPerpendicular:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintPerpendicular:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintRadius:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Circle is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintRadius:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintValue" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the radius</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintVertical:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchLine:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "EndPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>End point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchLine:EndPoint</name>
     <message>
-      <source>Attribute "EndPoint" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select an end point in the viewer</translation>
     </message>
   </context>
   <context>
     <name>SketchLine:StartPoint</name>
     <message>
-      <source>Attribute "StartPoint" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select a start point in the viewer</translation>
     </message>
   </context>
   <context>
     <name>SketchLine:StartPoint</name>
     <message>
-      <source>Attribute "StartPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Start point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchLine:EndPoint</name>
     <message>
-      <source>Attribute "EndPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>End point is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchLine:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "StartPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select a start point</translation>
     </message>
   </context>
   <context>
     <name>SketchPoint:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "PointCoordinates" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Point is not defined</translation>
     </message>
   </context>
   <context>
     <name>SketchPoint:PointCoordinates</name>
     <message>
-      <source>Attribute "PointCoordinates" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a point</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchPoint:PointCoordinates</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select a point</translation>
     </message>
   </context>
   <context>
     <name>SketchRectangle:RectEndPoint</name>
     <message>
-      <source>Attribute "RectEndPoint" is locked by modification value in the viewer.</source>
-      <translation>Select an end point of the rectangle</translation>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an end point of the rectangle.</translation>
     </message>
   </context>
   <context>
     <name>SketchRectangle:RectStartPoint</name>
     <message>
-      <source>Attribute "RectStartPoint" is locked by modification value in the viewer.</source>
-      <translation>Select a first point of the rectangle</translation>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a point.</translation>
     </message>
   </context>
   <context>
     <name>SketchRectangle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "RectStartPoint" is not initialized.</source>
-      <translation>Select a first point of the rectangle</translation>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select a point.</translation>
     </message>
   </context>
   <context>
-    <name>SketchRectangle:Model_FeatureValidator</name>
+    <name>SketchRectangle:RectEndPoint</name>
     <message>
-      <source>Attribute "RectEndPoint" is not initialized.</source>
-      <translation>Select an end point of the rectangle</translation>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select a point.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchRectangle:RectStartPoint</name>
+    <message>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
+      <translation>Select an point.</translation>
     </message>
   </context>
 
   <context>
     <name>SketchArc:ArcCenter</name>
     <message>
-      <source>Attribute "center_point" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select a center point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:ArcCenter</name>
     <message>
-      <source>Attribute "center_point" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Center point is not defined</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:ArcEndPoint</name>
     <message>
-      <source>Attribute "ArcEndPoint" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select an end point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:ArcPassedPoint</name>
     <message>
-      <source>Attribute "ArcPassedPoint" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select an intermediate point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:ArcStartPoint</name>
     <message>
-      <source>Attribute "ArcStartPoint" is locked by modification value in the viewer.</source>
+      <source>Attribute "%1" is locked by modification value in the viewer.</source>
       <translation>Select a start point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ArcEndPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>End point is not defined</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ArcPassedPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Intermediate point is not defined</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "center_point" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select an arc center</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator:ArcStartPoint</name>
     <message>
-      <source>Attribute "start_point" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select an arc start point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "end_point" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select an arc end point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ArcPassedPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select an arc passed point</translation>
     </message>
   </context>
   <context>
     <name>SketchArc:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ArcTangentPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select an arc tangent point</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintMirror:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Mirror line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintMirror:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintMirrorList" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Objects for mirror are not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiRotation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "AngleType" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Type of angle is not defined</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiRotation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiRotationCenter" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Rotation center is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiRotation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiRotationList" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select objects to rotate</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiRotation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiRotationAngle" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set rotation angle</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiRotation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiRotationObjects" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the number of resulting objects</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiTranslation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiTranslationEndPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>End point of translation vector is not defined</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiTranslation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiTranslationList" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Objects for translation are not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiTranslation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiTranslationStartPoint" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select a start point</translation>
     </message>
   </context>
   <context>
     <name>SketchMultiTranslation:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "MultiTranslationObjects" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select a total number of objects</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintAngle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintAngle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintAngle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "AngleValue" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the angle value</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintAngle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "AngleType" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Type of angle is not set</translation>
     </message>
   </context>
     <name>SketchConstraintCoincidence:ConstraintEntityA:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintCoincidence:ConstraintEntityB:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintCoincidence:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintCoincidence:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintDistance:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintDistance:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintDistance:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintDistance:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintDistance:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintValue" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the distance</translation>
     </message>
   </context>
     <name>SketchConstraintEqual:ConstraintEntityA:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintEqual:ConstraintEntityB:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
       <source>An empty object is used.</source>
       <translation>An empty object is used</translation>
     </message>
+    <message>
+      <source>The %1 feature is not supported by the Equal constraint.</source>
+      <translation>The %1 feature is not supported by the Equal constraint.</translation>
+    </message>
+    <message>
+      <source>Features with kinds %1 and %2 can not be equal.</source>
+      <translation>Features with kinds %1 and %2 can not be equal.</translation>
+    </message>
   </context>
   <context>
     <name>SketchConstraintEqual:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintEqual:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintLength:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintLength:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintLength:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintValue" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the length value</translation>
     </message>
   </context>
     <name>SketchConstraintMiddle:ConstraintEntityA:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintMiddle:ConstraintEntityB:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
   <context>
     <name>SketchConstraintMiddle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintMiddle:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintParallel:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintParallel:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second line is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintRigid:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Object is not selected</translation>
     </message>
   </context>
     <name>SketchConstraintTangent:ConstraintEntityA:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityA and ConstraintEntityB attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintTangent:ConstraintEntityB:PartSet_DifferentObjects</name>
     <message>
       <source>The feature uses one  object in ConstraintEntityB and ConstraintEntityA attributes.</source>
-      <translation>Diferent objects should be selected</translation>
+      <translation>Different objects should be selected</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchConstraintTangent:ConstraintEntityA:SketchPlugin_TangentAttr</name>
+    <message>
+      <source>Two segments cannot be tangent</source>
+      <translation>Two segments cannot be tangent</translation>
     </message>
   </context>
   <context>
   <context>
     <name>SketchConstraintTangent:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>First object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchConstraintTangent:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityB" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Second object is not selected</translation>
     </message>
   </context>
   <context>
     <name>SketchFillet:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintEntityA" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Select one or several points for filet</translation>
     </message>
   </context>
   <context>
     <name>SketchFillet:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ConstraintValue" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation>Set the fillet radius</translation>
     </message>
   </context>
   <context>
     <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
     <message>
-      <source>Error: one of the selected point does not have coicidence.</source>
-      <translation>One of the selected point does not have coicidence</translation>
+      <source>Error: one of the selected point does not have coincidence.</source>
+      <translation>One of the selected point does not have coincidence</translation>
     </message>
   </context>
   <context>
       <source>The attribute with the %1 type is not processed</source>
       <translation>An argument of type %1 of the projection feature is not supported</translation>
     </message>
-  </context>
-  <context>
-    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
     <message>
-      <source>The attribute %1 should be an edge</source>
-      <translation>The projected item must be an edge</translation>
+      <source>The attribute %1 should be an edge or vertex</source>
+      <translation>The projected item must be an edge or a vertex</translation>
     </message>
-  </context>
-  <context>
-    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
     <message>
       <source>There is no sketch referring to the current feature</source>
       <translation>The projection feature has no sketch</translation>
     </message>
+    <message>
+      <source>Unable to project feature from the same sketch</source>
+      <translation>Feature from the current sketch cannot be projected</translation>
+    </message>
+    <message>
+      <source>Error: Line is orthogonal to the sketch plane.</source>
+      <translation>Error: Line is orthogonal to the sketch plane.</translation>
+    </message>
+    <message>
+      <source>Error: Circle is orthogonal to the sketch plane.</source>
+      <translation>Error: Circle is orthogonal to the sketch plane.</translation>
+    </message>
+    <message>
+      <source>Error: Arc is orthogonal to the sketch plane.</source>
+      <translation>Error: Arc is orthogonal to the sketch plane.</translation>
+    </message>
+    <message>
+      <source>Error: Ellipse is orthogonal to the sketch plane.</source>
+      <translation>Error: Ellipse is orthogonal to the sketch plane.</translation>
+    </message>
+    <message>
+      <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
+      <translation>Error: Elliptic Arc is orthogonal to the sketch plane.</translation>
+    </message>
+    <message>
+      <source>Error: Selected object is not supported for projection.</source>
+      <translation>Error: Selected object is not supported for projection.</translation>
+    </message>
   </context>
-  
   <context>
     <name>SketchProjection:Model_FeatureValidator</name>
     <message>
-      <source>Attribute "ExternalFeature" is not initialized.</source>
+      <source>Attribute "%1" is not initialized.</source>
       <translation></translation>
     </message>
   </context>
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/Test3019.py b/src/SketchPlugin/Test/Test3019.py
new file mode 100644 (file)
index 0000000..a40f094
--- /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
+#
+
+"""
+    Test3019.py
+    Test case for issue #3019 "Error when load python script"
+"""
+
+from salome.shaper import model
+from SketchAPI import *
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "k", "30")
+model.addParameter(Part_1_doc, "M", "10")
+model.addParameter(Part_1_doc, "h", "20")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(15, -8.660254037843767, 15, 8.660254037843762)
+SketchLine_2 = Sketch_1.addLine(15, 8.660254037843762, 0, 0)
+SketchLine_2.setAuxiliary(True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(0, 0, 15, -8.660254037843767)
+SketchLine_3.setAuxiliary(True)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_1.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_3.startPoint(), SketchLine_1.result(), "k/2", True)
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchLine_3.startPoint(), 360, 6, True)
+[SketchLine_4, SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8] = SketchMultiRotation_1.rotated()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 10)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "M")
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_3.startPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f-SketchCircle_1_2r")], model.selection(), "h", 0)
+Point_2 = model.addPoint(Part_1_doc, "0", "0", "h/2")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "Point_1"), 19.5)
+Common_1 = model.addCommon(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1"), model.selection("SOLID", "Sphere_1_1")])
+Folder_1 = model.addFolder(Part_1_doc, Sketch_1, Extrusion_1)
+Folder_2 = model.addFolder(Part_1_doc, Point_2, Sphere_1)
+model.end()
+
+model.testNbResults(Common_1, 1)
+model.testNbSubResults(Common_1, [0])
+model.testNbSubShapes(Common_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Common_1, GeomAPI_Shape.FACE, [21])
+model.testNbSubShapes(Common_1, GeomAPI_Shape.EDGE, [114])
+model.testNbSubShapes(Common_1, GeomAPI_Shape.VERTEX, [228])
+model.testResultsVolumes(Common_1, [9302.86764641653])
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestChangeSketchPlane4.py b/src/SketchPlugin/Test/TestChangeSketchPlane4.py
new file mode 100644 (file)
index 0000000..b81dd89
--- /dev/null
@@ -0,0 +1,62 @@
+# 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()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchCircle_1 = Sketch_1.addCircle(-29.162567194092, -4.973946236013575, 24.14811574522286)
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_2.addLine(-77.4631035991525, 93.73498685458384, -26.22597517262966, 46.04636096467877)
+SketchLine_2 = Sketch_2.addLine(-26.22597517262966, 46.04636096467877, 72.15826607546271, 123.5085570887089)
+SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(72.15826607546271, 123.5085570887089, -77.4631035991525, 93.73498685458384)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection(), 50, 50)
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_2/SketchLine_2"))
+SketchProjection_1 = Sketch_3.addProjection(model.selection("EDGE", "Sketch_1/SketchCircle_1_2"), True)
+SketchEllipse_1 = SketchProjection_1.createdFeature()
+SketchLine_4 = Sketch_3.addLine(-38.4752072906812, 8.839586602068252, -81.23746009846235, -13.43622256955389)
+SketchConstraintCoincidence_4 = Sketch_3.setCoincident(SketchLine_4.startPoint(), SketchEllipse_1.result())
+SketchLine_5 = Sketch_3.addLine(-81.23746009846235, -13.43622256955389, -38.77350759536917, -18.22647561616226)
+SketchConstraintCoincidence_5 = Sketch_3.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_3.setCoincident(SketchLine_5.endPoint(), SketchEllipse_1.result())
+model.do()
+model.end()
+
+model.checkSketch(Sketch_3, 4)
+model.testNbSubFeatures(Sketch_3, "SketchConstraintCoincidence", 3)
+ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape()
+assert(ellipse1.isEdge() and ellipse1.edge().isEllipse())
+
+model.begin()
+Sketch_3.setPlane(model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_2/SketchLine_1"))
+model.end()
+model.checkSketch(Sketch_3, 4)
+model.testNbSubFeatures(Sketch_3, "SketchConstraintCoincidence", 3)
+ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape()
+assert(ellipse1.isEdge() and ellipse1.edge().isEllipse())
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestConstraintAngleEllipse.py b/src/SketchPlugin/Test/TestConstraintAngleEllipse.py
new file mode 100644 (file)
index 0000000..f795677
--- /dev/null
@@ -0,0 +1,125 @@
+# 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 constraint "Angle" applied for ellipse's axes
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-12"
+
+class TestAngleEllipse(unittest.TestCase):
+  def setUp(self):
+    axisStart = GeomAPI_Pnt2d(30., 60.)
+    axisEnd = GeomAPI_Pnt2d(80., 50.)
+    passedPoint = GeomAPI_Pnt2d(60., 60.)
+    self.myAngle = 60
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
+    self.myDOF = 5
+    self.myOX = self.mySketch.addLine("OX")
+    model.do()
+    self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    self.myCenter = macroEllipse.center()
+    self.myFocus1 = macroEllipse.focus1()
+    self.myFocus2 = macroEllipse.focus2()
+    self.myMajorAxis = macroEllipse.majorAxis()
+    self.myMajorStart = macroEllipse.majorAxisStart()
+    self.myMajorEnd = macroEllipse.majorAxisEnd()
+    self.myMinorAxis = macroEllipse.minorAxis()
+    self.myMinorStart = macroEllipse.minorAxisStart()
+    self.myMinorEnd = macroEllipse.minorAxisEnd()
+
+
+  def tearDown(self):
+    model.end()
+    self.checkDOF()
+    self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
+    self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
+    self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
+    self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
+    self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
+    self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
+    self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
+    self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
+    self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
+    self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
+    self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", 11)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+  def assertAngle(self, theStart, theEnd, theAngle):
+    dirX = (theEnd.x() - theStart.x()) / math.hypot(theEnd.x() - theStart.x(), theEnd.y() - theStart.y())
+    self.assertAlmostEqual(math.fabs(dirX), math.cos(theAngle * math.pi / 180))
+
+
+  def test_angle_major_axis(self):
+    """ Test 1. Make angle between major axis of ellipse and OX
+    """
+    self.mySketch.setAngle(self.myOX.result(), self.myMajorAxis.result(), self.myAngle)
+    self.myDOF -= 1
+    model.do()
+    self.assertAngle(self.myMajorAxis.startPoint(), self.myMajorAxis.endPoint(), self.myAngle)
+    self.assertAngle(self.myMajorStart.coordinates(), self.myMajorEnd.coordinates(), self.myAngle)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintAngle", 1)
+
+  def test_angle_minor_axis(self):
+    """ Test 2. Make angle between minor axis of ellipse and OX
+    """
+    self.mySketch.setAngle(self.myOX.result(), self.myMinorAxis.result(), self.myAngle)
+    self.myDOF -= 1
+    model.do()
+    self.assertAngle(self.myMinorAxis.startPoint(), self.myMinorAxis.endPoint(), self.myAngle)
+    self.assertAngle(self.myMinorStart.coordinates(), self.myMinorEnd.coordinates(), self.myAngle)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintAngle", 1)
+
+  def test_angle_ellipse_axes(self):
+    """ Test 3. Set angle between axes of an ellipse. Check conflicting constraints.
+    """
+    self.mySketch.setAngle(self.myMajorAxis.result(), self.myMinorAxis.result(), self.myAngle)
+    model.end()
+    self.assertNotEqual(self.mySketch.solverError(), "")
+    model.undo()
+    model.begin()
+
+
+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/TestConstraintCoincidenceEllipse.py b/src/SketchPlugin/Test/TestConstraintCoincidenceEllipse.py
new file mode 100644 (file)
index 0000000..16f0f8a
--- /dev/null
@@ -0,0 +1,241 @@
+# 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 constraint coincidence applied for ellipse and its sub-results
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-12"
+
+class TestCoincidenceEllipse(unittest.TestCase):
+  def setUp(self):
+    axisStart = GeomAPI_Pnt2d(30., 60.)
+    axisEnd = GeomAPI_Pnt2d(80., 50.)
+    passedPoint = GeomAPI_Pnt2d(60., 60.)
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
+    self.myDOF = 5
+    self.myOrigin = self.mySketch.addPoint("Origin")
+    self.myOX = self.mySketch.addLine("OX")
+    model.do()
+    self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    self.myCenter = macroEllipse.center()
+    self.myFocus1 = macroEllipse.focus1()
+    self.myFocus2 = macroEllipse.focus2()
+    self.myMajorAxis = macroEllipse.majorAxis()
+    self.myMajorStart = macroEllipse.majorAxisStart()
+    self.myMajorEnd = macroEllipse.majorAxisEnd()
+    self.myMinorAxis = macroEllipse.minorAxis()
+    self.myMinorStart = macroEllipse.minorAxisStart()
+    self.myMinorEnd = macroEllipse.minorAxisEnd()
+    self.myExpectFailure = False
+
+  def tearDown(self):
+    model.end()
+    if self.myExpectFailure:
+      assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+      model.undo()
+    else:
+      self.checkDOF()
+      self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
+      self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
+      self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
+      self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
+      self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
+      self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
+      self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
+      self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
+      self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
+      self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
+      self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
+      model.testNbSubFeatures(self.mySketch, "SketchPoint", 8)
+      model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+      model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+      model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", 11)
+      model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointFixing(self, thePoint):
+    self.mySketch.setCoincident(thePoint, self.myOrigin.coordinates())
+    self.myDOF -= 2
+    model.do()
+    if not self.myExpectFailure:
+      self.assertPoints(thePoint, self.myOrigin.coordinates())
+      self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
+      self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+  def checkPointOnAxis(self, thePoint):
+    self.mySketch.setCoincident(thePoint, self.myOX.result())
+    self.myDOF -= 1
+    model.do()
+    if not self.myExpectFailure:
+      self.assertAlmostEqual(thePoint.y(), 0.0)
+      self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
+      self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
+
+  def checkPointOnLine(self, thePoint, theLineStart, theLineEnd):
+    vecP = [thePoint.x() - theLineStart.x(), thePoint.y() - theLineStart.y()]
+    vecL = [theLineEnd.x() - theLineStart.x(), theLineEnd.y() - theLineStart.y()]
+    dist = math.fabs(vecP[0] * vecL[1] - vecP[1] * vecL[0]) / math.hypot(vecL[0], vecL[1])
+
+    self.assertAlmostEqual(dist, 0.0)
+    self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
+    self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
+
+  def checkPointOnEllipse(self, thePoint, theEllipse):
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  thePoint)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  thePoint)
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * theEllipse.majorRadius().value(), 7)
+
+
+  def test_concident_center(self):
+    """ Test 1. Make center of ellipse coincident with the Origin
+    """
+    self.checkPointFixing(self.myCenter.coordinates())
+
+  def test_coincident_first_focus(self):
+    """ Test 2. Make first focus of ellipse coincident with the Origin
+    """
+    self.checkPointFixing(self.myFocus1.coordinates())
+
+  def test_coincident_second_focus(self):
+    """ Test 3. Make second focus of ellipse coincident with the Origin
+    """
+    self.checkPointFixing(self.myFocus2.coordinates())
+
+  def test_coincident_major_axis_start(self):
+    """ Test 4. Make start point on the major axis of ellipse coincident with the Origin
+    """
+    self.checkPointFixing(self.myMajorStart.coordinates())
+
+  def test_coincident_major_axis_end(self):
+    """ Test 5. Make end point on the major axis of ellipse coincident with the Origin
+    """
+    self.checkPointFixing(self.myMajorEnd.coordinates())
+
+  def test_coincident_minor_axis_start(self):
+    """ Test 6. Make start point on the minor axis of ellipse coincident with the Origin
+    """
+    self.checkPointFixing(self.myMinorStart.coordinates())
+
+  def test_coincident_minor_axis_end(self):
+    """ Test 7. Make end point on the minor axis of ellipse coincident with the Origin.
+                Check solver is failed to compute the coincidence.
+    """
+    self.myExpectFailure = True
+    self.checkPointFixing(self.myMinorEnd.coordinates())
+
+
+  def test_center_on_line(self):
+    """ Test 8. Make center of ellipse coincident with the OX
+    """
+    self.checkPointOnAxis(self.myCenter.coordinates())
+
+  def test_first_focus_on_line(self):
+    """ Test 9. Make first focus of ellipse coincident with the OX
+    """
+    self.checkPointOnAxis(self.myFocus1.coordinates())
+
+  def test_second_focus_on_line(self):
+    """ Test 10. Make second focus of ellipse coincident with the OX
+    """
+    self.checkPointOnAxis(self.myFocus2.coordinates())
+
+  def test_major_axis_start_on_line(self):
+    """ Test 11. Make start point on the major axis of ellipse coincident with the OX
+    """
+    self.checkPointOnAxis(self.myMajorStart.coordinates())
+
+  def test_major_axis_end_on_line(self):
+    """ Test 12. Make end point on the major axis of ellipse coincident with the OX
+    """
+    self.checkPointOnAxis(self.myMajorEnd.coordinates())
+
+  def test_minor_axis_start_on_line(self):
+    """ Test 13. Make start point on the minor axis of ellipse coincident with the OX
+    """
+    self.checkPointOnAxis(self.myMinorStart.coordinates())
+
+  def test_minor_axis_end_on_line(self):
+    """ Test 14. Make end point on the minor axis of ellipse coincident with the OX
+    """
+    self.myExpectFailure = True
+    self.checkPointOnAxis(self.myMinorEnd.coordinates())
+
+
+  def test_origin_on_major_axis(self):
+    """ Test 15. Make origin coincident with the major axis of the ellipse
+    """
+    self.mySketch.setCoincident(self.myMajorAxis.result(), self.myOrigin.coordinates())
+    self.myDOF -= 1
+    model.do()
+    self.checkPointOnLine(self.myOrigin.coordinates(), self.myMajorStart.coordinates(), self.myMajorEnd.coordinates())
+
+  def test_origin_on_minor_axis(self):
+    """ Test 16. Make origin coincident with the minor axis of the ellipse
+    """
+    self.mySketch.setCoincident(self.myMinorAxis.result(), self.myOrigin.coordinates())
+    self.myDOF -= 1
+    model.end()
+    # solver shows wrong result
+    assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+    model.undo()
+
+    # move ellipse and set coincidence once again
+    model.begin()
+    self.mySketch.move(self.myMinorStart, 20, 10)
+    model.do()
+    self.mySketch.setCoincident(self.myMinorAxis.results()[-1], self.myOrigin.coordinates())
+    model.do()
+    self.checkPointOnLine(self.myOrigin.coordinates(), self.myMinorStart.coordinates(), self.myMinorEnd.coordinates())
+
+
+  def test_origin_on_ellipse(self):
+    """ Test 17. Make origin coincident with the ellipse
+    """
+    self.mySketch.setCoincident(self.myEllipse.results()[-1], self.myOrigin.coordinates())
+    self.myDOF -= 1
+    model.do()
+    self.checkPointOnEllipse(self.myOrigin.coordinates(), self.myEllipse)
+
+
+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/TestConstraintCoincidenceEllipticArc.py b/src/SketchPlugin/Test/TestConstraintCoincidenceEllipticArc.py
new file mode 100644 (file)
index 0000000..c7eb779
--- /dev/null
@@ -0,0 +1,264 @@
+# 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 constraint coincidence applied for elliptic arc and its sub-results
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-02"
+
+class TestCoincidenceEllipticArc(unittest.TestCase):
+  def setUp(self):
+    center = GeomAPI_Pnt2d(-10., 5.)
+    axisEnd = GeomAPI_Pnt2d(40., -5.)
+    startPoint = GeomAPI_Pnt2d(20., 5.)
+    endPoint = GeomAPI_Pnt2d(-40., 5.)
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipticArc = self.mySketch.addEllipticArc(center, axisEnd, startPoint, endPoint, False)
+    self.myDOF = 7
+    self.myOrigin = self.mySketch.addPoint("Origin")
+    self.myOX = self.mySketch.addLine("OX")
+    model.do()
+    self.myEllipticArc = SketchAPI_EllipticArc(model.lastSubFeature(self.mySketch, "SketchEllipticArc"))
+    self.myCenter = macroEllipticArc.center()
+    self.myFocus1 = macroEllipticArc.focus1()
+    self.myFocus2 = macroEllipticArc.focus2()
+    self.myMajorAxis = macroEllipticArc.majorAxis()
+    self.myMajorStart = macroEllipticArc.majorAxisStart()
+    self.myMajorEnd = macroEllipticArc.majorAxisEnd()
+    self.myMinorAxis = macroEllipticArc.minorAxis()
+    self.myMinorStart = macroEllipticArc.minorAxisStart()
+    self.myMinorEnd = macroEllipticArc.minorAxisEnd()
+    self.myExpectFailure = False
+
+  def tearDown(self):
+    model.end()
+    if self.myExpectFailure:
+      assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+      model.undo()
+    else:
+      self.checkDOF()
+      self.assertPoints(self.myCenter.coordinates(), self.myEllipticArc.center())
+      self.assertPoints(self.myFocus1.coordinates(), self.myEllipticArc.firstFocus())
+      self.assertPoints(self.myFocus2.coordinates(), self.myEllipticArc.secondFocus())
+      self.assertPoints(self.myMajorStart.coordinates(), self.myEllipticArc.majorAxisNegative())
+      self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipticArc.majorAxisPositive())
+      self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipticArc.majorAxisNegative())
+      self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipticArc.majorAxisPositive())
+      self.assertPoints(self.myMinorStart.coordinates(), self.myEllipticArc.minorAxisNegative())
+      self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipticArc.minorAxisPositive())
+      self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipticArc.minorAxisNegative())
+      self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipticArc.minorAxisPositive())
+      model.testNbSubFeatures(self.mySketch, "SketchPoint", 8)
+      model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+      model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+      model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", 11)
+      model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointFixing(self, thePoint):
+    self.mySketch.setCoincident(thePoint, self.myOrigin.coordinates())
+    self.myDOF -= 2
+    model.do()
+    if not self.myExpectFailure:
+      self.assertPoints(thePoint, self.myOrigin.coordinates())
+      self.assertGreater(self.myEllipticArc.majorRadius().value(), 0.0)
+      self.assertGreater(self.myEllipticArc.minorRadius().value(), 0.0)
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+  def checkPointOnAxis(self, thePoint):
+    self.mySketch.setCoincident(thePoint, self.myOX.result())
+    self.myDOF -= 1
+    model.do()
+    if not self.myExpectFailure:
+      self.assertAlmostEqual(thePoint.y(), 0.0)
+      self.assertGreater(self.myEllipticArc.majorRadius().value(), 0.0)
+      self.assertGreater(self.myEllipticArc.minorRadius().value(), 0.0)
+
+  def checkPointOnLine(self, thePoint, theLineStart, theLineEnd):
+    vecP = [thePoint.x() - theLineStart.x(), thePoint.y() - theLineStart.y()]
+    vecL = [theLineEnd.x() - theLineStart.x(), theLineEnd.y() - theLineStart.y()]
+    dist = math.fabs(vecP[0] * vecL[1] - vecP[1] * vecL[0]) / math.hypot(vecL[0], vecL[1])
+
+    self.assertAlmostEqual(dist, 0.0)
+    self.assertGreater(self.myEllipticArc.majorRadius().value(), 0.0)
+    self.assertGreater(self.myEllipticArc.minorRadius().value(), 0.0)
+
+  def checkPointOnEllipse(self, thePoint, theEllipse):
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  thePoint)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  thePoint)
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * theEllipse.majorRadius().value(), 7)
+
+
+  def test_concident_center(self):
+    """ Test 1. Make center of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myCenter.coordinates())
+
+  def test_coincident_first_focus(self):
+    """ Test 2. Make first focus of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myFocus1.coordinates())
+
+  def test_coincident_second_focus(self):
+    """ Test 3. Make second focus of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myFocus2.coordinates())
+
+  def test_coincident_major_axis_start(self):
+    """ Test 4. Make start point on the major axis of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myMajorStart.coordinates())
+
+  def test_coincident_major_axis_end(self):
+    """ Test 5. Make end point on the major axis of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myMajorEnd.coordinates())
+
+  def test_coincident_minor_axis_start(self):
+    """ Test 6. Make start point on the minor axis of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myMinorStart.coordinates())
+
+  def test_coincident_minor_axis_end(self):
+    """ Test 7. Make end point on the minor axis of elliptic arc coincident with the Origin.
+                Check solver is failed to compute the coincidence.
+    """
+    self.myExpectFailure = True
+    self.checkPointFixing(self.myMinorEnd.coordinates())
+
+  def test_coincident_start(self):
+    """ Test 8. Make start point of elliptic arc coincident with the Origin.
+                Check solver is failed to compute the coincidence.
+    """
+    self.myExpectFailure = True
+    self.checkPointFixing(self.myEllipticArc.startPoint())
+
+  def test_coincident_end(self):
+    """ Test 9. Make end point of elliptic arc coincident with the Origin
+    """
+    self.checkPointFixing(self.myEllipticArc.endPoint())
+
+
+  def test_center_on_line(self):
+    """ Test 10. Make center of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myCenter.coordinates())
+
+  def test_first_focus_on_line(self):
+    """ Test 11. Make first focus of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myFocus1.coordinates())
+
+  def test_second_focus_on_line(self):
+    """ Test 12. Make second focus of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myFocus2.coordinates())
+
+  def test_major_axis_start_on_line(self):
+    """ Test 13. Make start point on the major axis of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myMajorStart.coordinates())
+
+  def test_major_axis_end_on_line(self):
+    """ Test 14. Make end point on the major axis of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myMajorEnd.coordinates())
+
+  def test_minor_axis_start_on_line(self):
+    """ Test 15. Make start point on the minor axis of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myMinorStart.coordinates())
+
+  def test_minor_axis_end_on_line(self):
+    """ Test 16. Make end point on the minor axis of elliptic arc coincident with the OX
+    """
+    self.myExpectFailure = True
+    self.checkPointOnAxis(self.myMinorEnd.coordinates())
+
+  def test_coincident_start_on_line(self):
+    """ Test 17. Make start point of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myEllipticArc.startPoint())
+
+  def test_coincident_end_on_line(self):
+    """ Test 18. Make end point of elliptic arc coincident with the OX
+    """
+    self.checkPointOnAxis(self.myEllipticArc.endPoint())
+
+
+  def test_origin_on_major_axis(self):
+    """ Test 19. Make origin coincident with the major axis of the elliptic arc
+    """
+    self.mySketch.setCoincident(self.myMajorAxis.result(), self.myOrigin.coordinates())
+    self.myDOF -= 1
+    model.do()
+    self.checkPointOnLine(self.myOrigin.coordinates(), self.myMajorStart.coordinates(), self.myMajorEnd.coordinates())
+
+  def test_origin_on_minor_axis(self):
+    """ Test 20. Make origin coincident with the minor axis of the elliptic arc
+    """
+    self.mySketch.setCoincident(self.myMinorAxis.result(), self.myOrigin.coordinates())
+    self.myDOF -= 1
+    model.end()
+    # solver shows wrong result
+    assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+    model.undo()
+
+    # move elliptic arc and set coincidence once again
+    model.begin()
+    self.mySketch.move(self.myMinorStart, 20, 10)
+    model.do()
+    self.mySketch.setCoincident(self.myMinorAxis.results()[-1], self.myOrigin.coordinates())
+    model.do()
+    self.checkPointOnLine(self.myOrigin.coordinates(), self.myMinorStart.coordinates(), self.myMinorEnd.coordinates())
+
+
+  def test_origin_on_ellipse(self):
+    """ Test 21. Make origin coincident with the elliptic arc
+    """
+    self.mySketch.setCoincident(self.myEllipticArc.results()[-1], self.myOrigin.coordinates())
+    self.myDOF -= 1
+    model.do()
+    self.checkPointOnEllipse(self.myOrigin.coordinates(), self.myEllipticArc)
+
+
+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/TestConstraintCollinearEllipse.py b/src/SketchPlugin/Test/TestConstraintCollinearEllipse.py
new file mode 100644 (file)
index 0000000..4964f32
--- /dev/null
@@ -0,0 +1,134 @@
+# 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 constraint "Collinear" applied for ellipse's axes
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-18"
+
+class TestCollinearEllipse(unittest.TestCase):
+  def setUp(self):
+    axisStart = GeomAPI_Pnt2d(30., 60.)
+    axisEnd = GeomAPI_Pnt2d(80., 50.)
+    passedPoint = GeomAPI_Pnt2d(60., 60.)
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
+    self.myDOF = 5
+    self.myOX = self.mySketch.addLine("OX")
+    model.do()
+    self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    self.myCenter = macroEllipse.center()
+    self.myFocus1 = macroEllipse.focus1()
+    self.myFocus2 = macroEllipse.focus2()
+    self.myMajorAxis = macroEllipse.majorAxis()
+    self.myMajorStart = macroEllipse.majorAxisStart()
+    self.myMajorEnd = macroEllipse.majorAxisEnd()
+    self.myMinorAxis = macroEllipse.minorAxis()
+    self.myMinorStart = macroEllipse.minorAxisStart()
+    self.myMinorEnd = macroEllipse.minorAxisEnd()
+
+
+  def tearDown(self):
+    model.end()
+    self.checkDOF()
+    self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
+    self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
+    self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
+    self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
+    self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
+    self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
+    self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
+    self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
+    self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
+    self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
+    self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", 11)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+
+  def test_collinear_major_axis(self):
+    """ Test 1. Make major axis of ellipse collinear with OX
+    """
+    self.mySketch.setCollinear(self.myOX.result(), self.myMajorAxis.result())
+    self.myDOF -= 2
+    model.do()
+    self.assertAlmostEqual(self.myMajorAxis.startPoint().y(), 0)
+    self.assertAlmostEqual(self.myMajorAxis.endPoint().y(), 0)
+    self.assertAlmostEqual(self.myMajorStart.coordinates().y(), 0)
+    self.assertAlmostEqual(self.myMajorEnd.coordinates().y(), 0)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCollinear", 1)
+
+  def test_collinear_minor_axis(self):
+    """ Test 2. Make minor axis of ellipse collinear with OX
+    """
+    self.mySketch.setCollinear(self.myOX.result(), self.myMinorAxis.result())
+    self.myDOF -= 2
+    model.end()
+    # solver shows wrong result
+    assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+    model.undo()
+
+    model.begin()
+    self.mySketch.move(self.myMinorStart.coordinates(), 0, 70)
+    self.mySketch.move(self.myMinorEnd.coordinates(), 50, 70)
+    model.do()
+    self.mySketch.setCollinear(self.myOX.result(), self.myMinorAxis.result())
+    model.do()
+    self.assertAlmostEqual(self.myMinorAxis.startPoint().y(), 0)
+    self.assertAlmostEqual(self.myMinorAxis.endPoint().y(), 0)
+    self.assertAlmostEqual(self.myMinorStart.coordinates().y(), 0)
+    self.assertAlmostEqual(self.myMinorEnd.coordinates().y(), 0)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCollinear", 1)
+
+  def test_collinear_ellipse_axes(self):
+    """ Test 3. Set collinear axes of an ellipse. Check conflicting constraints.
+    """
+    self.mySketch.setCollinear(self.myMajorAxis, self.myMinorAxis)
+    model.end()
+    self.assertNotEqual(self.mySketch.solverError(), "")
+    model.undo()
+    model.begin()
+
+
+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/TestConstraintDistanceEllipse.py b/src/SketchPlugin/Test/TestConstraintDistanceEllipse.py
new file mode 100644 (file)
index 0000000..6ec2980
--- /dev/null
@@ -0,0 +1,199 @@
+# 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 constraint "Distance" applied sub-elements of an ellipse
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-12"
+
+class TestDistanceEllipse(unittest.TestCase):
+  def setUp(self):
+    axisStart = GeomAPI_Pnt2d(20., 60.)
+    axisEnd = GeomAPI_Pnt2d(80., 50.)
+    passedPoint = GeomAPI_Pnt2d(60., 70.)
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
+    self.myDOF = 5
+    self.myOrigin = self.mySketch.addPoint("Origin")
+    self.myOX = self.mySketch.addLine("OX")
+    model.do()
+    self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    self.myCenter = macroEllipse.center()
+    self.myFocus1 = macroEllipse.focus1()
+    self.myFocus2 = macroEllipse.focus2()
+    self.myMajorAxis = macroEllipse.majorAxis()
+    self.myMajorStart = macroEllipse.majorAxisStart()
+    self.myMajorEnd = macroEllipse.majorAxisEnd()
+    self.myMinorAxis = macroEllipse.minorAxis()
+    self.myMinorStart = macroEllipse.minorAxisStart()
+    self.myMinorEnd = macroEllipse.minorAxisEnd()
+    self.myExpectFailure = False
+    self.myDistance = 20
+
+  def tearDown(self):
+    model.end()
+    if self.myExpectFailure:
+      assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+      model.undo()
+    else:
+      self.checkDOF()
+      self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
+      self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
+      self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
+      self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
+      self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
+      self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
+      self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
+      self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
+      self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
+      self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
+      self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
+      model.testNbSubFeatures(self.mySketch, "SketchPoint", 8)
+      model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+      model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+      model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", 11)
+      model.testNbSubFeatures(self.mySketch, "SketchConstraintDistance", 1)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointPointDistance(self, thePoint1, thePoint2):
+    self.mySketch.setDistance(thePoint1, thePoint2, self.myDistance)
+    self.myDOF -= 1
+    model.do()
+    if not self.myExpectFailure:
+      self.assertAlmostEqual(model.distancePointPoint(thePoint1, thePoint2), self.myDistance)
+      self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
+      self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
+
+  def checkPointLineDistance(self, thePoint, theLine):
+    self.mySketch.setDistance(thePoint, theLine.result(), self.myDistance)
+    self.myDOF -= 1
+    model.do()
+    self.assertAlmostEqual(model.distancePointLine(thePoint, theLine), self.myDistance)
+    self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
+    self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+
+  def test_distance_center(self):
+    """ Test 1. Set distance to the Origin from the center of ellipse
+    """
+    self.checkPointPointDistance(self.myCenter.coordinates(), self.myOrigin.coordinates())
+
+  def test_distance_first_focus(self):
+    """ Test 2. Set distance to the Origin from the first focus of ellipse
+    """
+    self.checkPointPointDistance(self.myFocus1.coordinates(), self.myOrigin.coordinates())
+
+  def test_distance_second_focus(self):
+    """ Test 3. Set distance to the Origin from the second focus of ellipse
+    """
+    self.checkPointPointDistance(self.myFocus2.coordinates(), self.myOrigin.coordinates())
+
+  def test_distance_major_axis_start(self):
+    """ Test 4. Set distance to the Origin from the start point on the major axis of ellipse
+    """
+    self.checkPointPointDistance(self.myMajorStart.coordinates(), self.myOrigin.coordinates())
+
+  def test_distance_major_axis_end(self):
+    """ Test 5. Set distance to the Origin from the end point on the major axis of ellipse
+    """
+    self.checkPointPointDistance(self.myMajorEnd.coordinates(), self.myOrigin.coordinates())
+
+  def test_distance_minor_axis_start(self):
+    """ Test 6. Set distance to the Origin from the start point on the minor axis of ellipse
+    """
+    self.checkPointPointDistance(self.myMinorStart.coordinates(), self.myOrigin.coordinates())
+
+  def test_distance_minor_axis_end(self):
+    """ Test 7. Set distance to the Origin from the end point on the minor axis of ellipse
+    """
+    self.myExpectFailure = True
+    self.checkPointPointDistance(self.myMinorEnd.coordinates(), self.myOrigin.coordinates())
+
+
+  def test_distance_center_to_line(self):
+    """ Test 8. Set distance from theOX to the center of ellipse
+    """
+    self.checkPointLineDistance(self.myCenter.coordinates(), self.myOX)
+
+  def test_distance_first_focus_to_line(self):
+    """ Test 9. Set distance from theOX to the first focus of ellipse
+    """
+    self.checkPointLineDistance(self.myFocus1.coordinates(), self.myOX)
+
+  def test_distance_second_focus_to_line(self):
+    """ Test 10. Set distance from theOX to the second focus of ellipse
+    """
+    self.checkPointLineDistance(self.myFocus2.coordinates(), self.myOX)
+
+  def test_distance_major_axis_start_to_line(self):
+    """ Test 11. Set distance from theOX to the start point on the major axis of ellipse
+    """
+    self.checkPointLineDistance(self.myMajorStart.coordinates(), self.myOX)
+
+  def test_distance_major_axis_end_to_line(self):
+    """ Test 12. Set distance from theOX to the end point on the major axis of ellipse
+    """
+    self.checkPointLineDistance(self.myMajorEnd.coordinates(), self.myOX)
+
+  def test_distance_minor_axis_start_to_line(self):
+    """ Test 13. Set distance from theOX to the start point on the minor axis of ellipse
+    """
+    self.checkPointLineDistance(self.myMinorStart.coordinates(), self.myOX)
+
+  def test_distance_minor_axis_end_to_line(self):
+    """ Test 14. Set distance from theOX to the end point on the minor axis of ellipse
+    """
+    self.myDistance = 150
+    self.checkPointLineDistance(self.myMinorEnd.coordinates(), self.myOX)
+
+
+  def test_distance_origin_to_major_axis(self):
+    """ Test 15. Set distance from the Origin to the major axis of the ellipse
+    """
+    self.checkPointLineDistance(self.myOrigin.coordinates(), self.myMajorAxis)
+
+  def test_distance_origin_to_minor_axis(self):
+    """ Test 16. Set distance from the Origin to the minor axis of the ellipse
+    """
+    self.checkPointLineDistance(self.myOrigin.coordinates(), self.myMinorAxis)
+
+
+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/TestConstraintEqualEllipse.py b/src/SketchPlugin/Test/TestConstraintEqualEllipse.py
new file mode 100644 (file)
index 0000000..46bf795
--- /dev/null
@@ -0,0 +1,73 @@
+# 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 constraint "Equal" applied to the pair of ellipses
+"""
+
+from salome.shaper import model
+import math
+
+DOF = 0
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchEllipse_1 = Sketch_1.addEllipse(-27.88698315421018, 6.197107367602265, -8.725072906579975, 15.87998754592604, 11.10896680773502)
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchLine_1, SketchLine_2] = SketchEllipse_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+DOF += 5
+SketchEllipse_2 = Sketch_1.addEllipse(15.14848467636108, -15.95181340919842, 21.12194589112931, -20.27742325437541, 9.877448119278471)
+[SketchPoint_8, SketchPoint_9, SketchPoint_10, SketchPoint_11, SketchPoint_12, SketchPoint_13, SketchPoint_14, SketchLine_3, SketchLine_4] = SketchEllipse_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+DOF += 5
+SketchEllipticArc_1 = Sketch_1.addEllipticArc(49.62123971365138, 13.34935433264426, 64.40153327705804, 5.234651852264014, 68.29270956846837, 8.653290073592997, 32.00833375829566, 14.82599483073829, False)
+[SketchPoint_15, SketchPoint_16, SketchPoint_17, SketchPoint_18, SketchPoint_19, SketchPoint_20, SketchPoint_21, SketchLine_5, SketchLine_6] = SketchEllipticArc_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+DOF += 7
+SketchEllipticArc_2 = Sketch_1.addEllipticArc(7.849720447428027, 32.28934430567138, 19.71732573395684, 29.13862828729395, 12.53096585507117, 17.93622281956947, 4.288678376456463, 46.71874313598852, True)
+[SketchPoint_22, SketchPoint_23, SketchPoint_24, SketchPoint_25, SketchPoint_26, SketchPoint_27, SketchPoint_28, SketchLine_7, SketchLine_8] = SketchEllipticArc_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+DOF += 7
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchEllipse_1.result(), SketchEllipse_2.result())
+DOF -= 2
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchEllipse_1.result(), SketchEllipticArc_1.result())
+DOF -= 2
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchEllipticArc_1.result(), SketchEllipticArc_2.result())
+DOF -= 2
+model.do()
+model.end()
+
+TOLERANCE = 1.e-7
+
+dist1 = model.distancePointPoint(SketchEllipse_1.majorAxisNegative(), SketchEllipse_1.majorAxisPositive())
+dist2 = model.distancePointPoint(SketchEllipse_2.majorAxisNegative(), SketchEllipse_2.majorAxisPositive())
+dist3 = model.distancePointPoint(SketchEllipticArc_1.majorAxisNegative(), SketchEllipticArc_1.majorAxisPositive())
+dist4 = model.distancePointPoint(SketchEllipticArc_2.majorAxisNegative(), SketchEllipticArc_2.majorAxisPositive())
+assert(math.fabs(dist1 - dist2) < TOLERANCE)
+assert(math.fabs(dist1 - dist3) < TOLERANCE)
+assert(math.fabs(dist1 - dist4) < TOLERANCE)
+
+dist1 = model.distancePointPoint(SketchEllipse_1.minorAxisNegative(), SketchEllipse_1.minorAxisPositive())
+dist2 = model.distancePointPoint(SketchEllipse_2.minorAxisNegative(), SketchEllipse_2.minorAxisPositive())
+dist3 = model.distancePointPoint(SketchEllipticArc_1.minorAxisNegative(), SketchEllipticArc_1.minorAxisPositive())
+dist4 = model.distancePointPoint(SketchEllipticArc_2.minorAxisNegative(), SketchEllipticArc_2.minorAxisPositive())
+assert(math.fabs(dist1 - dist2) < TOLERANCE)
+assert(math.fabs(dist1 - dist3) < TOLERANCE)
+assert(math.fabs(dist1 - dist4) < TOLERANCE)
+
+assert(model.dof(Sketch_1) == DOF)
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py b/src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py
new file mode 100644 (file)
index 0000000..2688932
--- /dev/null
@@ -0,0 +1,252 @@
+# 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 middle point on an arc
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from GeomAPI import GeomAPI_Dir2d
+
+__updated__ = "2019-09-03"
+
+class TestMiddlePointOnArc(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myTestPassed = True
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myArc = self.mySketch.addArc(50, 50, 70, 50, 50, 70, False)
+    self.myLine = self.mySketch.addLine(55, 60, 50, 0)
+    self.myDOF = 9
+    model.do()
+    self.checkDOF()
+
+  def tearDown(self):
+    if self.myTestPassed:
+      model.assertArcValidity(self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkDOF()
+    model.end()
+    assert(model.checkPythonDump())
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkMiddlePoint(self, thePoint, theArc):
+    self.myTestPassed = False
+    # check point on arc
+    dist = thePoint.pnt().distance(theArc.center().pnt())
+    NB_DIGITS = 7 - math.floor(math.log10(theArc.radius().value()))
+    self.assertAlmostEqual(dist, theArc.radius().value(), NB_DIGITS)
+    # check middle point
+    dirPC = GeomAPI_Dir2d(thePoint.x() - theArc.center().x(),
+                          thePoint.y() - theArc.center().y())
+    dirSC = GeomAPI_Dir2d(theArc.startPoint().x() - theArc.center().x(),
+                          theArc.startPoint().y() - theArc.center().y())
+    dirEC = GeomAPI_Dir2d(theArc.endPoint().x() - theArc.center().x(),
+                          theArc.endPoint().y() - theArc.center().y())
+    angleSP = dirSC.angle(dirPC)
+    anglePE = dirPC.angle(dirEC)
+    self.assertAlmostEqual(angleSP, anglePE)
+    self.assertEqual(angleSP < 0, theArc.reversed().value())
+    self.myTestPassed = True
+
+  def rotatePoint(self, thePoint, theCenter, theAngle):
+    dirX = thePoint.x() - theCenter.x()
+    dirY = thePoint.y() - theCenter.y()
+    newX = theCenter.x() + dirX * math.cos(theAngle) - dirY * math.sin(theAngle)
+    newY = theCenter.y() + dirX * math.sin(theAngle) + dirY * math.cos(theAngle)
+    self.mySketch.move(thePoint, newX, newY)
+
+  def moveArc(self):
+    ANGLE_STEP = math.pi * 5.0 / 180.0
+    ANGLE_THRESHOLD = math.pi
+    # move start point of the arc clockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), -ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+    # move start point of the arc conterclockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+
+    # move end point of the arc clockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), -ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+    # move end point of the arc conterclockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+
+    # move center of the arc
+    DELTA = [1.0, 1.0]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    DELTA = [-1.0, 1.0]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+  def moveLine(self):
+    DELTA = [1.0, 0.0]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    DELTA = [0.0, 1.0]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+
+  def test_middle_point_PA(self):
+    """ Test 1. Set middle point constraint (point is the first argument)
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+
+  def test_middle_point_AP(self):
+    """ Test 2. Set middle point constraint (point is the second argument)
+    """
+    self.mySketch.setMiddlePoint(self.myArc.results()[1], self.myLine.startPoint())
+    self.myDOF -= 2
+    model.do()
+
+  def test_coincident_middle_point(self):
+    """ Test 3. Set middle point constraint for the point already coincident with the arc
+    """
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+    model.do()
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+
+  def test_middle_point_coincident(self):
+    """ Test 4. Set concidence of the point and the arc which are already constrained with middle point
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    model.do()
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+
+  @unittest.expectedFailure
+  def test_middle_point_limitation(self):
+    """ Test 5. Check middle point fails if the point's coordinates are equal to the arc boundary point
+    """
+    self.myLine.startPoint().setValue(self.myArc.endPoint().pnt())
+    model.do()
+    coincidence = self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+    # this check will fail due to the limitation of PlanGCS
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+  def test_middle_point_move_arc(self):
+    """ Test 6. Set middle point constraint and move arc
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveArc()
+
+  def test_middle_point_coincidence_move_arc(self):
+    """ Test 7. Set coincidence and middle point constraint and move arc
+    """
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+    model.do()
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveArc()
+
+  def test_middle_point_move_line(self):
+    """ Test 8. Set middle point constraint and move line
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveLine()
+
+  def test_middle_point_coincidence_move_line(self):
+    """ Test 9. Set coincidence and middle point constraint and move line
+    """
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+    model.do()
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveLine()
+
+  def test_remove_middle_point(self):
+    """ Test 10. Set and then remove middle point constraint
+    """
+    mp = self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+    self.myDOF -= 2
+    model.do()
+    model.assertArcValidity(self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkDOF()
+    # remove middle point
+    self.myDocument.removeFeature(mp.feature())
+    self.myDOF += 2
+    model.do()
+    self.checkDOF()
+    # set flag False to avoid checking middle point constraint in tearDown() method
+    self.myTestPassed = False
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py b/src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py
new file mode 100644 (file)
index 0000000..e9f4d35
--- /dev/null
@@ -0,0 +1,288 @@
+# 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 middle point on an elliptic arc
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-02"
+
+class TestMiddlePointOnEllipticArc(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myTestPassed = True
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myArc = self.mySketch.addEllipticArc(30, 20, 50, 30, 45, 40, 5, 6.11485435, False)
+    self.myLine = self.mySketch.addLine(10, 40, 40, 80)
+    self.myDOF = 11
+    model.do()
+    self.checkDOF()
+
+  def tearDown(self):
+    if self.myTestPassed:
+      self.assertArc(self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkDOF()
+    model.end()
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def toPeriod(self, theValue):
+    while theValue < -math.pi:
+      theValue += 2.0 * math.pi
+    while theValue >= math.pi:
+      theValue -= 2.0 * math.pi
+    return theValue
+
+  def checkMiddlePoint(self, thePoint, theArc):
+    self.myTestPassed = False
+    anEllipse = theArc.defaultResult().shape().edge().ellipse()
+    # check point on ellipse
+    self.checkPointOnEllipse(thePoint, anEllipse)
+    # check angles
+    TOLERANCE = 1.e-5
+    startAngle = 0; startPoint = GeomAPI_Pnt(theArc.startPoint().x(), theArc.startPoint().y(), 0)
+    startAngle = anEllipse.parameter(startPoint, TOLERANCE, startAngle)
+    endAngle = 0; endPoint = GeomAPI_Pnt(theArc.endPoint().x(), theArc.endPoint().y(), 0)
+    endAngle = anEllipse.parameter(endPoint, TOLERANCE, endAngle)
+    midAngle = 0; midPoint = GeomAPI_Pnt(thePoint.x(), thePoint.y(), 0)
+    midAngle = anEllipse.parameter(midPoint, TOLERANCE, midAngle)
+    diffMS = self.toPeriod(midAngle - startAngle)
+    diffEM = self.toPeriod(endAngle - midAngle)
+    self.assertAlmostEqual(diffMS, diffEM)
+    self.assertEqual(diffMS < 0, theArc.reversed().value())
+    self.myTestPassed = True
+
+  def checkPointOnEllipse(self, theCoordinates, theEllipse):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    if issubclass(type(theEllipse), SketchAPI_Ellipse):
+      majorRad = theEllipse.majorRadius().value()
+    else:
+      majorRad = theEllipse.majorRadius()
+    NB_DIGITS = 7 - math.floor(math.log10(majorRad))
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * majorRad, NB_DIGITS)
+
+  def assertArc(self, theArc):
+    anEllipse = theArc.defaultResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(theArc.startPoint(), anEllipse)
+    self.checkPointOnEllipse(theArc.endPoint(), anEllipse)
+
+  def rotatePoint(self, thePoint, theCenter, theAngle):
+    dirX = thePoint.x() - theCenter.x()
+    dirY = thePoint.y() - theCenter.y()
+    newX = theCenter.x() + dirX * math.cos(theAngle) - dirY * math.sin(theAngle)
+    newY = theCenter.y() + dirX * math.sin(theAngle) + dirY * math.cos(theAngle)
+    self.mySketch.move(thePoint, newX, newY)
+
+  def moveArc(self):
+    ANGLE_STEP = math.pi * 5.0 / 180.0
+    ANGLE_THRESHOLD = math.pi / 2.0
+    # move start point of the arc clockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), -ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+    # move start point of the arc conterclockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+
+    # move end point of the arc clockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), -ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+    # move end point of the arc conterclockwise
+    fullAngle = 0.0
+    while fullAngle < ANGLE_THRESHOLD:
+      self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), ANGLE_STEP)
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      fullAngle += ANGLE_STEP
+
+    # move center of the arc
+    DELTA = [0.1, 0.1]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    DELTA = [-0.1, 0.1]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+  def moveLine(self):
+    DELTA = [0.1, 0.0]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    DELTA = [0.0, 0.1]
+    for i in range(0, 40):
+      if i == 10 or i == 30:
+        DELTA = [-DELTA[0], -DELTA[1]]
+      self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
+      model.do()
+      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+
+  def test_middle_point_PA(self):
+    """ Test 1. Set middle point constraint (point is the first argument)
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+
+  def test_middle_point_AP(self):
+    """ Test 2. Set middle point constraint (point is the second argument)
+    """
+    self.mySketch.setMiddlePoint(self.myArc.results()[-1], self.myLine.startPoint())
+    self.myDOF -= 2
+    model.do()
+
+  def test_coincident_middle_point(self):
+    """ Test 3. Set middle point constraint for the point already coincident with the arc
+    """
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[-1])
+    model.do()
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+
+  def test_middle_point_coincident(self):
+    """ Test 4. Set concidence of the point and the arc which are already constrained with middle point
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    model.do()
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+
+  @unittest.expectedFailure
+  def test_middle_point_limitation(self):
+    """ Test 5. Check middle point fails if the point's coordinates are equal to the arc start point
+    """
+    self.myLine.startPoint().setValue(self.myArc.startPoint().pnt())
+    model.do()
+    coincidence = self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+    # this check will fail due to the limitation of PlanGCS
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+  def test_middle_point_equal_start(self):
+    """ Test 6. Check middle point does not fail if the point's coordinates are equal to the arc end point
+    """
+    self.myLine.startPoint().setValue(self.myArc.endPoint().pnt())
+    model.do()
+    coincidence = self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+
+  def test_middle_point_move_arc(self):
+    """ Test 7. Set middle point constraint and move arc
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveArc()
+
+  def test_middle_point_coincidence_move_arc(self):
+    """ Test 8. Set coincidence and middle point constraint and move arc
+    """
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[-1])
+    model.do()
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveArc()
+
+  def test_middle_point_move_line(self):
+    """ Test 9. Set middle point constraint and move line
+    """
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveLine()
+
+  def test_middle_point_coincidence_move_line(self):
+    """ Test 10. Set coincidence and middle point constraint and move line
+    """
+    self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[-1])
+    model.do()
+    self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.moveLine()
+
+  def test_remove_middle_point(self):
+    """ Test 11. Set and then remove middle point constraint
+    """
+    mp = self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[-1])
+    self.myDOF -= 2
+    model.do()
+    self.assertArc(self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkDOF()
+    # remove middle point
+    self.myDocument.removeFeature(mp.feature())
+    self.myDOF += 2
+    model.do()
+    self.checkDOF()
+    # set flag False to avoid checking middle point constraint in tearDown() method
+    self.myTestPassed = False
+
+
+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/TestConstraintPerpendicularArcLine.py b/src/SketchPlugin/Test/TestConstraintPerpendicularArcLine.py
new file mode 100644 (file)
index 0000000..c0fd9b3
--- /dev/null
@@ -0,0 +1,54 @@
+# 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()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(-35, -10, 20)
+SketchLine_1 = Sketch_1.addLine(-21, 2, 24, 21)
+SketchLine_2 = Sketch_1.addLine(24, 21, 20, -30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchArc_1 = Sketch_1.addArc(25, -30, 42, -34, 13, -17.31142245955048, False)
+model.do()
+
+# check error on perpendicularity of circle and arc
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchCircle_1.results()[1], SketchArc_1.results()[1])
+model.do()
+assert(SketchConstraintPerpendicular_1.feature().error() != "")
+
+# avoid the failure
+Part_1_doc.removeFeature(SketchConstraintPerpendicular_1.feature())
+model.do()
+assert(Sketch_1.feature().error() == "")
+
+# set correct constraints
+SketchConstraintPerpendicular_2 = Sketch_1.setPerpendicular(SketchCircle_1.results()[1], SketchLine_1.result())
+SketchConstraintPerpendicular_3 = Sketch_1.setPerpendicular(SketchLine_2.result(), SketchArc_1.results()[1])
+model.do()
+
+TOLERANCE = 1.e-7
+assert(model.distancePointLine(SketchCircle_1.center(), SketchLine_1) < TOLERANCE)
+assert(model.distancePointLine(SketchArc_1.center(), SketchLine_2) < TOLERANCE)
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestConstraintPerpendicularEllipseLine.py b/src/SketchPlugin/Test/TestConstraintPerpendicularEllipseLine.py
new file mode 100644 (file)
index 0000000..4a9678b
--- /dev/null
@@ -0,0 +1,76 @@
+# 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
+import math
+from GeomAPI import *
+
+TOLERANCE = 1.e-7
+
+def checkPerpendicular(theLine, theEllipse):
+    focus1 = theEllipse.firstFocus()
+    focus2 = theEllipse.secondFocus()
+    pf1 = theLine.project(focus1)
+    pf2 = theLine.project(focus2)
+    dist1 = focus1.distance(pf1)
+    dist2 = focus2.distance(pf2)
+    if math.fabs(dist1 - dist2) < TOLERANCE:
+        # no need further check, the line is equal to one of the ellipses axis
+        return
+    x = (dist2 * pf1.x() - dist1 * pf2.x()) / (dist2 - dist1)
+    y = (dist2 * pf1.y() - dist1 * pf2.y()) / (dist2 - dist1)
+    pnt = GeomAPI_Pnt(x, y, 0)
+    # check point on ellipse
+    majorRad = theEllipse.majorRadius()
+    assert(math.fabs(pnt.distance(focus1) + pnt.distance(focus2) - 2.0 * majorRad) < TOLERANCE * majorRad)
+
+
+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(-40, 10, -20, 30)
+SketchArc_1 = Sketch_1.addArc(25, -30, 42, -34, 13, -17.31142245955048, False)
+SketchEllipse_1 = Sketch_1.addEllipse(-50, 0, -30, -5, 15)
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchLine_2, SketchLine_3] = SketchEllipse_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+SketchEllipticArc_1 = Sketch_1.addEllipticArc(5, 30, -5, 45, -7, 47, 15, 33.68010611, False)
+[SketchPoint_8, SketchPoint_9, SketchPoint_10, SketchPoint_11, SketchPoint_12, SketchPoint_13, SketchPoint_14, SketchLine_4, SketchLine_5] = SketchEllipticArc_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+
+# check error on perpendicularity of arc and elliptic arc
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchArc_1.results()[1], SketchEllipticArc_1.result())
+model.do()
+assert(SketchConstraintPerpendicular_1.feature().error() != "")
+
+# avoid the failure
+Part_1_doc.removeFeature(SketchConstraintPerpendicular_1.feature())
+model.do()
+assert(Sketch_1.feature().error() == "")
+
+# set correct constraints
+SketchConstraintPerpendicular_2 = Sketch_1.setPerpendicular(SketchEllipticArc_1.result(), SketchLine_1.result())
+SketchConstraintPerpendicular_3 = Sketch_1.setPerpendicular(SketchLine_1.result(), SketchEllipse_1.result())
+model.do()
+
+checkPerpendicular(SketchLine_1.defaultResult().shape().edge().line(), SketchEllipse_1.defaultResult().shape().edge().ellipse())
+checkPerpendicular(SketchLine_1.defaultResult().shape().edge().line(), SketchEllipticArc_1.defaultResult().shape().edge().ellipse())
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestConstraintTangentEllipse.py b/src/SketchPlugin/Test/TestConstraintTangentEllipse.py
new file mode 100644 (file)
index 0000000..04f9a18
--- /dev/null
@@ -0,0 +1,354 @@
+# 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 constraint "Tangent" applied to ellipse and another entity
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-20"
+
+class TestTangentEllipse(unittest.TestCase):
+  def setUp(self):
+    axisStart = GeomAPI_Pnt2d(20., 60.)
+    axisEnd = GeomAPI_Pnt2d(80., 50.)
+    passedPoint = GeomAPI_Pnt2d(60., 70.)
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
+    model.do()
+    self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    self.myCenter = macroEllipse.center()
+    self.myFocus1 = macroEllipse.focus1()
+    self.myFocus2 = macroEllipse.focus2()
+    self.myMajorAxis = macroEllipse.majorAxis()
+    self.myMajorStart = macroEllipse.majorAxisStart()
+    self.myMajorEnd = macroEllipse.majorAxisEnd()
+    self.myMinorAxis = macroEllipse.minorAxis()
+    self.myMinorStart = macroEllipse.minorAxisStart()
+    self.myMinorEnd = macroEllipse.minorAxisEnd()
+
+    self.myDOF = 5
+    self.myNbPoints = 7
+    self.myNbLines = 2
+    self.myNbArcs = 0
+    self.myNbCircles = 0
+    self.myNbEllipses = 1
+    self.myNbInternals = 11
+    self.myNbCoincidence = 0
+    self.myNbTangency = 0
+
+  def tearDown(self):
+    model.end()
+    self.checkDOF()
+    self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
+    self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
+    self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
+    self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
+    self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
+    self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
+    self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
+    self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
+    self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
+    self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
+    self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+    model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternals)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidence)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", self.myNbTangency)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def assertTangentLineEllipse(self, theLine, theEllipse):
+    aLine = GeomAPI_Lin2d(theLine.startPoint().pnt(), theLine.endPoint().pnt())
+    projF1 = aLine.project(theEllipse.firstFocus().pnt())
+    projF2 = aLine.project(theEllipse.secondFocus().pnt())
+
+    distF1P1 = model.distancePointPoint(theEllipse.firstFocus(), projF1)
+    distF2P2 = model.distancePointPoint(theEllipse.secondFocus(), projF2)
+
+    tgPoint = GeomAPI_Pnt2d((projF1.x() * distF2P2 + projF2.x() * distF1P1) / (distF1P1 + distF2P2), (projF1.y() * distF2P2 + projF2.y() * distF1P1) / (distF1P1 + distF2P2))
+    distF1T = model.distancePointPoint(theEllipse.firstFocus(), tgPoint)
+    distF2T = model.distancePointPoint(theEllipse.secondFocus(), tgPoint)
+    self.assertAlmostEqual(distF1T + distF2T, 2 * theEllipse.majorRadius().value())
+
+  def assertTangentCircleEllipse(self, theCircle, theEllipse):
+    axis = GeomAPI_Dir2d(theEllipse.firstFocus().x() - theEllipse.center().x(), theEllipse.firstFocus().y() - theEllipse.center().y())
+    anEllipse = GeomAPI_Ellipse2d(theEllipse.center().pnt(), axis, theEllipse.majorRadius().value(), theEllipse.minorRadius().value())
+    aCircle = GeomAPI_Circ2d(theCircle.center().pnt(), GeomAPI_Dir2d(1, 0), theCircle.radius().value())
+
+    pOnE = GeomAPI_Pnt2d(0, 0)
+    pOnC = GeomAPI_Pnt2d(0, 0)
+    anEllipse.distance(aCircle, pOnE, pOnC)
+    self.assertAlmostEqual(model.distancePointPoint(pOnE, theCircle.center()), theCircle.radius().value())
+
+    dist1 = model.distancePointPoint(pOnC, theEllipse.firstFocus())
+    dist2 = model.distancePointPoint(pOnC, theEllipse.secondFocus())
+    self.assertAlmostEqual(dist1 + dist2, 2 * theEllipse.majorRadius().value())
+
+  def assertTangentEllipses(self, theEllipse1, theEllipse2):
+    axis1 = GeomAPI_Dir2d(theEllipse1.firstFocus().x() - theEllipse1.center().x(), theEllipse1.firstFocus().y() - theEllipse1.center().y())
+    anEllipse1 = GeomAPI_Ellipse2d(theEllipse1.center().pnt(), axis1, theEllipse1.majorRadius().value(), theEllipse1.minorRadius().value())
+    axis2 = GeomAPI_Dir2d(theEllipse2.firstFocus().x() - theEllipse2.center().x(), theEllipse2.firstFocus().y() - theEllipse2.center().y())
+    anEllipse2 = GeomAPI_Ellipse2d(theEllipse2.center().pnt(), axis2, theEllipse2.majorRadius().value(), theEllipse2.minorRadius().value())
+
+    p1 = GeomAPI_Pnt2d(0, 0)
+    p2 = GeomAPI_Pnt2d(0, 0)
+    anEllipse1.distance(anEllipse2, p1, p2)
+
+    dist1 = model.distancePointPoint(p2, theEllipse1.firstFocus())
+    dist2 = model.distancePointPoint(p2, theEllipse1.secondFocus())
+    self.assertAlmostEqual(dist1 + dist2, 2 * theEllipse1.majorRadius().value())
+
+    dist1 = model.distancePointPoint(p1, theEllipse2.firstFocus())
+    dist2 = model.distancePointPoint(p1, theEllipse2.secondFocus())
+    self.assertAlmostEqual(dist1 + dist2, 2 * theEllipse2.majorRadius().value())
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+
+  def test_line_tangent(self):
+    """ Test 1. Set tangency between ellipse and a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 90, 40)
+    self.myNbLines += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+  def test_line_coincident_then_tangent(self):
+    """ Test 2. Set tangency between ellipse and a line, if the extremity of the line is coincident with the ellipse
+    """
+    aLine = self.mySketch.addLine(10, 10, 90, 40)
+    self.mySketch.setCoincident(aLine.endPoint(), self.myEllipse.result())
+    self.myNbLines += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+  def test_line_tangent_then_coincident(self):
+    """ Test 3. Set tangency between ellipse and a line, after that apply coincidence of extremity of the line and the ellipse's curve
+    """
+    aLine = self.mySketch.addLine(10, 10, 90, 40)
+    self.myNbLines += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.mySketch.setCoincident(aLine.startPoint(), self.myEllipse.result())
+    self.myNbCoincidence += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+  def test_line_tangent_then_remove_coincidence(self):
+    """ Test 4. Set tangency between ellipse and a line, which have a coincident point, then remove this coincidence
+    """
+    aLine = self.mySketch.addLine(10, 10, 90, 40)
+    aCoincidence = self.mySketch.setCoincident(aLine.endPoint(), self.myEllipse.result())
+    self.myNbLines += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.myDocument.removeFeature(aCoincidence.feature())
+    self.myNbCoincidence -= 1
+    self.myDOF += 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+  def test_circle_tangent(self):
+    """ Test 5. Set tangency between ellipse and a circle
+    """
+    aCircle = self.mySketch.addCircle(30, 10, 20)
+    self.myNbCircles += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), aCircle.defaultResult())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(aCircle, self.myEllipse)
+
+
+  def test_circle_coincident_then_tangent(self):
+    """ Test 6. Set tangency between ellipse and a circle, if the circle is coincident with start point of ellipse's minor axis
+    """
+    aCircle = self.mySketch.addCircle(30, 10, 20)
+    self.mySketch.setCoincident(self.myMinorStart.coordinates(), aCircle.defaultResult())
+    self.myNbCircles += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 2
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), aCircle.defaultResult())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(aCircle, self.myEllipse)
+    self.assertAlmostEqual(model.distancePointPoint(aCircle.center(), self.myMinorStart.coordinates()), aCircle.radius().value())
+
+
+  def test_arc_tangent(self):
+    """ Test 7. Set tangency between ellipse and a circular arc
+    """
+    anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+    self.myNbArcs += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+  def test_arc_coincident_then_tangent(self):
+    """ Test 8. Set tangency between ellipse and an arc, if the extremity of the arc is coincident with the ellipse
+    """
+    anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+    self.mySketch.setCoincident(anArc.endPoint(), self.myEllipse.result())
+    self.myNbArcs += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+  def test_arc_tangent_then_coincident(self):
+    """ Test 9. Set tangency between ellipse and an arc, after that apply coincidence of extremity of the arc and the ellipse's curve
+    """
+    anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+    self.myNbArcs += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.mySketch.setCoincident(anArc.startPoint(), self.myEllipse.result())
+    self.myNbCoincidence += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+  def test_arc_tangent_then_remove_coincidence(self):
+    """ Test 10. Set tangency between ellipse and an arc, which have a coincident point, then remove this coincidence
+    """
+    anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+    aCoincidence = self.mySketch.setCoincident(anArc.endPoint(), self.myEllipse.result())
+    self.myNbArcs += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.myDocument.removeFeature(aCoincidence.feature())
+    self.myNbCoincidence -= 1
+    self.myDOF += 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+  def test_ellipse_tangent(self):
+    """ Test 11. Set tangency between two ellipses
+    """
+    anEllipse = self.mySketch.addEllipse(10, 10, 20, -50, 20)
+    self.myNbEllipses += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipse.result(), anEllipse.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentEllipses(anEllipse, self.myEllipse)
+
+
+
+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/TestConstraintTangentEllipticArc.py b/src/SketchPlugin/Test/TestConstraintTangentEllipticArc.py
new file mode 100644 (file)
index 0000000..77f0fd8
--- /dev/null
@@ -0,0 +1,458 @@
+# 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 constraint "Tangent" applied to elliptic arc and another entity
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-04"
+
+class TestTangentEllipticArc(unittest.TestCase):
+  def setUp(self):
+    center = GeomAPI_Pnt2d(30., 20.)
+    axisEnd = GeomAPI_Pnt2d(50., 30.)
+    startPoint = GeomAPI_Pnt2d(45, 40)
+    endPoint = GeomAPI_Pnt2d(5, 6.11485435)
+
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    macroEllipticArc = self.mySketch.addEllipticArc(center, axisEnd, startPoint, endPoint, False)
+    model.do()
+    self.myEllipticArc = SketchAPI_EllipticArc(model.lastSubFeature(self.mySketch, "SketchEllipticArc"))
+    self.myCenter = macroEllipticArc.center()
+    self.myFocus1 = macroEllipticArc.focus1()
+    self.myFocus2 = macroEllipticArc.focus2()
+    self.myMajorAxis = macroEllipticArc.majorAxis()
+    self.myMajorStart = macroEllipticArc.majorAxisStart()
+    self.myMajorEnd = macroEllipticArc.majorAxisEnd()
+    self.myMinorAxis = macroEllipticArc.minorAxis()
+    self.myMinorStart = macroEllipticArc.minorAxisStart()
+    self.myMinorEnd = macroEllipticArc.minorAxisEnd()
+
+    self.myDOF = 7
+    self.myNbPoints = 7
+    self.myNbLines = 2
+    self.myNbArcs = 0
+    self.myNbCircles = 0
+    self.myNbEllipses = 0
+    self.myNbEllipticArcs = 1
+    self.myNbInternals = 11
+    self.myNbCoincidence = 0
+    self.myNbTangency = 0
+
+  def tearDown(self):
+    model.end()
+    self.checkDOF()
+    self.assertPoints(self.myCenter.coordinates(), self.myEllipticArc.center())
+    self.assertPoints(self.myFocus1.coordinates(), self.myEllipticArc.firstFocus())
+    self.assertPoints(self.myFocus2.coordinates(), self.myEllipticArc.secondFocus())
+    self.assertPoints(self.myMajorStart.coordinates(), self.myEllipticArc.majorAxisNegative())
+    self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipticArc.majorAxisPositive())
+    self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipticArc.majorAxisNegative())
+    self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipticArc.majorAxisPositive())
+    self.assertPoints(self.myMinorStart.coordinates(), self.myEllipticArc.minorAxisNegative())
+    self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipticArc.minorAxisPositive())
+    self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipticArc.minorAxisNegative())
+    self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipticArc.minorAxisPositive())
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+    model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", self.myNbEllipticArcs)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternals)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidence)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", self.myNbTangency)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def assertTangentLineEllipse(self, theLine, theEllipticArc):
+    aLine = GeomAPI_Lin2d(theLine.startPoint().pnt(), theLine.endPoint().pnt())
+    projF1 = aLine.project(theEllipticArc.firstFocus().pnt())
+    projF2 = aLine.project(theEllipticArc.secondFocus().pnt())
+
+    distF1P1 = model.distancePointPoint(theEllipticArc.firstFocus(), projF1)
+    distF2P2 = model.distancePointPoint(theEllipticArc.secondFocus(), projF2)
+
+    tgPoint = GeomAPI_Pnt2d((projF1.x() * distF2P2 + projF2.x() * distF1P1) / (distF1P1 + distF2P2), (projF1.y() * distF2P2 + projF2.y() * distF1P1) / (distF1P1 + distF2P2))
+    distF1T = model.distancePointPoint(theEllipticArc.firstFocus(), tgPoint)
+    distF2T = model.distancePointPoint(theEllipticArc.secondFocus(), tgPoint)
+    NB_DIGITS = 7 - math.floor(math.log10(theEllipticArc.majorRadius().value()))
+    self.assertAlmostEqual(distF1T + distF2T, 2 * theEllipticArc.majorRadius().value(), NB_DIGITS)
+
+  def assertTangentCircleEllipse(self, theCircle, theEllipticArc):
+    axis = GeomAPI_Dir2d(theEllipticArc.firstFocus().x() - theEllipticArc.center().x(), theEllipticArc.firstFocus().y() - theEllipticArc.center().y())
+    anEllipticArc = GeomAPI_Ellipse2d(theEllipticArc.center().pnt(), axis, theEllipticArc.majorRadius().value(), theEllipticArc.minorRadius().value())
+    aCircle = GeomAPI_Circ2d(theCircle.center().pnt(), GeomAPI_Dir2d(1, 0), theCircle.radius().value())
+
+    pOnE = GeomAPI_Pnt2d(0, 0)
+    pOnC = GeomAPI_Pnt2d(0, 0)
+    anEllipticArc.distance(aCircle, pOnE, pOnC)
+    self.assertAlmostEqual(model.distancePointPoint(pOnE, theCircle.center()), theCircle.radius().value())
+
+    dist1 = model.distancePointPoint(pOnC, theEllipticArc.firstFocus())
+    dist2 = model.distancePointPoint(pOnC, theEllipticArc.secondFocus())
+    NB_DIGITS = 7 - math.floor(math.log10(theEllipticArc.majorRadius().value()))
+    self.assertAlmostEqual(dist1 + dist2, 2 * theEllipticArc.majorRadius().value(), NB_DIGITS)
+
+  def assertTangentEllipses(self, theEllipticArc1, theEllipticArc2):
+    axis1 = GeomAPI_Dir2d(theEllipticArc1.firstFocus().x() - theEllipticArc1.center().x(), theEllipticArc1.firstFocus().y() - theEllipticArc1.center().y())
+    anEllipticArc1 = GeomAPI_Ellipse2d(theEllipticArc1.center().pnt(), axis1, theEllipticArc1.majorRadius().value(), theEllipticArc1.minorRadius().value())
+    axis2 = GeomAPI_Dir2d(theEllipticArc2.firstFocus().x() - theEllipticArc2.center().x(), theEllipticArc2.firstFocus().y() - theEllipticArc2.center().y())
+    anEllipticArc2 = GeomAPI_Ellipse2d(theEllipticArc2.center().pnt(), axis2, theEllipticArc2.majorRadius().value(), theEllipticArc2.minorRadius().value())
+
+    p1 = GeomAPI_Pnt2d(0, 0)
+    p2 = GeomAPI_Pnt2d(0, 0)
+    anEllipticArc1.distance(anEllipticArc2, p1, p2)
+
+    dist1 = model.distancePointPoint(p2, theEllipticArc1.firstFocus())
+    dist2 = model.distancePointPoint(p2, theEllipticArc1.secondFocus())
+    NB_DIGITS = 7 - math.floor(math.log10(theEllipticArc1.majorRadius().value()))
+    self.assertAlmostEqual(dist1 + dist2, 2 * theEllipticArc1.majorRadius().value())
+
+    dist1 = model.distancePointPoint(p1, theEllipticArc2.firstFocus())
+    dist2 = model.distancePointPoint(p1, theEllipticArc2.secondFocus())
+    NB_DIGITS = 7 - math.floor(math.log10(theEllipticArc2.majorRadius().value()))
+    self.assertAlmostEqual(dist1 + dist2, 2 * theEllipticArc2.majorRadius().value(), NB_DIGITS)
+
+  def assertPoints(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 6)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 6)
+
+
+  def test_line_tangent(self):
+    """ Test 1. Set tangency between elliptic arc and a line
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    self.myNbLines += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_line_coincident_then_tangent(self):
+    """ Test 2. Set tangency between elliptic arc and a line, if the extremity of the line is coincident with the elliptic arc
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    self.mySketch.setCoincident(aLine.endPoint(), self.myEllipticArc.result())
+    self.myNbLines += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_line_tangent_then_coincident(self):
+    """ Test 3. Set tangency between elliptic arc and a line, after that apply coincidence of extremity of the line and the elliptic arc's curve
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    self.myNbLines += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.mySketch.setCoincident(aLine.startPoint(), self.myEllipticArc.result())
+    self.myNbCoincidence += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_line_tangent_then_remove_coincidence(self):
+    """ Test 4. Set tangency between elliptic arc and a line, which have a coincident point, then remove this coincidence
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    aCoincidence = self.mySketch.setCoincident(aLine.endPoint(), self.myEllipticArc.result())
+    self.myNbLines += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.myDocument.removeFeature(aCoincidence.feature())
+    self.myNbCoincidence -= 1
+    self.myDOF += 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_line_coincident_point_then_tangent(self):
+    """ Test 5. Set tangency between elliptic arc and a line, if the extremity of the line is coincident with the start point of elliptic arc
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    self.mySketch.setCoincident(aLine.endPoint(), self.myEllipticArc.startPoint())
+    self.myNbLines += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 2
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_line_tangent_then_coincident_point(self):
+    """ Test 6. Set tangency between elliptic arc and a line, after that apply coincidence of extremities of the line and the elliptic arc
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    self.myNbLines += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+    self.mySketch.setCoincident(aLine.startPoint(), self.myEllipticArc.startPoint())
+    self.myNbCoincidence += 1
+    self.myDOF -= 2
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_line_tangent_then_remove_coincidence_on_extremity(self):
+    """ Test 7. Set tangency between elliptic arc and a line, which have a coincident boundary point, then remove this coincidence
+    """
+    aLine = self.mySketch.addLine(10, -10, 90, 40)
+    aCoincidence = self.mySketch.setCoincident(aLine.endPoint(), self.myEllipticArc.endPoint())
+    self.myNbLines += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 2
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aLine.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.myDocument.removeFeature(aCoincidence.feature())
+    self.myNbCoincidence -= 1
+    self.myDOF += 2
+    model.do()
+
+    self.assertTangentLineEllipse(aLine, self.myEllipticArc)
+
+
+  def test_circle_tangent(self):
+    """ Test 8. Set tangency between elliptic arc and a circle
+    """
+    aCircle = self.mySketch.addCircle(30, 10, 20)
+    self.myNbCircles += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aCircle.defaultResult())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(aCircle, self.myEllipticArc)
+
+
+  def test_circle_coincident_then_tangent(self):
+    """ Test 9. Set tangency between elliptic arc and a circle, if the circle is coincident with start point of elliptic arc's minor axis
+    """
+    aCircle = self.mySketch.addCircle(30, 10, 20)
+    self.mySketch.setCoincident(self.myEllipticArc.startPoint(), aCircle.defaultResult())
+    self.myNbCircles += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 2
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), aCircle.defaultResult())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(aCircle, self.myEllipticArc)
+    self.assertAlmostEqual(model.distancePointPoint(aCircle.center(), self.myEllipticArc.startPoint()), aCircle.radius().value())
+
+
+  def test_arc_tangent(self):
+    """ Test 10. Set tangency between elliptic arc and a circular arc
+    """
+    anArc = self.mySketch.addArc(30, -10, 40, -10, 20, -10, False)
+    self.myNbArcs += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipticArc)
+
+
+  def test_arc_coincident_then_tangent(self):
+    """ Test 11. Set tangency between elliptic arc and an arc, if the extremities of the arcs are coincident
+    """
+    anArc = self.mySketch.addArc(30, -10, 40, -10, 20, -10, False)
+    self.mySketch.setCoincident(anArc.endPoint(), self.myEllipticArc.startPoint())
+    self.myNbArcs += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipticArc)
+
+
+  def test_arc_tangent_then_coincident(self):
+    """ Test 12. Set tangency between elliptic arc and an arc, after that apply coincidence of extremities of the arcs
+    """
+    anArc = self.mySketch.addArc(30, -10, 40, -10, 20, -10, False)
+    self.myNbArcs += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.mySketch.setCoincident(anArc.startPoint(), self.myEllipticArc.startPoint())
+    self.myNbCoincidence += 1
+    self.myDOF -= 2
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipticArc)
+
+
+  def test_arc_tangent_then_remove_coincidence(self):
+    """ Test 13. Set tangency between elliptic arc and an arc, which have a coincident point, then remove this coincidence
+    """
+    anArc = self.mySketch.addArc(30, -10, 40, -10, 20, -10, False)
+    aCoincidence = self.mySketch.setCoincident(anArc.endPoint(), self.myEllipticArc.endPoint())
+    self.myNbArcs += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anArc.results()[-1])
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.myDocument.removeFeature(aCoincidence.feature())
+    self.myNbCoincidence -= 1
+    self.myDOF += 1
+    model.do()
+
+    self.assertTangentCircleEllipse(anArc, self.myEllipticArc)
+
+
+  def test_ellipse_tangent(self):
+    """ Test 14. Set tangency between ellipse and elliptic arc
+    """
+    anEllipse = self.mySketch.addEllipse(-30, 10, -10, 0, 20)
+    self.myNbEllipses += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anEllipse.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentEllipses(anEllipse, self.myEllipticArc)
+
+
+  def test_elliptic_arcs_tangent(self):
+    """ Test 15. Set tangency between two elliptic arcs
+    """
+    anEllipticArc = self.mySketch.addEllipticArc(35, 20, 60, 30, 40, 40, 20, -0.4890968089561491, True)
+    self.myNbEllipticArcs += 1
+    self.myDOF += 7
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anEllipticArc.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentEllipses(anEllipticArc, self.myEllipticArc)
+
+
+  def test_elliptic_arcs_coincident_then_tangent(self):
+    """ Test 16. Set tangency between two elliptic arcs, if their extremities are coincident
+    """
+    anEllipticArc = self.mySketch.addEllipticArc(35, 20, 60, 30, 40, 40, 20, -0.4890968089561491, True)
+    self.mySketch.setCoincident(anEllipticArc.startPoint(), self.myEllipticArc.endPoint())
+    self.myNbEllipticArcs += 1
+    self.myNbCoincidence += 1
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.setTangent(self.myEllipticArc.result(), anEllipticArc.result())
+    self.myNbTangency += 1
+    self.myDOF -= 1
+    model.do()
+
+    self.assertTangentEllipses(anEllipticArc, self.myEllipticArc)
+
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
diff --git a/src/SketchPlugin/Test/TestCreateArcByTransversalLine.py b/src/SketchPlugin/Test/TestCreateArcByTransversalLine.py
new file mode 100644 (file)
index 0000000..0250f95
--- /dev/null
@@ -0,0 +1,163 @@
+# 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
+#
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from GeomDataAPI import *
+from ModelAPI import *
+from SketchAPI import SketchAPI_Sketch
+import math
+from salome.shaper import model
+
+__updated__ = "2019-08-16"
+
+TOLERANCE = 1.e-7
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+
+def verifyLastArc(theSketch, theCenter, theStart, theEnd):
+    """
+    subroutine to verify position of last arc in the sketch
+    """
+    aLastArc = model.lastSubFeature(theSketch, "SketchArc")
+    model.assertArc(aLastArc, theCenter, theStart, theEnd)
+
+def verifyArcLineTransversal(theArc, theLine):
+    aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
+    aDistCL = model.distancePointLine(aCenter, theLine)
+    assert aDistCL < TOLERANCE, "Arc and line are not orthogonal"
+
+def verifyPointOnArc(thePoint, theArc):
+    aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
+    aStart = geomDataAPI_Point2D(theArc.attribute("start_point"))
+    aRadius = model.distancePointPoint(aStart, aCenter)
+
+    aDistPP = model.distancePointPoint(aCenter, thePoint)
+    assert math.fabs(aRadius - aDistPP) < TOLERANCE, "Point is not on Circle, distance: {0}".format(aDistPP)
+
+
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+aSketch = SketchAPI_Sketch(aSketchFeature)
+
+# auxiliary line
+aLineStartPnt = [0., 0.]
+aLineEndPnt = [50., 0.]
+aSession.startOperation()
+aSketchLine = aSketchFeature.addFeature("SketchLine")
+aLineStart = geomDataAPI_Point2D(aSketchLine.attribute("StartPoint"))
+aLineEnd = geomDataAPI_Point2D(aSketchLine.attribute("EndPoint"))
+aLineStart.setValue(aLineStartPnt[0], aLineStartPnt[1])
+aLineEnd.setValue(aLineEndPnt[0], aLineEndPnt[1])
+aSession.finishOperation()
+
+#=========================================================================
+# Test 1. Create an arc, orthogonal to the line
+#=========================================================================
+anArcEndPnt = [80., 20.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+assert (anArc.getKind() == "SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+assert (not anArcTgPnt.isInitialized())
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+assert (not anArcEnd.isInitialized())
+anArcType = anArc.string("arc_type")
+assert (not anArcType.isInitialized())
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aLineEnd)
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+verifyLastArc(aSketchFeature, [], aLineEndPnt, anArcEndPnt)
+aLastArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+verifyArcLineTransversal(aLastArc, aSketchLine)
+model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 1)
+model.testNbSubFeatures(aSketch, "SketchConstraintPerpendicular", 1)
+
+#=========================================================================
+# Test 2. Create an arc, orthogonal to the previous arc (expect an error)
+#=========================================================================
+aPrevArc = aLastArc
+aPrevArcEnd = geomDataAPI_Point2D(aPrevArc.attribute("end_point"))
+anArcEndPnt = [50., 100.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+anArcType = anArc.string("arc_type")
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aPrevArcEnd)
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+assert(anArc.error() != "")
+# remove failed feature
+aSession.startOperation()
+aDocument.removeFeature(anArc)
+aSession.finishOperation()
+
+#=========================================================================
+# Test 3. Create an arc, orthogonal to the line with end point on the arc
+#=========================================================================
+aPrevArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+aPrevArcEnd = geomDataAPI_Point2D(aPrevArc.attribute("end_point"))
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+anArcEndRef = anArc.refattr("end_point_ref")
+anArcType = anArc.string("arc_type")
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aLineStart)
+anArcEndRef.setObject(aPrevArc.lastResult())
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+verifyLastArc(aSketchFeature, [], [aLineStart.x(), aLineStart.y()], [])
+aLastArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+verifyArcLineTransversal(aLastArc, aSketchLine)
+aLastArcEnd = geomDataAPI_Point2D(aLastArc.attribute("end_point"))
+verifyPointOnArc(aLastArcEnd, aPrevArc)
+model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3)
+model.testNbSubFeatures(aSketch, "SketchConstraintPerpendicular", 2)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestCreateEllipseByCenterSemiaxisAndPassed.py b/src/SketchPlugin/Test/TestCreateEllipseByCenterSemiaxisAndPassed.py
new file mode 100644 (file)
index 0000000..f03f43d
--- /dev/null
@@ -0,0 +1,347 @@
+# 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 creation of ellipse by center, semi-axis and passed point
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-09"
+
+class TestEllipse(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myCenter = GeomAPI_Pnt2d(50., 50.)
+    self.myFocus = GeomAPI_Pnt2d(70., 50.)
+    self.myPassedPoint = GeomAPI_Pnt2d(60., 60.)
+    self.myMinorRadius = 20.
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+  def checkPointOnLine(self, theCoordinates, theLine):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointLine(point, theLine)
+    self.assertAlmostEqual(dist, 0, 7)
+
+  def checkPointOnCircle(self, theCoordinates, theCircle):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointPoint(point, theCircle.center())
+    self.assertAlmostEqual(dist , theCircle.radius().value(), 7)
+
+  def checkPointOnEllipse(self, theCoordinates, theEllipse):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    if issubclass(type(theEllipse), SketchAPI_Ellipse):
+      majorRad = theEllipse.majorRadius().value()
+    else:
+      majorRad = theEllipse.majorRadius()
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * majorRad, 7)
+
+
+  def test_ellipse_by_center_and_focus(self):
+    """ Test 1. Create ellipse by coordinates of center, focus and minor radius
+    """
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter.x(), self.myCenter.y(), self.myFocus.x(), self.myFocus.y(), self.myMinorRadius)
+    self.myDOF += 5
+
+    self.myEllipse2 = self.mySketch.addEllipse(self.myCenter, self.myFocus, self.myMinorRadius)
+    self.myDOF += 5
+    model.do()
+
+    # check both ellipses are equal
+    anEllipse1 = self.myEllipse1.defaultResult().shape().edge().ellipse()
+    anEllipse2 = self.myEllipse2.defaultResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+
+  def test_ellipse_by_semiaxis_and_passed(self):
+    """ Test 2. Create ellipse by coordinates of center, major semi-axis point and a passed point on ellipse
+    """
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter.x(), self.myCenter.y(), self.myFocus.x(), self.myFocus.y(), self.myPassedPoint.x(), self.myPassedPoint.y(), True)
+    self.myDOF += 5
+    model.do()
+    anEllipseFeature1 = model.lastSubFeature(self.mySketch, "SketchEllipse")
+
+    self.myEllipse2 = self.mySketch.addEllipse(self.myCenter, self.myFocus, self.myPassedPoint, True)
+    self.myDOF += 5
+    model.do()
+    anEllipseFeature2 = model.lastSubFeature(self.mySketch, "SketchEllipse")
+
+    # check both ellipses are equal
+    anEllipse1 = anEllipseFeature1.lastResult().shape().edge().ellipse()
+    anEllipse2 = anEllipseFeature2.lastResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    # check passed point on ellipse
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse1)
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse2)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 14)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 4)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+
+  def test_ellipse_with_fixed_center(self):
+    """ Test 3. Create ellipse which center is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(aLine.endPoint(), self.myFocus, self.myPassedPoint, True)
+    self.myDOF += 3
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse.center(), aLine.endPoint())
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_center_on_line(self):
+    """ Test 4. Create ellipse which center is coincident with a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse([self.myCenter, aLine.result()], self.myFocus, self.myPassedPoint, True)
+    self.myDOF += 4
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on line
+    self.checkPointOnLine(anEllipse.center(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_center_on_circle(self):
+    """ Test 5. Create ellipse which center is coincident with a circle
+    """
+    aCircle = self.mySketch.addCircle(10, 10, 20)
+    self.myDOF += 3
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse([self.myCenter, aCircle.defaultResult()], self.myFocus, self.myPassedPoint, True)
+    self.myDOF += 4
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on circle
+    self.checkPointOnCircle(anEllipse.center(), aCircle)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_center_on_ellipse(self):
+    """ Test 6. Create ellipse which center is coincident with another ellipse
+    """
+    anOtherEllipse = self.mySketch.addEllipse(10, 10, 30, 20, 10)
+    self.myDOF += 5
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse([self.myCenter, anOtherEllipse.defaultResult()], self.myFocus, self.myPassedPoint, True)
+    self.myDOF += 4
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on ellipse
+    self.checkPointOnEllipse(anEllipse.center(), anOtherEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_fixed_axis(self):
+    """ Test 7. Create ellipse which point on major semi-axis is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter, aLine.endPoint(), self.myPassedPoint, True)
+    self.myDOF += 3
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse)
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    # check distance is equal to major semi-axis
+    dist = model.distancePointPoint(GeomAPI_Pnt2d(anEllipse.center().x(), anEllipse.center().y()), aLine.endPoint())
+    self.assertAlmostEqual(dist, anEllipse.majorRadius(), 7)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_on_line(self):
+    """ Test 8. Create ellipse which point on major semi-axis is coincident with a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter, [self.myFocus, aLine.result()], self.myPassedPoint, True)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check axis point on line
+    self.checkPointOnLine(anEllipse.majorAxisPositive(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_on_circle(self):
+    """ Test 9. Create ellipse which point on major semi-axis is coincident with a circle
+    """
+    aCircle = self.mySketch.addCircle(10, 10, 20)
+    self.myDOF += 3
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter, [self.myFocus, aCircle.defaultResult()], self.myPassedPoint, True)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check center on circle
+    self.checkPointOnCircle(anEllipse.majorAxisPositive(), aCircle)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_on_ellipse(self):
+    """ Test 10. Create ellipse which point on major semi-axis is coincident with another ellipse
+    """
+    anOtherEllipse = self.mySketch.addEllipse(10, 10, 90, 40, 30)
+    self.myDOF += 5
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter, [self.myFocus, anOtherEllipse.defaultResult()], self.myPassedPoint, True)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check center on ellipse
+    self.checkPointOnEllipse(anEllipse.majorAxisPositive(), anOtherEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_fixed_passed_point(self):
+    """ Test 11. Create ellipse which passed point is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter, self.myFocus, aLine.endPoint(), True)
+    self.myDOF += 4
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_passed_point_on_line(self):
+    """ Test 12. Create ellipse which passed point is placed on a line.
+                 Check no constraints is applied.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myCenter, self.myFocus, [self.myPassedPoint, aLine.result()], True)
+    self.myDOF += 5
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    # check neither coincidence nor tangent feature exists
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", 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/TestCreateEllipseByExternal.py b/src/SketchPlugin/Test/TestCreateEllipseByExternal.py
new file mode 100644 (file)
index 0000000..92d33ca
--- /dev/null
@@ -0,0 +1,91 @@
+# 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 creation of ellipse by external feature
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-12"
+
+# reference data
+CENTER_POINT = GeomAPI_Pnt2d(50., 50.)
+FOCUS_POINT = GeomAPI_Pnt2d(70., 60.)
+MINOR_RADIUS = 10.
+
+class TestEllipse(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+
+  def test_ellipse_by_external_name(self):
+    """ Test 1. Create ellipse by name of external edge
+    """
+    self.myEllipse = self.mySketch.addEllipse("Sketch_1/SketchEllipse_1")
+    model.do()
+
+    # check ellipse parameters
+    anEllipse = self.myEllipse.defaultResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(anEllipse.firstFocus(), FOCUS_POINT)
+    self.assertAlmostEqual(anEllipse.minorRadius(), MINOR_RADIUS)
+
+  def test_ellipse_by_external_selection(self):
+    """ Test 2. Create ellipse by selected edge
+    """
+    self.myEllipse = self.mySketch.addEllipse(ELLIPSE.results()[-1])
+    model.do()
+
+    # check ellipse parameters
+    anEllipse = self.myEllipse.defaultResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(anEllipse.firstFocus(), FOCUS_POINT)
+    self.assertAlmostEqual(anEllipse.minorRadius(), MINOR_RADIUS)
+
+
+if __name__ == "__main__":
+    model.begin()
+    aDocument = model.moduleDocument()
+    aSketch = model.addSketch(aDocument, model.defaultPlane("XOY"))
+    ELLIPSE = aSketch.addEllipse(CENTER_POINT, FOCUS_POINT, MINOR_RADIUS)
+    model.end()
+
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
diff --git a/src/SketchPlugin/Test/TestCreateEllipseByMajorAxisAndPassed.py b/src/SketchPlugin/Test/TestCreateEllipseByMajorAxisAndPassed.py
new file mode 100644 (file)
index 0000000..401ab72
--- /dev/null
@@ -0,0 +1,319 @@
+# 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 creation of ellipse by majoraxis and passed point
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-12"
+
+class TestEllipse(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myAxisStart = GeomAPI_Pnt2d(30., 60.)
+    self.myAxisEnd = GeomAPI_Pnt2d(80., 50.)
+    self.myPassedPoint = GeomAPI_Pnt2d(60., 60.)
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+  def checkPointOnLine(self, theCoordinates, theLine):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointLine(point, theLine)
+    self.assertAlmostEqual(dist, 0, 7)
+
+  def checkPointOnCircle(self, theCoordinates, theCircle):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointPoint(point, theCircle.center())
+    self.assertAlmostEqual(dist , theCircle.radius().value(), 7)
+
+  def checkPointOnEllipse(self, theCoordinates, theEllipse):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * theEllipse.majorRadius(), 7)
+
+
+  def test_ellipse_by_axis_and_passed(self):
+    """ Test 1. Create ellipse by points defining major semi-axis and a passed point on ellipse
+    """
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart.x(), self.myAxisStart.y(), self.myAxisEnd.x(), self.myAxisEnd.y(), self.myPassedPoint.x(), self.myPassedPoint.y(), False)
+    self.myDOF += 5
+    model.do()
+    anEllipseFeature1 = model.lastSubFeature(self.mySketch, "SketchEllipse")
+
+    self.myEllipse2 = self.mySketch.addEllipse(self.myAxisStart, self.myAxisEnd, self.myPassedPoint, False)
+    self.myDOF += 5
+    model.do()
+    anEllipseFeature2 = model.lastSubFeature(self.mySketch, "SketchEllipse")
+
+    # check both ellipses are equal
+    anEllipse1 = anEllipseFeature1.lastResult().shape().edge().ellipse()
+    anEllipse2 = anEllipseFeature2.lastResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    # check passed point on ellipse
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse1)
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse2)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 14)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 4)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+
+  def test_ellipse_with_fixed_axis_start(self):
+    """ Test 2. Create ellipse which negative point on the major axis coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(aLine.startPoint(), self.myAxisEnd, self.myPassedPoint, False)
+    self.myDOF += 3
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse)
+    self.checkPointOnEllipse(aLine.startPoint(), anEllipse)
+    # check distance is equal to major semi-axis
+    dist = model.distancePointPoint(GeomAPI_Pnt2d(anEllipse.center().x(), anEllipse.center().y()), aLine.startPoint())
+    self.assertAlmostEqual(dist, anEllipse.majorRadius(), 7)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_start_on_line(self):
+    """ Test 3. Create ellipse which negative point on the major axis coincident with a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse([self.myAxisStart, aLine.result()], self.myAxisEnd, self.myPassedPoint, False)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check negative point of major axis on line
+    self.checkPointOnLine(anEllipse.majorAxisNegative(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_start_on_circle(self):
+    """ Test 4. Create ellipse which negative point on the major axis coincident with a circle
+    """
+    aCircle = self.mySketch.addCircle(10, 10, 20)
+    self.myDOF += 3
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse([self.myAxisStart, aCircle.defaultResult()], self.myAxisEnd, self.myPassedPoint, False)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check center on circle
+    self.checkPointOnCircle(anEllipse.majorAxisNegative(), aCircle)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_start_on_ellipse(self):
+    """ Test 5. Create ellipse which negative point on the major axis coincident with another ellipse
+    """
+    anOtherEllipse = self.mySketch.addEllipse(10, 10, 30, 20, 10)
+    self.myDOF += 5
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse([self.myAxisStart, anOtherEllipse.defaultResult()], self.myAxisEnd, self.myPassedPoint, False)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check center on ellipse
+    self.checkPointOnEllipse(anEllipse.majorAxisNegative(), anOtherEllipse.defaultResult().shape().edge().ellipse())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_fixed_axis_end(self):
+    """ Test 6. Create ellipse which positive point on the major axis coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 90, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart, aLine.endPoint(), self.myPassedPoint, False)
+    self.myDOF += 3
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse)
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    # check distance is equal to major semi-axis
+    dist = model.distancePointPoint(GeomAPI_Pnt2d(anEllipse.center().x(), anEllipse.center().y()), aLine.endPoint())
+    self.assertAlmostEqual(dist, anEllipse.majorRadius(), 7)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_end_on_line(self):
+    """ Test 7. Create ellipse which negative point on the major axis coincident with a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart, [self.myAxisEnd, aLine.result()], self.myPassedPoint, False)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check axis point on line
+    self.checkPointOnLine(anEllipse.majorAxisPositive(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_end_on_circle(self):
+    """ Test 8. Create ellipse which negative point on the major axis coincident with a circle
+    """
+    aCircle = self.mySketch.addCircle(10, 10, 20)
+    self.myDOF += 3
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart, [self.myAxisEnd, aCircle.defaultResult()], self.myPassedPoint, False)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check center on circle
+    self.checkPointOnCircle(anEllipse.majorAxisPositive(), aCircle)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_axis_end_on_ellipse(self):
+    """ Test 9. Create ellipse which negative point on the major axis coincident with another ellipse
+    """
+    anOtherEllipse = self.mySketch.addEllipse(10, 10, 90, 40, 30)
+    self.myDOF += 5
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart, [self.myAxisEnd, anOtherEllipse.defaultResult()], self.myPassedPoint, False)
+    self.myDOF += 4
+    model.do()
+
+    anEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+    # check center on ellipse
+    self.checkPointOnEllipse(anEllipse.majorAxisPositive(), anOtherEllipse.defaultResult().shape().edge().ellipse())
+    # check coincidence feature exists
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_fixed_passed_point(self):
+    """ Test 10. Create ellipse which passed point is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart, self.myAxisEnd, aLine.endPoint(), False)
+    self.myDOF += 4
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_ellipse_with_passed_point_on_line(self):
+    """ Test 11. Create ellipse which passed point is placed on a line.
+                 Check no constraints is applied.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.myEllipse1 = self.mySketch.addEllipse(self.myAxisStart, self.myAxisEnd, [self.myPassedPoint, aLine.result()], False)
+    self.myDOF += 5
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipse")
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myPassedPoint, anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    # check neither coincidence nor tangent feature exists
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", 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/TestCreateEllipticArc.py b/src/SketchPlugin/Test/TestCreateEllipticArc.py
new file mode 100644 (file)
index 0000000..fe675da
--- /dev/null
@@ -0,0 +1,379 @@
+# 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 creation of elliptic arc by center, semi-axis, start and end points
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-01"
+
+class TestEllipticArc(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myCenter = GeomAPI_Pnt2d(50., 50.)
+    self.myFocus = GeomAPI_Pnt2d(70., 60.)
+    self.myStartPoint = GeomAPI_Pnt2d(60., 65.)
+    self.myEndPoint = GeomAPI_Pnt2d(60., 42.535751)
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+  def checkPointOnLine(self, theCoordinates, theLine):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointLine(point, theLine)
+    self.assertAlmostEqual(dist, 0, 7)
+
+  def checkPointOnCircle(self, theCoordinates, theCircle):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointPoint(point, theCircle.center())
+    self.assertAlmostEqual(dist , theCircle.radius().value(), 7)
+
+  def checkPointOnEllipse(self, theCoordinates, theEllipse):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    if issubclass(type(theEllipse), SketchAPI_Ellipse):
+      majorRad = theEllipse.majorRadius().value()
+    else:
+      majorRad = theEllipse.majorRadius()
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * majorRad, 7)
+
+
+  def test_elliptic_arc_by_coordinates(self):
+    """ Test 1. Create elliptic arc by coordinates of center, point on the major axis, start and end points
+    """
+    self.myEllipse1 = self.mySketch.addEllipticArc(self.myCenter.x(), self.myCenter.y(),
+                                                   self.myFocus.x(), self.myFocus.y(),
+                                                   self.myStartPoint.x(), self.myStartPoint.y(),
+                                                   self.myEndPoint.x(), self.myEndPoint.y(), False)
+    self.myDOF += 7
+
+    self.myEllipse2 = self.mySketch.addEllipticArc(self.myCenter.x(), self.myCenter.y(),
+                                                   self.myFocus.x(), self.myFocus.y(),
+                                                   self.myStartPoint.x(), self.myStartPoint.y(),
+                                                   self.myEndPoint.x(), self.myEndPoint.y(), True)
+    self.myDOF += 7
+    model.do()
+
+    # check both ellipses are equal
+    anArcEdge1 = self.myEllipse1.defaultResult().shape().edge()
+    anArcEdge2 = self.myEllipse2.defaultResult().shape().edge()
+    anEllipse1 = anArcEdge1.ellipse()
+    anEllipse2 = anArcEdge2.ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    self.checkPointsEqual(self.myEllipse1.startPoint(), self.myEllipse2.startPoint())
+    self.checkPointsEqual(self.myEllipse1.endPoint(), self.myEllipse2.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 2)
+    # check middle points are different
+    assert(anArcEdge1.middlePoint().x() < self.myStartPoint.x())
+    assert(anArcEdge2.middlePoint().x() > self.myStartPoint.x())
+
+  def test_elliptic_arc_by_points(self):
+    """ Test 2. Create elliptic arc by points
+    """
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 7
+    model.do()
+    anEllipseFeature1 = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature1)
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, self.myEndPoint, True)
+    self.myDOF += 7
+    model.do()
+    anEllipseFeature2 = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse2 = SketchAPI_EllipticArc(anEllipseFeature2)
+
+    # check both ellipses are equal
+    anArcEdge1 = anEllipseFeature1.lastResult().shape().edge()
+    anArcEdge2 = anEllipseFeature2.lastResult().shape().edge()
+    anEllipse1 = anArcEdge1.ellipse()
+    anEllipse2 = anArcEdge2.ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    self.checkPointsEqual(self.myEllipse1.startPoint(), self.myEllipse2.startPoint())
+    self.checkPointsEqual(self.myEllipse1.endPoint(), self.myEllipse2.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 14)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 4)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 2)
+    # check middle points are different
+    assert(anArcEdge1.middlePoint().x() < self.myStartPoint.x())
+    assert(anArcEdge2.middlePoint().x() > self.myStartPoint.x())
+
+  def test_elliptic_arc_with_fixed_center(self):
+    """ Test 3. Create elliptic arc which center is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(aLine.endPoint(), self.myFocus, self.myStartPoint, self.myEndPoint, True)
+    self.myDOF += 5
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse.center(), aLine.endPoint())
+    self.checkPointOnEllipse(self.myStartPoint, anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_center_on_line(self):
+    """ Test 4. Create elliptic arc which center is coincident with a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc([self.myCenter, aLine.result()], self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on line
+    self.checkPointOnLine(anEllipse.center(), aLine)
+    self.checkPointOnEllipse(self.myEllipse1.startPoint(), anEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_center_on_circle(self):
+    """ Test 5. Create elliptic arc which center is coincident with a circle
+    """
+    aCircle = self.mySketch.addCircle(10, 10, 20)
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.addEllipticArc([self.myCenter, aCircle.defaultResult()], self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on circle
+    self.checkPointOnCircle(anEllipse.center(), aCircle)
+    self.checkPointOnEllipse(self.myEllipse1.startPoint(), anEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_center_on_ellipse(self):
+    """ Test 6. Create elliptic arc which center is coincident with another ellipse
+    """
+    anOtherEllipse = self.mySketch.addEllipse(10, 10, 30, 20, 10)
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.addEllipticArc([self.myCenter, anOtherEllipse.defaultResult()], self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on ellipse
+    self.checkPointOnEllipse(anEllipse.center(), anOtherEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.startPoint(), anEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_fixed_axis(self):
+    """ Test 7. Create elliptic arc which point on major semi-axis is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, aLine.endPoint(), self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myStartPoint, anEllipse)
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    # check distance is equal to major semi-axis
+    dist = model.distancePointPoint(GeomAPI_Pnt2d(anEllipse.center().x(), anEllipse.center().y()), aLine.endPoint())
+    self.assertAlmostEqual(dist, anEllipse.majorRadius(), 7)
+    self.checkPointsEqual(self.myEllipse1.majorAxisPositive(), aLine.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_axis_on_line(self):
+    """ Test 8. Create elliptic arc which point on major semi-axis is coincident with a line.
+                Check no coincidence constraint is created.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, [self.myFocus, aLine.result()], self.myStartPoint, self.myEndPoint, True)
+    self.myDOF += 7
+    model.do()
+
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 0)
+
+  def test_elliptic_arc_with_fixed_start_point(self):
+    """ Test 9. Create elliptic arc which start point is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, aLine.endPoint(), self.myEndPoint, True)
+    self.myDOF += 5
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    self.checkPointsEqual(aLine.endPoint(), self.myEllipse1.startPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_start_point_on_line(self):
+    """ Test 10. Create elliptic arc which start point is placed on a line.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, [self.myStartPoint, aLine.result()], self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnLine(self.myEllipse1.startPoint(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_fixed_end_point(self):
+    """ Test 11. Create elliptic arc which end point is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, aLine.endPoint(), True)
+    self.myDOF += 5
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    self.checkPointsEqual(aLine.endPoint(), self.myEllipse1.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_end_point_on_line(self):
+    """ Test 12. Create elliptic arc which end point is placed on a line.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, [self.myEndPoint, aLine.result()], False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnLine(self.myEllipse1.endPoint(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+
+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/TestCreateEllipticArcByExternal.py b/src/SketchPlugin/Test/TestCreateEllipticArcByExternal.py
new file mode 100644 (file)
index 0000000..7d83217
--- /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
+#
+
+"""
+    Test creation of elliptic arc by external feature
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-02"
+
+# reference data
+CENTER_POINT = GeomAPI_Pnt2d(50., 50.)
+MAJOR_AXIS_POINT = GeomAPI_Pnt2d(70., 60.)
+START_POINT = GeomAPI_Pnt2d(60., 65.)
+END_POINT = GeomAPI_Pnt2d(60., 42.535751)
+ARC_LENGTH_1 = 0
+ARC_LENGTH_2 = 0
+
+class TestEllipticArcByExternal(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+
+  def test_elliptic_arc_by_external_name_1(self):
+    """ Test 1. Create elliptic arc by name of external edge (direct)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc("Sketch_1/SketchEllipticArc_1")
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(self.myEllipse.startPoint(), START_POINT)
+    self.checkPointsEqual(self.myEllipse.endPoint(), END_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_1)
+
+  def test_elliptic_arc_by_external_name_2(self):
+    """ Test 2. Create elliptic arc by name of external edge (reversed)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc("Sketch_1/SketchEllipticArc_2")
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(anArcEdge.firstPoint(), END_POINT)
+    self.checkPointsEqual(anArcEdge.lastPoint(), START_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_2)
+
+  def test_elliptic_arc_by_external_selection_1(self):
+    """ Test 3. Create elliptic arc by selected edge (direct)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc(ELLIPTIC_ARC_1.results()[-1])
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(self.myEllipse.startPoint(), START_POINT)
+    self.checkPointsEqual(self.myEllipse.endPoint(), END_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_1)
+
+  def test_elliptic_arc_by_external_selection_2(self):
+    """ Test 4. Create elliptic arc by selected edge (reversed)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc(ELLIPTIC_ARC_2.results()[-1])
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(self.myEllipse.startPoint(), END_POINT)
+    self.checkPointsEqual(self.myEllipse.endPoint(), START_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_2)
+
+
+if __name__ == "__main__":
+    model.begin()
+    aDocument = model.moduleDocument()
+    aSketch = model.addSketch(aDocument, model.defaultPlane("XOY"))
+    aSketch.addEllipticArc(CENTER_POINT, MAJOR_AXIS_POINT, START_POINT, END_POINT, False)
+    model.do()
+
+    ELLIPTIC_ARC_1 = SketchAPI_EllipticArc(model.lastSubFeature(aSketch, "SketchEllipticArc"))
+    ARC_LENGTH_1 = ELLIPTIC_ARC_1.defaultResult().shape().edge().length()
+
+    aSketch.addEllipticArc(CENTER_POINT, MAJOR_AXIS_POINT, START_POINT, END_POINT, True)
+    model.end()
+
+    ELLIPTIC_ARC_2 = SketchAPI_EllipticArc(model.lastSubFeature(aSketch, "SketchEllipticArc"))
+    ARC_LENGTH_2 = ELLIPTIC_ARC_2.defaultResult().shape().edge().length()
+
+    # redefine end point
+    END_POINT = ELLIPTIC_ARC_2.endPoint()
+
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
diff --git a/src/SketchPlugin/Test/TestMoveEllipse.py b/src/SketchPlugin/Test/TestMoveEllipse.py
new file mode 100644 (file)
index 0000000..3795ee8
--- /dev/null
@@ -0,0 +1,240 @@
+# 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 GeomDataAPI import geomDataAPI_Point2D
+from salome.shaper import model
+
+__updated__ = "2019-09-12"
+
+class TestMoveEllipse(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myCenter = [70., 50.]
+    self.myFocus = [100., 70.]
+    self.myMinorRadius = 20.
+    self.myEllipse = self.mySketch.addEllipse(self.myCenter[0], self.myCenter[1], self.myFocus[0], self.myFocus[1], self.myMinorRadius)
+    self.myDOF = 5
+    model.do()
+    self.checkDOF()
+    self.myMajorRadius = self.myEllipse.majorRadius().value()
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointCoordinates(self, thePoint, theCoordinates):
+    aCoord = []
+    if issubclass(type(theCoordinates), GeomAPI_Pnt2d):
+      aCoord = [theCoordinates.x(), theCoordinates.y()]
+    else:
+      aCoord = theCoordinates
+    DIGITS = 7 - math.floor(math.log10(math.hypot(aCoord[0], aCoord[1])))
+    self.assertAlmostEqual(thePoint.x(), aCoord[0], DIGITS)
+    self.assertAlmostEqual(thePoint.y(), aCoord[1], DIGITS)
+
+  def checkPointOnEllipse(self, theCoordinates, theEllipse):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * theEllipse.majorRadius().value(), 7 - math.floor(math.log10(theEllipse.majorRadius().value())))
+
+  def fixMajorRadius(self):
+    self.mySketch.setDistance(self.myEllipse.center(), self.myEllipse.majorAxisPositive(), self.myMajorRadius)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+  def fixMinorRadius(self):
+    self.mySketch.setDistance(self.myEllipse.center(), self.myEllipse.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 ellipse
+    """
+    newPosition = [self.myCenter[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myEllipse.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), newPosition)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipse.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_free_ellipse(self):
+    """ Test 2. Movement of a free ellipse dragging the edge
+    """
+    newPosition = GeomAPI_Pnt2d(120., 90.)
+    self.mySketch.move(self.myEllipse.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), self.myCenter)
+    self.checkPointOnEllipse(newPosition, self.myEllipse)
+    self.assertNotEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipse.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[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myEllipse.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), newPosition)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipse.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.myEllipse.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipse)
+    self.assertNotEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipse.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[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myEllipse.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), newPosition)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipse.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_ellipse_fixed_minor_radius(self):
+    """ Test 6. Movement of ellipse with fixed minor radius
+    """
+    self.fixMinorRadius()
+
+    newPosition = GeomAPI_Pnt2d(120., 90.)
+    self.mySketch.move(self.myEllipse.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipse)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipse.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.myEllipse.center())
+
+    newPosition = [self.myCenter[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myEllipse.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), self.myCenter)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipse.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_ellipse_fixed_center(self):
+    """ Test 8. Movement of ellipse with fixed center
+    """
+    self.fixPoint(self.myEllipse.center())
+
+    newPosition = GeomAPI_Pnt2d(120., 90.)
+    self.mySketch.move(self.myEllipse.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipse)
+    self.assertNotEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipse.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_center_ellipse_fixed_focus(self):
+    """ Test 9. Movement of central point of ellipse with fixed focus
+    """
+    self.fixPoint(self.myEllipse.firstFocus())
+
+    newPosition = GeomAPI_Pnt2d(self.myCenter[0] + 20., self.myCenter[1] + 10.)
+    self.mySketch.move(self.myEllipse.center(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), newPosition)
+    self.checkPointCoordinates(self.myEllipse.firstFocus(), self.myFocus)
+    self.assertNotEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipse.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)
+    """
+    self.fixPoint(self.myEllipse.firstFocus())
+
+    newPosition = GeomAPI_Pnt2d(self.myFocus[0] + 10., self.myFocus[1] + 10.)
+    self.mySketch.move(self.myEllipse.firstFocus(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.firstFocus(), self.myFocus)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertAlmostEqual(self.myEllipse.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_ellipse_fixed_focus(self):
+    """ Test 11. Movement of ellipse with fixed focus
+    """
+    self.fixPoint(self.myEllipse.firstFocus())
+
+    newPosition = GeomAPI_Pnt2d(80., 90.)
+    self.mySketch.move(self.myEllipse.defaultResult(), newPosition.x(), newPosition.y())
+    model.do()
+    self.checkPointOnEllipse(newPosition, self.myEllipse)
+    self.checkPointCoordinates(self.myEllipse.firstFocus(), self.myFocus)
+    self.assertNotEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+    self.assertNotEqual(self.myEllipse.majorRadius().value(), self.myMajorRadius)
+
+  def test_move_fixed_ellipse(self):
+    """ Test 12. Trying to move fully fixed ellipse
+    """
+    self.mySketch.setFixed(self.myEllipse.results()[-1])
+    self.myDOF -= 5
+    model.do()
+    self.checkDOF()
+
+    newPosition = [120., 90.]
+    self.mySketch.move(self.myEllipse.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myEllipse.center(), self.myCenter)
+    self.checkPointCoordinates(self.myEllipse.firstFocus(), self.myFocus)
+    self.assertAlmostEqual(self.myEllipse.minorRadius().value(), self.myMinorRadius)
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert(model.checkPythonDump())
index 0265fd406cba0e6d43fff3ecbd32fb67527f90a8..9f251831d5b2354dad301854c7c6f96d5af0922d 100644 (file)
@@ -89,6 +89,8 @@ assert(featureToPresentation(SketchConstraintMirror_1.feature()).getAISObject(No
 assert(featureToPresentation(SketchMultiTranslation_1.feature()).getAISObject(None) is not None)
 assert(featureToPresentation(SketchMultiRotation_1.feature()).getAISObject(None) is not None)
 
+model.end()
+
 # Test presentation for Fillet on low-level
 aSession = ModelAPI_Session.get()
 aSketchFeature = featureToCompositeFeature(Sketch_1.feature())
@@ -126,4 +128,30 @@ anArcPnt3.setValue(0, 5)
 assert(featureToPresentation(anArc).getAISObject(None) is not None)
 aSession.finishOperation()
 
-model.end()
+# Test presentation for MacroEllipse on low-level
+aSession.startOperation()
+anEllipse = aSketchFeature.addFeature("SketchMacroEllipse")
+anEllipsePnt1 = geomDataAPI_Point2D(anEllipse.attribute("first_point"))
+anEllipsePnt2 = geomDataAPI_Point2D(anEllipse.attribute("second_point"))
+anEllipsePnt3 = geomDataAPI_Point2D(anEllipse.attribute("passed_point"))
+anEllipseType = anEllipse.string("ellipse_type")
+anEllipseType.setValue("by_center_axis_point")
+anEllipsePnt1.setValue(10, 0)
+anEllipsePnt2.setValue(-10, 0)
+anEllipsePnt3.setValue(0, 5)
+assert(featureToPresentation(anEllipse).getAISObject(None) is not None)
+aSession.finishOperation()
+
+# Test presentation for MacroEllipticArc on low-level
+aSession.startOperation()
+anEllipticArc = aSketchFeature.addFeature("SketchMacroEllipticArc")
+anEllipticArcPnt1 = geomDataAPI_Point2D(anEllipticArc.attribute("center"))
+anEllipticArcPnt2 = geomDataAPI_Point2D(anEllipticArc.attribute("major_axis_point"))
+anEllipticArcPnt3 = geomDataAPI_Point2D(anEllipticArc.attribute("start_point"))
+anEllipticArcPnt4 = geomDataAPI_Point2D(anEllipticArc.attribute("end_point"))
+anEllipticArcPnt1.setValue(0, 0)
+anEllipticArcPnt2.setValue(10, 0)
+anEllipticArcPnt3.setValue(0, 5)
+anEllipticArcPnt4.setValue(-10, 0)
+assert(featureToPresentation(anEllipticArc).getAISObject(None) is not None)
+aSession.finishOperation()
diff --git a/src/SketchPlugin/Test/TestProjectionEllipse.py b/src/SketchPlugin/Test/TestProjectionEllipse.py
new file mode 100644 (file)
index 0000000..c6a97d9
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(0, -100, 20)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchAPI_Line(SketchLine_1).startPoint(), 100, True)
+model.do()
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), model.selection("EDGE", "PartSet/OX"), 30)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]"), True)
+SketchCircle_2 = SketchProjection_2.createdFeature()
+model.do()
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchProjection_3 = Sketch_3.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face]"), True)
+SketchEllipse_1 = SketchProjection_3.createdFeature()
+SketchProjection_4 = Sketch_3.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]"), True)
+SketchEllipse_2 = SketchProjection_4.createdFeature()
+model.do()
+model.end()
+
+from GeomAPI import *
+
+ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape()
+assert(ellipse1.isEdge() and ellipse1.edge().isEllipse())
+ellipse2 = SketchEllipse_2.results()[-1].resultSubShapePair()[0].shape()
+assert(ellipse2.isEdge() and ellipse2.edge().isEllipse())
+
+# TODO [limitation]: projection of an ellipse to non-parallel plane is forbiden (OCCT issue #31016)
+assert(Sketch_2.feature().error() != "")
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestProjectionEllipticArc.py b/src/SketchPlugin/Test/TestProjectionEllipticArc.py
new file mode 100644 (file)
index 0000000..7d8fc93
--- /dev/null
@@ -0,0 +1,61 @@
+# Copyright (C) 2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchLine_2 = Sketch_1.addLine(-17.32050807568878, -110, 0, -100)
+SketchLine_3 = Sketch_1.addLine(0, -100, 10, -117.3205080756888)
+SketchArc_1 = Sketch_1.addArc(0, -100, 10, -117.3205080756888, -17.32050807568878, -110, False)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 20)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchAPI_Line(SketchLine_1).startPoint(), 100, True)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_2.endPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchArc_1.endPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchArc_1.startPoint())
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_2.result(), SketchLine_3.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_1.result(), 150)
+model.do()
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), model.selection("EDGE", "PartSet/OX"), 30)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/To_Face][Extrusion_1_1/Generated_Face&Sketch_1/SketchArc_1_2]"), True)
+SketchEllipticArc_1 = SketchProjection_2.createdFeature()
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/From_Face][Extrusion_1_1/Generated_Face&Sketch_1/SketchArc_1_2]"), True)
+SketchEllipticArc_2 = SketchProjection_3.createdFeature()
+model.do()
+model.end()
+
+from GeomAPI import *
+
+ellipse1 = SketchEllipticArc_1.results()[-1].resultSubShapePair()[0].shape()
+assert(ellipse1.isEdge() and ellipse1.edge().isEllipse())
+ellipse2 = SketchEllipticArc_2.results()[-1].resultSubShapePair()[0].shape()
+assert(ellipse2.isEdge() and ellipse2.edge().isEllipse())
+
+assert(model.checkPythonDump())
index 0ad4fb507f3d1e2f19c234431b54c544031a7fb6..49cdb2ab5a57037ee08e6ffac27806e234b002ce 100644 (file)
@@ -159,7 +159,7 @@ testProjections(Part_1_doc, Sketch_7, aProjectedList, aFailedIDs)
 
 # Test projection to slope side face of the prism
 Sketch_8 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_2/SketchLine_2"))
-aFailedIDs = set([0, 1])
+aFailedIDs = set()
 testProjections(Part_1_doc, Sketch_8, aProjectedList, aFailedIDs)
 
 model.end()
diff --git a/src/SketchPlugin/Test/TestRemoveEllipse.py b/src/SketchPlugin/Test/TestRemoveEllipse.py
new file mode 100644 (file)
index 0000000..7a8d3c4
--- /dev/null
@@ -0,0 +1,106 @@
+# 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 removing ellipse and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbEllipses, theNbInternalConstraints):
+    model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+    model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+    model.testNbSubFeatures(theSketch, "SketchEllipse", theNbEllipses)
+    model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipse_1 = Sketch_1.addEllipse(40, 30, 70, 40, 20)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipse_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+model.end()
+
+DEFAULT_DOF = 5
+DEFAULT_POINTS = 7
+DEFAULT_LINES = 2
+DEFAULT_ELLIPSES = 1
+DEAFULT_INTERNALS = 11
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+points = [Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd]
+for pnt in points:
+    model.begin()
+    removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+    model.end()
+
+    assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_ELLIPSES, DEAFULT_INTERNALS - 1)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary axes one by one.
+lines = [MajorAxisLine, MinorAxisLine]
+for ln in lines:
+    model.begin()
+    removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+    model.end()
+
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_ELLIPSES, DEAFULT_INTERNALS - 2)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3.  Remove the ellipse.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchEllipse_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipse_2 = Sketch_2.addEllipse(40, -30, 70, 0, 10)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipse_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+model.end()
+
+model.begin()
+removeFeaturesAndReferences(FeatureSet([MajorAxisLine.feature(), Focus2.feature()]))
+Focus1.setAuxiliary(False)
+MinorAxisEnd.setAuxiliary(False)
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_ELLIPSES, DEAFULT_INTERNALS - 3)
+assert(model.dof(Sketch_2) == DEFAULT_DOF)
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestRemoveEllipticArc.py b/src/SketchPlugin/Test/TestRemoveEllipticArc.py
new file mode 100644 (file)
index 0000000..ccea403
--- /dev/null
@@ -0,0 +1,107 @@
+# 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 removing elliptic arc and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbEllipticArcs, theNbInternalConstraints):
+    model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+    model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+    model.testNbSubFeatures(theSketch, "SketchEllipticArc", theNbEllipticArcs)
+    model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipticArc_1 = Sketch_1.addEllipticArc(40, 30, 70, 60, 60, 65, 60., 23.3257583582, False)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipticArc_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+model.end()
+
+DEFAULT_DOF = 7
+DEFAULT_POINTS = 7
+DEFAULT_LINES = 2
+DEFAULT_ELLIPTIC_ARCS = 1
+DEAFULT_INTERNALS = 11
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+points = [Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd]
+for pnt in points:
+    model.begin()
+    removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+    model.end()
+
+    assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS - 1)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary axes one by one.
+lines = [MajorAxisLine, MinorAxisLine]
+for ln in lines:
+    model.begin()
+    removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+    model.end()
+
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS - 2)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3.  Remove the elliptic arc.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchEllipticArc_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipticArc_2 = Sketch_2.addEllipticArc(40, -30, 70, 0, 30, 10, 0, -20, True)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipticArc_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+SketchEllipticArc_2.setAuxiliary(True)
+model.do()
+model.end()
+
+model.begin()
+removeFeaturesAndReferences(FeatureSet([MajorAxisLine.feature(), Focus2.feature()]))
+Focus1.setAuxiliary(False)
+MinorAxisLine.setAuxiliary(False)
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS - 3)
+assert(model.dof(Sketch_2) == DEFAULT_DOF)
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestSplitEllipse.py b/src/SketchPlugin/Test/TestSplitEllipse.py
new file mode 100644 (file)
index 0000000..ab00b81
--- /dev/null
@@ -0,0 +1,135 @@
+# 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 salome.shaper import geom
+import math
+
+from ModelAPI import *
+from SketchAPI import *
+
+CENTER = geom.Pnt2d(10, 10)
+MAJOR_RADIUS = 50
+MINOR_RADIUS = 30
+
+DOF = 11
+NB_LINES = 3
+NB_ELLIPSES = 1
+NB_ELLIPTIC_ARCS = 0
+NB_COINCIDENCES = 5
+
+TOLERANCE = 1.e-6
+
+def checkFeaturesQuantity(theSketch):
+    model.testNbSubFeatures(theSketch, "SketchLine", NB_LINES)
+    model.testNbSubFeatures(theSketch, "SketchEllipse", NB_ELLIPSES)
+    model.testNbSubFeatures(theSketch, "SketchEllipticArc", NB_ELLIPTIC_ARCS)
+    model.testNbSubFeatures(theSketch, "SketchConstraintCoincidence", NB_COINCIDENCES)
+    assert(model.dof(theSketch) == DOF)
+
+def checkEllipticArcs(theSketch):
+    for aSub in theSketch.features().list():
+        aFeature = ModelAPI_Feature.feature(aSub)
+        if aFeature is not None and aFeature.getKind() == "SketchEllipticArc":
+            assertEllipticArc(SketchAPI_EllipticArc(aFeature))
+
+def assertEllipticArc(theArc):
+    assertPoints(theArc.center(), CENTER)
+    assertPoints(theArc.majorAxisPositive(), geom.Pnt2d(CENTER.x() + MAJOR_RADIUS, CENTER.y()))
+    assertPoints(theArc.minorAxisPositive(), geom.Pnt2d(CENTER.x(), CENTER.y() + MINOR_RADIUS))
+
+def assertPoints(thePoint1, thePoint2):
+  assert(math.fabs(thePoint1.x() - thePoint2.x()) < TOLERANCE), "{} != {}".format(thePoint1.x(), thePoint2.x())
+  assert(math.fabs(thePoint1.y() - thePoint2.y()) < TOLERANCE), "{} != {}".format(thePoint1.y(), thePoint2.y())
+
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipse_1 = Sketch_1.addEllipse(CENTER.x(), CENTER.y(), CENTER.x() + math.sqrt(MAJOR_RADIUS**2 - MINOR_RADIUS**2), CENTER.y(), MINOR_RADIUS)
+SketchLine_1 = Sketch_1.addLine(-16.74176451428603, -15.34869012470842, -16.85909682653373, 35.30399198463829)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchEllipse_1.result())
+SketchLine_2 = Sketch_1.addLine(-16.85909682653373, 35.30399198463829, 20.9032928583277, -19.27802168426675)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchEllipse_1.result())
+SketchLine_3 = Sketch_1.addLine(34.69765676551338, 36.08465583643841, 35.0422024535432, -15.96612629290852)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.startPoint(), SketchEllipse_1.result())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchEllipse_1.result())
+model.do()
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+# split the ellipse
+SketchSplit = Sketch_1.addSplit(SketchEllipse_1, geom.Pnt2d(CENTER.x() + MAJOR_RADIUS, CENTER.y()))
+model.do()
+NB_ELLIPSES -= 1
+NB_ELLIPTIC_ARCS += 2
+NB_COINCIDENCES += 4
+DOF += 3
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+# split the middle arc of ellipse
+EllipticArc = SketchAPI_EllipticArc(model.lastSubFeature(Sketch_1, "SketchEllipticArc"))
+ANGLE = -math.pi/2 - math.pi/10
+SketchSplit = Sketch_1.addSplit(EllipticArc, geom.Pnt2d(CENTER.x() + MAJOR_RADIUS * math.cos(ANGLE), CENTER.y() + MINOR_RADIUS * math.sin(ANGLE)))
+model.do()
+NB_ELLIPTIC_ARCS += 2
+NB_COINCIDENCES += 4
+DOF += 8
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+# try to split the boundary arc of ellipse,
+# it shoult fail, because there is no coincident points
+EllipticArc = SketchAPI_EllipticArc(model.lastSubFeature(Sketch_1, "SketchEllipticArc"))
+SketchSplit = Sketch_1.addSplit(EllipticArc, geom.Pnt2d(CENTER.x() - MAJOR_RADIUS, CENTER.y()))
+model.end()
+aValidators = ModelAPI_Session.get().validators()
+assert(not aValidators.validate(SketchSplit.feature()))
+
+# remove previous split and add coincidence
+model.undo()
+model.begin()
+Part_1_doc.removeFeature(SketchSplit.feature())
+model.do()
+Sketch_1.setCoincident(SketchLine_1.endPoint(), EllipticArc.result())
+Sketch_1.setCoincident(SketchLine_2.startPoint(), EllipticArc.result())
+model.do()
+NB_COINCIDENCES += 1
+DOF -= 1
+
+# split the boundary arc of ellipse
+SketchSplit = Sketch_1.addSplit(EllipticArc, geom.Pnt2d(CENTER.x() - MAJOR_RADIUS, CENTER.y()))
+model.do()
+NB_ELLIPTIC_ARCS += 1
+NB_COINCIDENCES += 4
+DOF += 4
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestTrimEllipse.py b/src/SketchPlugin/Test/TestTrimEllipse.py
new file mode 100644 (file)
index 0000000..ba3c59d
--- /dev/null
@@ -0,0 +1,118 @@
+# 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 salome.shaper import geom
+import math
+
+from ModelAPI import *
+from SketchAPI import *
+
+CENTER = geom.Pnt2d(10, 10)
+MAJOR_RADIUS = 50
+MINOR_RADIUS = 30
+
+DOF = 11
+NB_LINES = 3
+NB_ELLIPSES = 1
+NB_ELLIPTIC_ARCS = 0
+NB_COINCIDENCES = 6
+NB_EQUALS = 0
+
+TOLERANCE = 1.e-6
+
+def checkFeaturesQuantity(theSketch):
+    model.testNbSubFeatures(theSketch, "SketchLine", NB_LINES)
+    model.testNbSubFeatures(theSketch, "SketchEllipse", NB_ELLIPSES)
+    model.testNbSubFeatures(theSketch, "SketchEllipticArc", NB_ELLIPTIC_ARCS)
+    model.testNbSubFeatures(theSketch, "SketchConstraintCoincidence", NB_COINCIDENCES)
+    model.testNbSubFeatures(theSketch, "SketchConstraintEqual", NB_EQUALS)
+    assert(model.dof(theSketch) == DOF)
+
+def checkEllipticArcs(theSketch):
+    for aSub in theSketch.features().list():
+        aFeature = ModelAPI_Feature.feature(aSub)
+        if aFeature is not None and aFeature.getKind() == "SketchEllipticArc":
+            assertEllipticArc(SketchAPI_EllipticArc(aFeature))
+
+def assertEllipticArc(theArc):
+    assertPoints(theArc.center(), CENTER)
+    assertPoints(theArc.majorAxisPositive(), geom.Pnt2d(CENTER.x() + MAJOR_RADIUS, CENTER.y()))
+    assertPoints(theArc.minorAxisPositive(), geom.Pnt2d(CENTER.x(), CENTER.y() + MINOR_RADIUS))
+
+def assertPoints(thePoint1, thePoint2):
+  assert(math.fabs(thePoint1.x() - thePoint2.x()) < TOLERANCE), "{} != {}".format(thePoint1.x(), thePoint2.x())
+  assert(math.fabs(thePoint1.y() - thePoint2.y()) < TOLERANCE), "{} != {}".format(thePoint1.y(), thePoint2.y())
+
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipse_1 = Sketch_1.addEllipse(CENTER.x(), CENTER.y(), CENTER.x() + math.sqrt(MAJOR_RADIUS**2 - MINOR_RADIUS**2), CENTER.y(), MINOR_RADIUS)
+SketchLine_1 = Sketch_1.addLine(-16.74176451428603, -15.34869012470842, -16.85909682653373, 35.30399198463829)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchEllipse_1.result())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchEllipse_1.result())
+SketchLine_2 = Sketch_1.addLine(-16.85909682653373, 35.30399198463829, 20.9032928583277, -19.27802168426675)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_2.startPoint(), SketchEllipse_1.result())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchEllipse_1.result())
+SketchLine_3 = Sketch_1.addLine(34.69765676551338, 36.08465583643841, 35.0422024535432, -17.96612629290852)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_3.startPoint(), SketchEllipse_1.result())
+model.do()
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+# trim the ellipse
+SketchSplit = Sketch_1.addTrim(SketchEllipse_1, geom.Pnt2d(CENTER.x() + MAJOR_RADIUS, CENTER.y()))
+model.do()
+NB_ELLIPSES -= 1
+NB_ELLIPTIC_ARCS += 1
+NB_COINCIDENCES += 1
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+# trim the middle arc of ellipse
+EllipticArc = SketchAPI_EllipticArc(model.lastSubFeature(Sketch_1, "SketchEllipticArc"))
+ANGLE = -math.pi/2 - math.pi/10
+SketchSplit = Sketch_1.addTrim(EllipticArc, geom.Pnt2d(CENTER.x() + MAJOR_RADIUS * math.cos(ANGLE), CENTER.y() + MINOR_RADIUS * math.sin(ANGLE)))
+model.do()
+NB_ELLIPTIC_ARCS += 1
+NB_COINCIDENCES += 1
+NB_EQUALS += 1
+DOF += 1
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+# trim the boundary arc of ellipse
+SketchSplit = Sketch_1.addTrim(EllipticArc, geom.Pnt2d(CENTER.x() - MAJOR_RADIUS, CENTER.y()))
+model.do()
+NB_COINCIDENCES -= 1
+DOF += 1
+
+checkFeaturesQuantity(Sketch_1)
+checkEllipticArcs(Sketch_1)
+
+model.end()
+
+assert(model.checkPythonDump())
index f60148a465d1272a4823c3c24dca2cf1a41827cc..dc99970dfb5185130bfa59680f0dc36d9c91a3f8 100644 (file)
@@ -88,6 +88,8 @@ The plug-in includes the following features for creation of 2D objects:
    rectangleFeature.rst
    circleFeature.rst
    arcFeature.rst
+   ellipseFeature.rst
+   arcEllipseFeature.rst
 
 .. _sketch_constraints:
 
diff --git a/src/SketchPlugin/doc/TUI_ellipseFeature.rst b/src/SketchPlugin/doc/TUI_ellipseFeature.rst
new file mode 100644 (file)
index 0000000..eb0d9c4
--- /dev/null
@@ -0,0 +1,11 @@
+
+  .. _tui_create_ellipse:
+
+Create Skecth Ellipse
+====================
+
+.. literalinclude:: examples/ellipse.py
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/ellipse.py>`
diff --git a/src/SketchPlugin/doc/TUI_ellipticArcFeature.rst b/src/SketchPlugin/doc/TUI_ellipticArcFeature.rst
new file mode 100644 (file)
index 0000000..89d3d24
--- /dev/null
@@ -0,0 +1,11 @@
+
+  .. _tui_create_elliptic_arc:
+
+Create Skecth Elliptic Arc
+==========================
+
+.. literalinclude:: examples/elliptic_arc.py
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/elliptic_arc.py>`
diff --git a/src/SketchPlugin/doc/arcEllipseFeature.rst b/src/SketchPlugin/doc/arcEllipseFeature.rst
new file mode 100644 (file)
index 0000000..2387f96
--- /dev/null
@@ -0,0 +1,46 @@
+.. |earc.icon|    image:: images/elliptic_arc.png
+
+Elliptic Arc
+============
+
+Elliptic Arc feature creates an elliptic arc segment in the current Sketch.
+
+To add a new Elliptic Arc to the Sketch:
+
+#. select in the Main Menu *Sketch - > Elliptic Arc* item  or
+#. click |earc.icon| **Elliptic Arc** button in Sketch toolbar:
+
+The following property panel appears:
+
+.. image:: images/elliptic_arc_panel.png
+   :align: center
+
+Click in the view to set the center point, then move the mouse and click a second time to set a point of a one semi-axis, then click to set a starting point of the arc and then to set an end point of the arc.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addEllipticArc(CenterX, CenterY, FocusX, FocusY, StartX, StartY, EndX, EndY, Inversed)
+
+    :param real: Center X.
+    :param real: Center Y.
+    :param real: Focus X.
+    :param real: Focus Y.
+    :param real: Start X.
+    :param real: Start Y.
+    :param real: End X.
+    :param real: End Y.
+    :param boolean: Is inversed.
+    :return: Result object.
+
+Result
+""""""
+
+Created elliptic arc appears in the view.
+
+.. image:: images/elliptic_arc_result.png
+          :align: center
+
+.. centered::
+   Elliptic arc created
+
+**See Also** a sample TUI Script of :ref:`tui_create_elliptic_arc` operation.
\ No newline at end of file
index 9139ea4db9c7980ba2520635ec00bf43862c4150..5cdb22aa9b9aec1edc2a4df69f3253f5b7790f8b 100644 (file)
@@ -10,7 +10,7 @@ To add a new Arc to the Sketch:
 #. select in the Main Menu *Sketch - > Arc* item  or
 #. click |arc.icon| **Arc** button in Sketch toolbar:
 
-There are 3 algorithms for creation of an Arc:
+There are 4 algorithms for creation of an Arc:
 
 .. image:: images/arc_base_32x32.png
    :align: left
@@ -24,6 +24,10 @@ There are 3 algorithms for creation of an Arc:
    :align: left
 **By tangent point and end point** creates an arc segment with the tangent point and the end point.
 
+.. image:: images/arc_perp_32x32.png
+   :align: left
+**By point on perpendicular line and end point** creates an arc segment perpendicular to a straight line with the start point, connected with boundary of this line, and the end point.
+
 By center and two points
 """"""""""""""""""""""""
 
@@ -75,8 +79,8 @@ and finally move the mouse and click a third time to set the passed point.
     :param real: Passed Y.
     :return: Result object.
 
-By tangent point and point
-""""""""""""""""""""""""""
+By tangent point and end point
+""""""""""""""""""""""""""""""
 
 .. image:: images/Arc_panel_tang.png
    :align: center
@@ -90,12 +94,36 @@ The tangent point by itself is a start point. The edge on which it lies will be
 
 **TUI Command**:
 
-.. py:function:: Sketch_1.addArc(TangetPoint, EndX, EndY, Inversed)
+.. py:function:: Sketch_1.addArc(TangentPoint, EndX, EndY, Inversed)
+
+    :param object: Tangent Point.
+    :param real: End X.
+    :param real: End Y.
+    :param boolean: Is inversed.
+    :return: Result object.
+
+By point on perpendicular line and end point
+""""""""""""""""""""""""""""""""""""""""""""
+
+.. image:: images/Arc_panel_perp.png
+   :align: center
+
+Select a point on a straight segment in the view to set the start point, then move the mouse and click to set the end point.
+The edge on which the start point lies will be perpendicular to the arc (the center of the arc is lying on the edge).
+
+- When entering a start point by selecting a point on segment, a Perpendicular constraint is created.
+- When entering an end point by selecting a segment, a Coincident constraint is created.
+- When entering an end point, only segments are selectable.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addArc(StartPoint, EndX, EndY, Inversed, True)
 
-    :param object: Tanget Point.
+    :param object: Start Point.
     :param real: End X.
     :param real: End Y.
     :param boolean: Is inversed.
+    :param boolean: Arc is perpendicular (always True).
     :return: Result object.
 
 Result
@@ -107,6 +135,6 @@ Created arc appears in the view.
           :align: center
 
 .. centered::
-   Circle created
+   Arc created
 
 **See Also** a sample TUI Script of :ref:`tui_create_arc` operation.
\ No newline at end of file
index bc751c01e6e451c91dfe809522f5e3b0cc153fcd..cdd84a51e0e0c9bb4ccebb130313d4225c8543c4 100644 (file)
@@ -1,3 +1,77 @@
+.. |ellipse.icon|    image:: images/ellipse.png
 
- Ellipse
- =======
+Ellipse
+=======
+
+The feature Ellipse creates an ellipse in the current Sketch.
+
+To add a new Ellipse to the Sketch:
+
+#. select in the Main Menu *Sketch - > Ellipse* item  or
+#. click |ellipse.icon| **Ellipse** button in Sketch toolbar:
+
+There are 2 algorithms for creation of an Ellipse:
+
+.. image:: images/ellipse_cent_rad_32x32.png
+   :align: left
+**By center and major semi-axes and passing points** creates an ellipse with the given center passing through given points.
+
+.. image:: images/ellipse_axes_32x32.png
+   :align: left
+**By major axis and passing point** creates an ellipse passing through the given three points.
+
+By center and major semi-axes and passing points
+""""""""""""""""""""""""""""""""""""""""""""""""
+
+.. image:: images/ellipse_panel_pt_rad.png
+   :align: center
+
+Click in the view once to set the center point, then move the mouse and click to set a point of a first semi-axis, then again move the mouse to set a point of a second semi-axis.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addEllipse(CenterX, CenterY, MajorAxisX, MajorAxisY, PassedX, PassedY, True)
+
+    :param real: Center X.
+    :param real: Center Y.
+    :param real: Major Axis X.
+    :param real: Major Axis Y.
+    :param real: Passed X.
+    :param real: Passed Y.
+    :param boolean: True mentions that the first coordinates define the center of the ellipse.
+    :return: Result object.
+
+By major axis and passing point
+"""""""""""""""""""""""""""""""
+
+.. image:: images/ellipse_panel_3pt.png
+   :align: center
+
+Click in the view once to set a first point of a first axis, then move the mouse and click to set a second point of the first axis, then again move the mouse to set a point of a second semi-axis.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addEllipse(MajorAxisStartX, MajorAxisStartY, MajorAxisEndX, MajorAxisEndY, PassedX, PassedY, False)
+
+    :param real: Major Axis Start X.
+    :param real: Major Axis Start Y.
+    :param real: Major Axis End X.
+    :param real: Major Axis End Y.
+    :param real: Passed X.
+    :param real: Passed Y.
+    :param boolean: False mentions that the first coordinates define the start point of major axis of the ellipse.
+    :return: Result object.
+
+Result
+""""""
+
+Created ellipse appears in the view.
+
+.. image:: images/ellipse_result.png
+          :align: center
+
+.. centered::
+   Ellipse created
+
+
+**See Also** a sample TUI Script of :ref:`tui_create_ellipse` operation.
index 3d44a951d86c41603bfaa186aa6298bc53d2abb7..cad2078bf9d72f7190a411dafd2f25a817b0ffc7 100644 (file)
@@ -10,5 +10,6 @@ SketchArc_2 = Sketch_1.addArc(8.1, 56.7, 58.2, 6.6, 44.8, 69.2)
 SketchLine_3 = Sketch_1.addLine(25.0, 109.4, 68.1, 153.6)
 SketchLine_3.setAuxiliary(True)
 SketchArc_3 = Sketch_1.addArc(SketchLine_3.startPoint(), 92.1, 34.0, True)
+SketchArc_4 = Sketch_1.addArc(SketchLine_3.endPoint(), 150.0, 10.0, True, True)
 model.do()
 model.end()
diff --git a/src/SketchPlugin/doc/examples/ellipse.py b/src/SketchPlugin/doc/examples/ellipse.py
new file mode 100644 (file)
index 0000000..870489d
--- /dev/null
@@ -0,0 +1,9 @@
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchEllipse_1 = Sketch_1.addEllipse(-70, 5, -25, 10, -50, 40, True)
+SketchEllipse_2 = Sketch_1.addEllipse(30, 50, 90, 10, 70, 50, False)
+model.do()
+model.end()
diff --git a/src/SketchPlugin/doc/examples/elliptic_arc.py b/src/SketchPlugin/doc/examples/elliptic_arc.py
new file mode 100644 (file)
index 0000000..31891b4
--- /dev/null
@@ -0,0 +1,9 @@
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchEllipticArc_1 = Sketch_1.addEllipticArc(-130.9349397590362, 14.84578313253013, -130.1669839639096, 36.73252329363673, -113.8987951807229, 13.87228915662651, -144.7734498958671, 30.30133508641346, False)
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchLine_1, SketchLine_2] = SketchEllipticArc_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+model.end()
index 089d50730b22e133d05303bec7a93f95039ff42e..fd1b9aa8222b272545ae6b5234fda67fe2cffc7d 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_panel_3pt.png and b/src/SketchPlugin/doc/images/Arc_panel_3pt.png differ
index 9a5b9ed4a95cb5807180d49b6668a17cf2a36b7b..f702ca8bed48e2fd0eba6e80765590ff7ef3af5a 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_panel_base.png and b/src/SketchPlugin/doc/images/Arc_panel_base.png differ
diff --git a/src/SketchPlugin/doc/images/Arc_panel_perp.png b/src/SketchPlugin/doc/images/Arc_panel_perp.png
new file mode 100644 (file)
index 0000000..71d0a54
Binary files /dev/null and b/src/SketchPlugin/doc/images/Arc_panel_perp.png differ
index ca02054011cb4b73ec2d6e950eda6e196622d55f..a14b891acaecd71f2a634254fdb70364cd604b42 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_panel_tang.png and b/src/SketchPlugin/doc/images/Arc_panel_tang.png differ
index b23a9022b44b0b5515292be17d51c26b7e8f31e4..1772eda3593471d5ad235c2c5cd31c86b6feae13 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_res.png and b/src/SketchPlugin/doc/images/Arc_res.png differ
index 0747cff0c00df58b083515f5d0e76c2046f22008..f1c0b928e1026e108a1e9ef08bda239aee007c14 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Perpendicular_panel.png and b/src/SketchPlugin/doc/images/Perpendicular_panel.png differ
diff --git a/src/SketchPlugin/doc/images/arc_perp_32x32.png b/src/SketchPlugin/doc/images/arc_perp_32x32.png
new file mode 100644 (file)
index 0000000..56f9f83
Binary files /dev/null and b/src/SketchPlugin/doc/images/arc_perp_32x32.png differ
diff --git a/src/SketchPlugin/doc/images/ellipse.png b/src/SketchPlugin/doc/images/ellipse.png
new file mode 100644 (file)
index 0000000..f1f6265
Binary files /dev/null and b/src/SketchPlugin/doc/images/ellipse.png differ
diff --git a/src/SketchPlugin/doc/images/ellipse_axes_32x32.png b/src/SketchPlugin/doc/images/ellipse_axes_32x32.png
new file mode 100644 (file)
index 0000000..a1a83d5
Binary files /dev/null and b/src/SketchPlugin/doc/images/ellipse_axes_32x32.png differ
diff --git a/src/SketchPlugin/doc/images/ellipse_cent_rad_32x32.png b/src/SketchPlugin/doc/images/ellipse_cent_rad_32x32.png
new file mode 100644 (file)
index 0000000..5781d8c
Binary files /dev/null and b/src/SketchPlugin/doc/images/ellipse_cent_rad_32x32.png differ
diff --git a/src/SketchPlugin/doc/images/ellipse_panel_3pt.png b/src/SketchPlugin/doc/images/ellipse_panel_3pt.png
new file mode 100644 (file)
index 0000000..fe10e4f
Binary files /dev/null and b/src/SketchPlugin/doc/images/ellipse_panel_3pt.png differ
diff --git a/src/SketchPlugin/doc/images/ellipse_panel_pt_rad.png b/src/SketchPlugin/doc/images/ellipse_panel_pt_rad.png
new file mode 100644 (file)
index 0000000..91e196d
Binary files /dev/null and b/src/SketchPlugin/doc/images/ellipse_panel_pt_rad.png differ
diff --git a/src/SketchPlugin/doc/images/ellipse_result.png b/src/SketchPlugin/doc/images/ellipse_result.png
new file mode 100644 (file)
index 0000000..c000454
Binary files /dev/null and b/src/SketchPlugin/doc/images/ellipse_result.png differ
diff --git a/src/SketchPlugin/doc/images/elliptic_arc.png b/src/SketchPlugin/doc/images/elliptic_arc.png
new file mode 100644 (file)
index 0000000..4bd841f
Binary files /dev/null and b/src/SketchPlugin/doc/images/elliptic_arc.png differ
diff --git a/src/SketchPlugin/doc/images/elliptic_arc_panel.png b/src/SketchPlugin/doc/images/elliptic_arc_panel.png
new file mode 100644 (file)
index 0000000..81bc130
Binary files /dev/null and b/src/SketchPlugin/doc/images/elliptic_arc_panel.png differ
diff --git a/src/SketchPlugin/doc/images/elliptic_arc_result.png b/src/SketchPlugin/doc/images/elliptic_arc_result.png
new file mode 100644 (file)
index 0000000..dad8e61
Binary files /dev/null and b/src/SketchPlugin/doc/images/elliptic_arc_result.png differ
index 0cf532283f5edd4e571a22243b09692143f33836..dbcbc9b3b6efcff6aaa70229d43cd535a7aa3c59 100644 (file)
@@ -1,15 +1,16 @@
 .. _sketchPerpendicular:
-.. |perpendicular.icon|    image:: images/perpendicular.png
+.. |Perpendicular.icon|    image:: images/Perpendicular.png
 
 Perpendicular constraint
 ========================
 
 Perpendicular constraint fixes two lines at 90 degrees to one another.
+For a line and a circle/arc the perpendicular constraint fixes the center of circle/arc to be on a line.
 
 To create a Perpendicular constraint in the active Sketch:
 
 #. select in the Main Menu *Sketch - > Perpendicular* item  or
-#. click |perpendicular.icon| **Perpendicular** button in Sketch toolbar:
+#. click |Perpendicular.icon| **Perpendicular** button in Sketch toolbar:
 
 Property panel:
 
@@ -18,10 +19,12 @@ Property panel:
 
 Input fields:
 
-- **First line** is the first line selected in the view.
-- **Second line** is the second line selected in the view.
+- **First object** is the first line, circle or arc selected in the view.
+- **Second object** is the second line, circle or arc selected in the view.
 
-After the lines are selected, a special sign will be added to each of them in the view.
+After the objects are selected, a special sign will be added to each of them in the view.
+
+If one of selected objects is circular, then another has to be a straight line.
 
 **TUI Command**:
 
@@ -37,7 +40,7 @@ Result
 Created Perpendicular constraint appears in the view.
 
 .. image:: images/Perpendicular_res.png
-          :align: center
+           :align: center
 
 .. centered::
    Created perpendicular constraint
diff --git a/src/SketchPlugin/icons/arc_perp_32x32.png b/src/SketchPlugin/icons/arc_perp_32x32.png
new file mode 100644 (file)
index 0000000..56f9f83
Binary files /dev/null and b/src/SketchPlugin/icons/arc_perp_32x32.png differ
index 6f311635df843c220850f9dc54ac7459bf1c15db..f1f62658ef8008ebc60e6759514f24255398f7e9 100644 (file)
Binary files a/src/SketchPlugin/icons/ellipse.png and b/src/SketchPlugin/icons/ellipse.png differ
diff --git a/src/SketchPlugin/icons/ellipse_axes_32x32.png b/src/SketchPlugin/icons/ellipse_axes_32x32.png
new file mode 100644 (file)
index 0000000..a1a83d5
Binary files /dev/null and b/src/SketchPlugin/icons/ellipse_axes_32x32.png differ
diff --git a/src/SketchPlugin/icons/ellipse_cent_rad_32x32.png b/src/SketchPlugin/icons/ellipse_cent_rad_32x32.png
new file mode 100644 (file)
index 0000000..5781d8c
Binary files /dev/null and b/src/SketchPlugin/icons/ellipse_cent_rad_32x32.png differ
diff --git a/src/SketchPlugin/icons/elliptic_arc.png b/src/SketchPlugin/icons/elliptic_arc.png
new file mode 100644 (file)
index 0000000..4bd841f
Binary files /dev/null and b/src/SketchPlugin/icons/elliptic_arc.png differ
diff --git a/src/SketchPlugin/icons/radius_major.png b/src/SketchPlugin/icons/radius_major.png
new file mode 100644 (file)
index 0000000..ef86a07
Binary files /dev/null and b/src/SketchPlugin/icons/radius_major.png differ
diff --git a/src/SketchPlugin/icons/radius_minor.png b/src/SketchPlugin/icons/radius_minor.png
new file mode 100644 (file)
index 0000000..3be332a
Binary files /dev/null and b/src/SketchPlugin/icons/radius_minor.png differ
index 118bec3ac059912f37d713c125f5f615b27bac1d..1476a14926570dc655e341a8be0bb9b4a7d2b8ad 100644 (file)
@@ -5,6 +5,7 @@
         id="Sketch"
         nested="SketchPoint SketchIntersectionPoint SketchLine
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
+                SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
                 SketchRectangle
                 SketchProjection
                 SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
@@ -12,7 +13,7 @@
                 SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical
                 SketchConstraintEqual SketchConstraintTangent
                 SketchFillet SketchSplit SketchTrim
-                SketchConstraintCoincidence
+                SketchConstraintCoincidence SketchConstraintCoincidenceInternal
                 SketchConstraintMirror SketchConstraintAngle
                 SketchMultiRotation SketchMultiTranslation
                 SketchConstraintCollinear SketchConstraintMiddle"
@@ -24,7 +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="SolverDOF"/>  -->
         <label id="SolverError" styleSheet="color : red; font : bold"/>
         <validator id="SketchPlugin_SolverErrorValidator"/>
       </feature>
                                  enable_value="enable_by_preferences"/>
         <sketch-2dpoint_selector id="EndPoint" accept_expressions="0" title="End point" tooltip="End point coordinates"
                                  enable_value="enable_by_preferences"/>
-        <labelvalue id="LineLength" accept_expressions="0" label="Length:" default="computed" icon="icons/Sketch/distance_value.png"
+        <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"/>
         <validator id="GeomValidators_Different" parameters="StartPoint,EndPoint"/>
       </feature>
     </group>
-    <group id="Circular geometry">
+    <group id="Conical geometry">
       <!-- SketchCircle is a hidden feature. It is created inside SketchMacroCircle. -->
       <feature id="SketchCircle"
                title="Circle"
@@ -64,7 +65,7 @@
                                  enable_value="enable_by_preferences"/>
         <labelvalue id="circle_radius"
                     icon="icons/Sketch/radius.png"
-                    label="Radius:"
+                    label="Radius"
                     tooltip="Set radius"
                     default="computed"
                     accept_expressions="0"
         </toolbox>
         <labelvalue id="circle_radius"
                     icon="icons/Sketch/radius.png"
-                    label="Radius:"
+                    label="Radius"
                     tooltip="Set radius"
                     default="computed"
                     accept_expressions="0"
                     obligatory="0"
                     enable_value="enable_by_preferences">
-          <validator id="GeomValidators_Positive"/>
         </labelvalue>
         <boolvalue id="Auxiliary"
                    tooltip="Construction element"
         <validator id="GeomValidators_Different" parameters="center_point,start_point,end_point"/>
         <labelvalue id="radius"
                     icon="icons/Sketch/radius.png"
-                    label="Radius:"
+                    label="Radius"
                     tooltip="Set radius"
                     accept_expressions="0"
                     min="0"
         </labelvalue>
         <labelvalue id="angle"
                     icon="icons/Sketch/angle.png"
-                    label="Angle:"
+                    label="Angle"
                     tooltip="Set angle"
                     default="0"
                     use_reset="false"
               <validator id="SketchPlugin_ArcEndPointValidator" parameters="end_point_ref"/>
             </sketch-2dpoint_selector>
           </box>
+          <box id="by_transversal_line"
+               icon="icons/Sketch/arc_perp_32x32.png"
+               title="Perpendicular to line">
+            <sketch_shape_selector id="tangent_point"
+                                   label="Point on the perpendicular line"
+                                   tooltip="Select point on line"
+                                   shape_types="vertex">
+              <validator id="SketchPlugin_ArcTransversalPoint"/>
+            </sketch_shape_selector>
+            <sketch-2dpoint_selector id="end_point_3"
+                                     reference_attribute="end_point_ref"
+                                     title="End point"
+                                     tooltip="End point"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences">
+              <validator id="SketchPlugin_ArcEndPointValidator" parameters="end_point_ref"/>
+            </sketch-2dpoint_selector>
+          </box>
         </toolbox>
         <labelvalue id="radius"
                     icon="icons/Sketch/radius.png"
-                    label="Radius:"
+                    label="Radius"
                     tooltip="Set radius"
                     accept_expressions="0"
                     min="0"
         </labelvalue>
         <labelvalue id="angle"
                     icon="icons/Sketch/angle.png"
-                    label="Angle:"
+                    label="Angle"
                     tooltip="Set angle"
                     default="0"
                     use_reset="false"
         </sketch_shape_selector>
         <!--<validator id="PartSet_FilletSelection"/>-->
       </feature>
-      <!--  SketchSplit  -->
-      <feature id="SketchSplit" title="Split"
-               tooltip="Cut selected segment arc or circle on existing coincident points"
-               icon="icons/Sketch/split.png"
-               helpfile="splitFeature.html">
-        <sketch_feature_point_selector
-            id="SelectedObject"
-            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
-            label="Segment"
-            tooltip="Select segment for split"
-            shape_types="edge"
-            use_external="false">
-          <validator id="SketchPlugin_SplitValidator"/>
-        </sketch_feature_point_selector>
-        <validator id="PartSet_SplitSelection"/>
-      </feature>
-      <!--  SketchTrim  -->
-      <feature id="SketchTrim" title="Trim"
-               tooltip="Trim selected segment arc or circle on intersection points nearest to the graphic selection"
-               icon="icons/Sketch/trim.png"
-               helpfile="trimFeature.html">
-        <sketch_feature_point_selector
-            id="SelectedObject"
-            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
-            label="Segment"
-            tooltip="Select segment for trim"
-            shape_types="edge"
-            use_external="false">
-          <validator id="SketchPlugin_TrimValidator"/>
-        </sketch_feature_point_selector>
-        <validator id="PartSet_SplitSelection"/>
-      </feature>
-    </group>
 
-<excluded>
-    <group id="Elliptic geometry">
       <!-- SketchEllipse is a hidden feature. It is created inside SketchMacroEllipse. -->
       <feature id="SketchEllipse"
                title="Ellipse"
                                  tooltip="Center coordinates"
                                  accept_expressions="0"
                                  enable_value="enable_by_preferences"/>
-        <sketch-2dpoint_selector id="ellipse_focus"
-                                 title="Focus"
+        <sketch-2dpoint_selector id="ellipse_first_focus"
+                                 title="First focus"
                                  tooltip="Focus coordinates"
                                  accept_expressions="0"
                                  enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_second_focus"
+                                 title="Second focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_major_axis_start_point"
+                                 title="Major axis start"
+                                 tooltip="Coordinates of point on negative direction of major axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_major_axis_end_point"
+                                 title="Major axis end"
+                                 tooltip="Coordinates of point on positive direction of major axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_minor_axis_start_point"
+                                 title="Minor axis start"
+                                 tooltip="Coordinates of point on negative direction of minor axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_minor_axis_end_point"
+                                 title="Minor axis end"
+                                 tooltip="Coordinates of point on positive direction of minor axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
         <labelvalue id="ellipse_major_radius"
-                    icon="icons/Sketch/radius.png"
-                    label="Major radius:"
+                    icon="icons/Sketch/radius_major.png"
+                    label="Major radius"
                     tooltip="Set major radius"
                     default="computed"
                     accept_expressions="0"
                     enable_value="enable_by_preferences">
         </labelvalue>
         <labelvalue id="ellipse_minor_radius"
-                    icon="icons/Sketch/radius.png"
-                    label="Minor radius:"
+                    icon="icons/Sketch/radius_minor.png"
+                    label="Minor radius"
                     tooltip="Set minor radius"
                     default="computed"
                     accept_expressions="0"
                title="Ellipse"
                tooltip="Create ellipse"
                helpfile="ellipseFeature.html">
-        <sketch-2dpoint_selector id="center_point"
-                                 reference_attribute="center_point_ref"
+        <toolbox id="ellipse_type" modified_in_edit="edit_ellipse_type">
+          <box id="by_center_axis_point"
+               icon="icons/Sketch/ellipse_cent_rad_32x32.png"
+               title="Center, major semi-axis and passing point">
+            <sketch-2dpoint_selector id="first_point"
+                                     reference_attribute="first_point_ref"
+                                     title="Center point"
+                                     tooltip="Center point coordinates"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences"/>
+            <sketch-2dpoint_selector id="second_point"
+                                     reference_attribute="second_point_ref"
+                                     title="Major axis point"
+                                     tooltip="Major axis point coordinates"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences"/>
+            <sketch-2dpoint_selector id="passed_point"
+                                     reference_attribute="passed_point_ref"
+                                     title="Passed point"
+                                     tooltip="Passed point coordinates"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences"/>
+          </box>
+          <box id="by_major_axis_and_point"
+               icon="icons/Sketch/ellipse_axes_32x32.png"
+               title="Major axis and passing point">
+            <sketch-2dpoint_selector id="first_point_1"
+                                     reference_attribute="first_point_ref_1"
+                                     title="Major axis start point"
+                                     tooltip="Major axis start point coordinates"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences"/>
+            <sketch-2dpoint_selector id="second_point_1"
+                                     reference_attribute="second_point_ref_1"
+                                     title="Major axis end point"
+                                     tooltip="Major axis end point coordinates"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences"/>
+            <sketch-2dpoint_selector id="passed_point_1"
+                                     reference_attribute="passed_point_ref_1"
+                                     title="Passed point"
+                                     tooltip="Passed point coordinates"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences"/>
+          </box>
+        </toolbox>
+        <labelvalue id="major_radius"
+                    icon="icons/Sketch/radius_major.png"
+                    label="Major radius"
+                    tooltip="Set major radius"
+                    default="computed"
+                    accept_expressions="0"
+                    obligatory="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <labelvalue id="minor_radius"
+                    icon="icons/Sketch/radius_minor.png"
+                    label="Minor radius"
+                    tooltip="Set minor radius"
+                    default="computed"
+                    accept_expressions="0"
+                    obligatory="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <boolvalue id="Auxiliary"
+                   tooltip="Construction element"
+                   label="Auxiliary"
+                   default="false"
+                   obligatory="0"/>
+      </feature>
+
+      <!-- SketchEllipticArc is a hidden feature. It is created inside SketchMacroEllipse. -->
+      <feature id="SketchEllipticArc"
+               title="Elliptic arc"
+               tooltip="Create elliptic arc"
+               icon="icons/Sketch/elliptic_arc.png"
+               internal="1">
+        <sketch-2dpoint_selector id="ellipse_center"
+                                 title="Center"
+                                 tooltip="Center coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_first_focus"
+                                 title="First focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_second_focus"
+                                 title="Second focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_major_axis_start_point"
+                                 title="Major axis start"
+                                 tooltip="Coordinates of point on negative direction of major axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_major_axis_end_point"
+                                 title="Major axis end"
+                                 tooltip="Coordinates of point on positive direction of major axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_minor_axis_start_point"
+                                 title="Minor axis start"
+                                 tooltip="Coordinates of point on negative direction of minor axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_minor_axis_end_point"
+                                 title="Minor axis end"
+                                 tooltip="Coordinates of point on positive direction of minor axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="start_point"
+                                 title="Start point"
+                                 tooltip="Arc start point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="end_point"
+                                 title="End point"
+                                 tooltip="Arc end point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <labelvalue id="ellipse_major_radius"
+                    icon="icons/Sketch/radius_major.png"
+                    label="Major radius"
+                    tooltip="Set major radius"
+                    default="computed"
+                    accept_expressions="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <labelvalue id="ellipse_minor_radius"
+                    icon="icons/Sketch/radius_minor.png"
+                    label="Minor radius"
+                    tooltip="Set minor radius"
+                    default="computed"
+                    accept_expressions="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+      </feature>
+      <!-- SketchMacroEllipticArc -->
+      <feature id="SketchMacroEllipticArc"
+               icon="icons/Sketch/elliptic_arc.png"
+               title="Elliptic arc"
+               tooltip="Create elliptic arc"
+               helpfile="ellipseFeature.html">
+        <sketch-2dpoint_selector id="center"
+                                 reference_attribute="center_ref"
                                  title="Center point"
                                  tooltip="Center point coordinates"
                                  accept_expressions="0"
                                  tooltip="Major axis point coordinates"
                                  accept_expressions="0"
                                  enable_value="enable_by_preferences"/>
-        <sketch-2dpoint_selector id="passed_point"
-                                 reference_attribute="passed_point_ref"
-                                 title="Passed point"
-                                 tooltip="Passed point coordinates"
+        <sketch-2dpoint_selector id="start_point"
+                                 reference_attribute="start_point_ref"
+                                 title="Start point"
+                                 tooltip="Arc start point coordinates"
                                  accept_expressions="0"
-                                 enable_value="enable_by_preferences">
-<!--          <validator id="SketchPlugin_CirclePassedPointValidator"/> -->
-        </sketch-2dpoint_selector>
-<!--        <validator id="GeomValidators_Different" parameters="center_point_ref,passed_point_ref"/> -->
-        <labelvalue id="ellipse_major_radius"
-                    icon="icons/Sketch/radius.png"
-                    label="Major radius:"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="end_point"
+                                 reference_attribute="end_point_ref"
+                                 title="End point"
+                                 tooltip="Arc end point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <labelvalue id="major_radius"
+                    icon="icons/Sketch/radius_major.png"
+                    label="Major radius"
                     tooltip="Set major radius"
                     default="computed"
                     accept_expressions="0"
                     obligatory="0"
                     enable_value="enable_by_preferences">
-          <validator id="GeomValidators_Positive"/>
         </labelvalue>
-        <labelvalue id="ellipse_minor_radius"
-                    icon="icons/Sketch/radius.png"
-                    label="Minor radius:"
+        <labelvalue id="minor_radius"
+                    icon="icons/Sketch/radius_minor.png"
+                    label="Minor radius"
                     tooltip="Set minor radius"
                     default="computed"
                     accept_expressions="0"
                     obligatory="0"
                     enable_value="enable_by_preferences">
-          <validator id="GeomValidators_Positive"/>
         </labelvalue>
         <boolvalue id="Auxiliary"
                    tooltip="Construction element"
                    obligatory="0"/>
       </feature>
     </group>
-</excluded>
+
+    <group id="Segmentation">
+      <!--  SketchSplit  -->
+      <feature id="SketchSplit" title="Split"
+               tooltip="Cut selected segment arc or circle on existing coincident points"
+               icon="icons/Sketch/split.png"
+               helpfile="splitFeature.html">
+        <sketch_feature_point_selector
+            id="SelectedObject"
+            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
+            label="Segment"
+            tooltip="Select segment for split"
+            shape_types="edge"
+            use_external="false">
+          <validator id="SketchPlugin_SplitValidator"/>
+        </sketch_feature_point_selector>
+        <validator id="PartSet_SplitSelection"/>
+      </feature>
+      <!--  SketchTrim  -->
+      <feature id="SketchTrim" title="Trim"
+               tooltip="Trim selected segment arc or circle on intersection points nearest to the graphic selection"
+               icon="icons/Sketch/trim.png"
+               helpfile="trimFeature.html">
+        <sketch_feature_point_selector
+            id="SelectedObject"
+            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
+            label="Segment"
+            tooltip="Select segment for trim"
+            shape_types="edge"
+            use_external="false">
+          <validator id="SketchPlugin_TrimValidator"/>
+        </sketch_feature_point_selector>
+        <validator id="PartSet_SplitSelection"/>
+      </feature>
+    </group>
 
     <group id="Projection">
       <!-- Projected feature -->
           <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityC"/>
         </sketch_shape_selector>
         <sketch_multi_selector id="ConstraintMirrorList"
-            label="Segments:"
+            label="Segments"
             tooltip="Select list of objects to be mirrored"
             shape_types="Edges"
             use_external="true"
         tooltip="Copy objects and move"
         helpfile="translationFeature.html">
         <sketch_multi_selector id="MultiTranslationList"
-            label="Segments:"
+            label="Segments"
             tooltip="Select list of objects to be translated"
             shape_types="Edges"
             use_external="true"
         tooltip="Copy objects and rotate"
         helpfile="rotationFeature.html">
         <sketch_multi_selector id="MultiRotationList"
-            label="Segments:"
+            label="Segments"
             tooltip="Select list of objects to be rotated"
             shape_types="Edges"
             use_external="true"
     </group>
 
     <group id="Dimensional constraints">
-    <!--  SketchConstraintDistance  -->
+      <!--  SketchConstraintDistance  -->
       <feature
         id="SketchConstraintDistance"
         title="Distance"
       <feature id="SketchConstraintRigid" title="Fixed" tooltip="Fix an object" icon="icons/Sketch/fixed.png"
                helpfile="rigidFeature.html">
         <sketch_shape_selector id="ConstraintEntityA" label="Object"
-                        tooltip="Select point, line end point, line, center of circle or arc."
+                        tooltip="Select point, curve or its boundary point."
                         shape_types="edge vertex">
-          <validator id="GeomValidators_ShapeType" parameters="vertex,line,circle"/>
+          <validator id="GeomValidators_ShapeType" parameters="vertex,edge"/>
           <validator id="SketchPlugin_NotFixed"/>
         </sketch_shape_selector>
         <validator id="PartSet_RigidSelection"/>
         <validator id="PartSet_ParallelSelection"/>
       </feature>
 
-    <!--  SketchConstraintPerpendicular  -->
+      <!--  SketchConstraintPerpendicular  -->
       <feature id="SketchConstraintPerpendicular" title="Perpendicular"
-               tooltip="Create constraint defining two perpendicular lines"
+               tooltip="Create constraint defining two orthogonal objects"
                icon="icons/Sketch/perpendicular.png"
                helpfile="perpendicularFeature.html">
         <sketch_shape_selector id="ConstraintEntityA"
-            label="First line" tooltip="Select a line"
+            label="First object" tooltip="Select line or arc"
             shape_types="edge">
           <validator id="PartSet_DifferentObjects"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
-            <validator id="GeomValidators_ShapeType" parameters="line"/>
+          <validator id="SketchPlugin_PerpendicularAttr" parameters="ConstraintEntityB"/>
+          <validator id="GeomValidators_ShapeType" parameters="edge"/>
         </sketch_shape_selector>
 
         <sketch_shape_selector id="ConstraintEntityB"
-            label="Second line" tooltip="Select a line"
+            label="Second object" tooltip="Select line or arc"
             shape_types="edge">
-            <validator id="PartSet_DifferentObjects"/>
+          <validator id="PartSet_DifferentObjects"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
-            <validator id="GeomValidators_ShapeType" parameters="line"/>
+          <validator id="SketchPlugin_PerpendicularAttr" parameters="ConstraintEntityA"/>
+          <validator id="GeomValidators_ShapeType" parameters="edge"/>
         </sketch_shape_selector>
         <validator id="PartSet_PerpendicularSelection"/>
       </feature>
         </sketch_shape_selector>
         <validator id="PartSet_CoincidentSelection"/>
       </feature>
+      <!--  SketchConstraintCoincidenceInternal  -->
+      <feature id="SketchConstraintCoincidenceInternal" title="Internal Coincidence" tooltip="Internal coincidence" icon="icons/Sketch/coincedence.png"
+               helpfile="coincedenceFeature.html" internal="1">
+        <sketch_shape_selector id="ConstraintEntityA" label="First object" tooltip="Select a first object" shape_types="vertex">
+          <validator id="PartSet_DifferentObjects"/>
+          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+        </sketch_shape_selector>
+        <sketch_shape_selector id="ConstraintEntityB" label="Second object" tooltip="Select a second object" shape_types="vertex">
+          <validator id="PartSet_DifferentObjects"/>
+          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+          <validator id="SketchPlugin_CoincidenceAttr" parameters="ConstraintEntityA"/>
+        </sketch_shape_selector>
+        <validator id="PartSet_CoincidentSelection"/>
+      </feature>
 
       <!--  SketchConstraintMiddle  -->
       <feature id="SketchConstraintMiddle" title="Middle point" tooltip="Create constraint for setting middle point on a line"
 
       <!--  SketchConstraintEqual  -->
       <feature id="SketchConstraintEqual" title="Equal"
-        tooltip="Create constraint defining equal lengths of two lines or line and arc or equal radii of two arcs or two circles or arc and circle"
+        tooltip="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"
         icon="icons/Sketch/equal.png"
                helpfile="equalFeature.html">
         <sketch_shape_selector id="ConstraintEntityA"
-            label="First object" tooltip="Select line, circle or arc" shape_types="edge">
+            label="First object" tooltip="Select edge" shape_types="edge">
           <validator id="PartSet_DifferentObjects"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
         </sketch_shape_selector>
 
         <sketch_shape_selector id="ConstraintEntityB"
-            label="Second object" tooltip="Select line, circle or arc" shape_types="edge">
+            label="Second object" tooltip="Select edge" shape_types="edge">
           <validator id="SketchPlugin_EqualAttr" parameters="ConstraintEntityA"/>
           <validator id="PartSet_DifferentObjects"/>
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
         <validator id="PartSet_EqualSelection"/>
       </feature>
 
-    <!--  SketchConstraintCollinear  -->
+      <!--  SketchConstraintCollinear  -->
       <feature id="SketchConstraintCollinear" title="Collinear" tooltip="Create constraint defining collinearity of two lines"
                icon="icons/Sketch/collinear.png"
                helpfile="collinearFeature.html">
index 2c4b5899640a08abe9e1aeea2a8c2e2624923fea..fafa0372ac5780f3b4d4905d4985d8a3f2498eca 100644 (file)
@@ -50,6 +50,7 @@ SET(SKETCHSOLVER_CONSTRAINT_HEADERS
     SketchSolver_ConstraintMiddle.h
     SketchSolver_ConstraintMirror.h
     SketchSolver_ConstraintFixed.h
+    SketchSolver_ConstraintPerpendicular.h
     SketchSolver_ConstraintTangent.h
     SketchSolver_ConstraintMulti.h
     SketchSolver_ConstraintMultiRotation.h
@@ -74,6 +75,7 @@ SET(SKETCHSOLVER_CONSTRAINT_SOURCES
     SketchSolver_ConstraintMiddle.cpp
     SketchSolver_ConstraintMirror.cpp
     SketchSolver_ConstraintFixed.cpp
+    SketchSolver_ConstraintPerpendicular.cpp
     SketchSolver_ConstraintTangent.cpp
     SketchSolver_ConstraintMulti.cpp
     SketchSolver_ConstraintMultiRotation.cpp
@@ -91,6 +93,7 @@ SET(SKETCHSOLVER_LIBRARIES
 
 SET(SKETCHSOLVER_TEXT_RESOURCES
     SketchSolver_msg_en.ts
+    SketchSolver_msg_fr.ts
 )
 
 INCLUDE_DIRECTORIES(
index 7a961fcad378ae7db1a3048a2b30258e77514f20..fab1f0356d3f363e00fff20140a125395f3172e9 100644 (file)
@@ -25,10 +25,11 @@ SET(PLANEGCSSOLVER_HEADERS
     PlaneGCSSolver_Storage.h
     PlaneGCSSolver_ConstraintWrapper.h
     PlaneGCSSolver_EdgeWrapper.h
-    PlaneGCSSolver_EdgeWrapper.h
+    PlaneGCSSolver_EntityWrapper.h
     PlaneGCSSolver_PointWrapper.h
     PlaneGCSSolver_ScalarWrapper.h
     PlaneGCSSolver_AngleWrapper.h
+    PlaneGCSSolver_BooleanWrapper.h
     PlaneGCSSolver_Tools.h
 )
 
@@ -40,6 +41,7 @@ SET(PLANEGCSSOLVER_SOURCES
     PlaneGCSSolver_PointWrapper.cpp
     PlaneGCSSolver_ScalarWrapper.cpp
     PlaneGCSSolver_AngleWrapper.cpp
+    PlaneGCSSolver_BooleanWrapper.cpp
     PlaneGCSSolver_Tools.cpp
 )
 
index ea6eef78c0d289b9c0f6b0b698f5966c46bdf60a..ca463c53d70f063745d9f062bf7c250cc6810d24 100644 (file)
@@ -21,6 +21,7 @@
 #include <PlaneGCSSolver_AttributeBuilder.h>
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
 
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
@@ -44,6 +45,16 @@ static double* createParameter(PlaneGCSSolver_Storage* theStorage)
   return theStorage ? theStorage->createParameter() : (new double(0));
 }
 
+static EntityWrapperPtr createBoolean(const AttributePtr& theAttribute)
+{
+  BooleanWrapperPtr aWrapper;
+  AttributeBooleanPtr aBoolean =
+      std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
+  if (aBoolean)
+    aWrapper = BooleanWrapperPtr(new PlaneGCSSolver_BooleanWrapper(aBoolean->value()));
+  return aWrapper;
+}
+
 static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
                                      PlaneGCSSolver_Storage* theStorage)
 {
@@ -99,6 +110,8 @@ EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
     aResult = createPoint(theAttribute, myStorage);
   if (!aResult)
     aResult = createScalar(theAttribute, myStorage);
+  if (!aResult)
+    aResult = createBoolean(theAttribute);
   if (aResult && !myStorage)
     aResult->setExternal(true);
   return aResult;
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_BooleanWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_BooleanWrapper.cpp
new file mode 100644 (file)
index 0000000..225c434
--- /dev/null
@@ -0,0 +1,25 @@
+// 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 <PlaneGCSSolver_BooleanWrapper.h>
+
+PlaneGCSSolver_BooleanWrapper::PlaneGCSSolver_BooleanWrapper(bool theParam)
+  : myValue(theParam)
+{
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_BooleanWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_BooleanWrapper.h
new file mode 100644 (file)
index 0000000..3bd1d8d
--- /dev/null
@@ -0,0 +1,51 @@
+// 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 PlaneGCSSolver_BooleanWrapper_H_
+#define PlaneGCSSolver_BooleanWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+
+/**
+ *  Wrapper providing storage for boolean values.
+ */
+class PlaneGCSSolver_BooleanWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+  PlaneGCSSolver_BooleanWrapper(bool theValue);
+
+  /// \brief Change value of parameter
+  void setValue(bool theValue)
+  { myValue = theValue; }
+  /// \brief Return value of parameter
+  bool value() const
+  { return myValue; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const
+  { return ENTITY_BOOLEAN; }
+
+protected:
+  bool myValue;
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_BooleanWrapper> BooleanWrapperPtr;
+
+#endif
index fccd4d718b0cea8c7dd3eeb43275825a3f3fef60..0f46e7544d73920b8f3349618b3f1a6dc7c4d982 100644 (file)
@@ -39,17 +39,20 @@ typedef int ConstraintID;
 // Predefined values for identifiers
 const ConstraintID CID_UNKNOWN  =  0;
 const ConstraintID CID_MOVEMENT = -1;
-const ConstraintID CID_FICTIVE = 1024;
+const ConstraintID CID_FICTIVE  = 99;
 
 /// Types of entities
 enum SketchSolver_EntityType {
   ENTITY_UNKNOWN = 0,
+  ENTITY_BOOLEAN,
   ENTITY_SCALAR,
   ENTITY_ANGLE,
   ENTITY_POINT,
   ENTITY_LINE,
   ENTITY_CIRCLE,
-  ENTITY_ARC
+  ENTITY_ARC,
+  ENTITY_ELLIPSE,
+  ENTITY_ELLIPTIC_ARC
 };
 
 /// Types of constraints
@@ -57,8 +60,7 @@ enum SketchSolver_ConstraintType {
   CONSTRAINT_UNKNOWN = 0,
   CONSTRAINT_COINCIDENCE,      // base coincidence if we don't know exact type yet
   CONSTRAINT_PT_PT_COINCIDENT,
-  CONSTRAINT_PT_ON_LINE,
-  CONSTRAINT_PT_ON_CIRCLE,
+  CONSTRAINT_PT_ON_CURVE,
   CONSTRAINT_MIDDLE_POINT,
   CONSTRAINT_DISTANCE,         // base distance if we don't know the measured objects yet
   CONSTRAINT_PT_PT_DISTANCE,
@@ -72,14 +74,16 @@ enum SketchSolver_ConstraintType {
   CONSTRAINT_VERTICAL,
   CONSTRAINT_PARALLEL,
   CONSTRAINT_PERPENDICULAR,
+  CONSTRAINT_PERPENDICULAR_CURVES,
   CONSTRAINT_SYMMETRIC,
   CONSTRAINT_EQUAL,           // base equality if we don't know the measured objects yet
   CONSTRAINT_EQUAL_LINES,
   CONSTRAINT_EQUAL_LINE_ARC,
   CONSTRAINT_EQUAL_RADIUS,
+  CONSTRAINT_EQUAL_ELLIPSES,
   CONSTRAINT_TANGENT,         // base tangency if we don't know the measured objects yet
   CONSTRAINT_TANGENT_CIRCLE_LINE,
-  CONSTRAINT_TANGENT_CIRCLE_CIRCLE,
+  CONSTRAINT_TANGENT_CURVE_CURVE,
   CONSTRAINT_COLLINEAR,
   CONSTRAINT_MULTI_TRANSLATION,
   CONSTRAINT_MULTI_ROTATION
index 7ec36cf236a33507de548cfad7bde4f137c137a5..f9683203880051e28acbc8a99d0e71ef8d4cf014 100644 (file)
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <cmath>
 
+static bool isLine(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Line>(theEntity).get();
+}
+
+static bool isCircle(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Circle>(theEntity).get();
+}
+
+static bool isArc(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Arc>(theEntity).get();
+}
+
+static bool isEllipse(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Ellipse>(theEntity).get();
+}
+
+static bool isEllipticArc(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity).get();
+}
+
+
 PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
   : myEntity(theEntity)
 {
-  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(myEntity);
-  if (aLine) myType = ENTITY_LINE;
-  else {
-    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(myEntity);
-    if (anArc) myType = ENTITY_ARC;
-    else {
-      std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(myEntity);
-      if (aCircle) myType = ENTITY_CIRCLE;
-    }
-  }
+  if (isLine(myEntity))
+    myType = ENTITY_LINE;
+  else if (isArc(myEntity))
+    myType = ENTITY_ARC;
+  else if (isCircle(myEntity))
+    myType = ENTITY_CIRCLE;
+  else if (isEllipticArc(myEntity))
+    myType = ENTITY_ELLIPTIC_ARC;
+  else if (isEllipse(myEntity))
+    myType = ENTITY_ELLIPSE;
 }
 
 static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
@@ -44,23 +70,36 @@ static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
 
 bool PlaneGCSSolver_EdgeWrapper::isDegenerated() const
 {
-  static const double aSqTol = tolerance * 1e-2;
-  static const double aMaxRadius = 1e8;
+  static const double THE_SQ_TOL = tolerance * 1e-2;
+  static const double THE_ANGLE_TOL = 1.e-5;
+  static const double THE_MAX_RADIUS = 1e8;
+  static const double THE_SQ_MAX_RADIUS = THE_MAX_RADIUS * THE_MAX_RADIUS;
+
   if (myType == ENTITY_LINE) {
     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(myEntity);
-    return squareDistance(aLine->p1, aLine->p2) < aSqTol;
+    return squareDistance(aLine->p1, aLine->p2) < THE_SQ_TOL;
   }
   else if (myType == ENTITY_CIRCLE) {
     std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(myEntity);
-    return *aCircle->rad < tolerance || *aCircle->rad > aMaxRadius;
+    return *aCircle->rad < tolerance || *aCircle->rad > THE_MAX_RADIUS;
   }
   else if (myType == ENTITY_ARC) {
-    static const double anAngleTol = 1.e-5;
     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(myEntity);
     double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle);
     double aSqRadius = squareDistance(anArc->center, anArc->start);
-    return aSqRadius < aSqTol || aSqRadius > aMaxRadius * aMaxRadius || // <- arc radius
-           anAngleDiff < anAngleTol || fabs(anAngleDiff - 2*PI) < anAngleTol; // <- arc angle
+    return aSqRadius < THE_SQ_TOL || aSqRadius > THE_SQ_MAX_RADIUS || // <- arc radius
+           anAngleDiff < THE_ANGLE_TOL || fabs(anAngleDiff - 2*PI) < THE_ANGLE_TOL; // <- arc angle
+  }
+  else if (myType == ENTITY_ELLIPSE) {
+    std::shared_ptr<GCS::Ellipse> anEllipse = std::dynamic_pointer_cast<GCS::Ellipse>(myEntity);
+    return *anEllipse->radmin < tolerance || anEllipse->getRadMaj() > THE_MAX_RADIUS;
+  }
+  else if (myType == ENTITY_ELLIPTIC_ARC) {
+    std::shared_ptr<GCS::ArcOfEllipse> anArc =
+        std::dynamic_pointer_cast<GCS::ArcOfEllipse>(myEntity);
+    double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle);
+    return *anArc->radmin < THE_SQ_TOL || anArc->getRadMaj() > THE_SQ_MAX_RADIUS || // <- arc radius
+           anAngleDiff < THE_ANGLE_TOL || fabs(anAngleDiff - 2*PI) < THE_ANGLE_TOL; // <- arc angle
   }
   return false;
 }
index 9cd5bc2cbe972483cda4a46702b463805656df6c..e84b809c60ee26d62a52bc8422c42d0e76f9d86c 100644 (file)
@@ -21,6 +21,7 @@
 #define PlaneGCSSolver_EdgeWrapper_H_
 
 #include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
 #include <PlaneGCSSolver_EntityWrapper.h>
 
 /**
@@ -44,9 +45,16 @@ public:
 
   bool isDegenerated() const;
 
+  void setReversed(BooleanWrapperPtr theReversed)
+  { myReversed = theReversed; }
+
+  bool isReversed() const
+  { return myReversed ? myReversed->value() : false; }
+
 private:
   SketchSolver_EntityType myType;
   GCSCurvePtr myEntity;
+  BooleanWrapperPtr myReversed; // preferably used to control arc orientation
 };
 
 typedef std::shared_ptr<PlaneGCSSolver_EdgeWrapper> EdgeWrapperPtr;
index 0d224cbdb017bdd434389665fa2e8abb3e66263b..5eceaf63c5c20f1d63906b4584d4ee401b24eabc 100644 (file)
@@ -28,6 +28,9 @@
 #include <list>
 #include <memory>
 
+class PlaneGCSSolver_EntityWrapper;
+typedef std::shared_ptr<PlaneGCSSolver_EntityWrapper> EntityWrapperPtr;
+
 /**
  *  Wrapper providing operations with entities regardless the solver.
  */
@@ -45,10 +48,16 @@ public:
   /// \brief Return the External flag
   bool isExternal() const { return myExternal; }
 
+  /// \brief Store names of attributes and their values if necessary
+  void setAdditionalAttributes(const std::map<std::string, EntityWrapperPtr>& theAttribues)
+  { myAdditionalAttributes = theAttribues; }
+  /// \brief Return the list of additional attributes
+  const std::map<std::string, EntityWrapperPtr>& additionalAttributes() const
+  { return myAdditionalAttributes; }
+
 private:
   bool myExternal;
+  std::map<std::string, EntityWrapperPtr> myAdditionalAttributes;
 };
 
-typedef std::shared_ptr<PlaneGCSSolver_EntityWrapper> EntityWrapperPtr;
-
 #endif
index c2965e3eed652e0ada68cbee33756ff294a85b8d..400319aed4bd9804a46ec5c2c118da1d8473c9d7 100644 (file)
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
@@ -39,6 +43,9 @@ static EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes);
 static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes);
 static EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
                                   PlaneGCSSolver_Storage*      theStorage);
+static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
+static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
+                                          PlaneGCSSolver_Storage*   theStorage);
 
 
 PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
@@ -89,6 +96,12 @@ EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeat
   // Arc
   else if (aFeatureKind == SketchPlugin_Arc::ID())
     aResult = createArc(myAttributes, myStorage);
+  // Ellipse
+  else if (aFeatureKind == SketchPlugin_Ellipse::ID())
+    aResult = createEllipse(myAttributes);
+  // Arc of ellipse
+  else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
+    aResult = createEllipticArc(myAttributes, myStorage);
   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
   else if (aFeatureKind == SketchPlugin_Point::ID() ||
            aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
@@ -162,45 +175,117 @@ EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
                            PlaneGCSSolver_Storage*      theStorage)
 {
   std::shared_ptr<GCS::Arc> aNewArc(new GCS::Arc);
+  BooleanWrapperPtr isReversed;
 
   // Base attributes of arc (center, start and end points)
   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
   for (; anIt != theAttributes.end(); ++anIt) {
     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
-    if (!aPoint)
-      continue;
-
-    if (anIt->first->id() == SketchPlugin_Arc::CENTER_ID())
-      aNewArc->center = *(aPoint->point());
-    else if (anIt->first->id() == SketchPlugin_Arc::START_ID())
-      aNewArc->start = *(aPoint->point());
-    else if (anIt->first->id() == SketchPlugin_Arc::END_ID())
-      aNewArc->end = *(aPoint->point());
+    if (aPoint) {
+      if (anIt->first->id() == SketchPlugin_Arc::CENTER_ID())
+        aNewArc->center = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_Arc::START_ID())
+        aNewArc->start = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_Arc::END_ID())
+        aNewArc->end = *(aPoint->point());
+    }
+    else {
+      // reversed flag
+      isReversed = std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(anIt->second);
+    }
   }
 
-  // Additional atrtributes of arc necessary for PlaneGCS solver
+  // Additional attributes of arc necessary for PlaneGCS solver
   // (start and end angles, radius)
   aNewArc->startAngle = createParameter(theStorage);
   aNewArc->endAngle   = createParameter(theStorage);
   aNewArc->rad        = createParameter(theStorage);
 
-  static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
-  std::shared_ptr<GeomAPI_Pnt2d> aCenter(
-      new GeomAPI_Pnt2d(*aNewArc->center.x, *aNewArc->center.y));
-  std::shared_ptr<GeomAPI_Pnt2d> aStart(
-      new GeomAPI_Pnt2d(*aNewArc->start.x, *aNewArc->start.y));
+  EdgeWrapperPtr anArcWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
+  anArcWrapper->setReversed(isReversed);
+  PlaneGCSSolver_Tools::recalculateArcParameters(anArcWrapper);
 
-  *aNewArc->rad = aStart->distance(aCenter);
+  return anArcWrapper;
+}
 
-  std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
-  *aNewArc->startAngle = OX->angle(aDir);
+EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes)
+{
+  std::shared_ptr<GCS::Ellipse> aNewEllipse(new GCS::Ellipse);
 
-  aDir = std::shared_ptr<GeomAPI_Dir2d>(
-      new GeomAPI_Dir2d((*aNewArc->end.x) - aCenter->x(), (*aNewArc->end.y) - aCenter->y()));
-  *aNewArc->endAngle = OX->angle(aDir);
+  std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
 
-  return EntityWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewArc));
+  AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+    if (aPoint) {
+      if (anIt->first->id() == SketchPlugin_Ellipse::CENTER_ID())
+        aNewEllipse->center = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_Ellipse::FIRST_FOCUS_ID())
+        aNewEllipse->focus1 = *(aPoint->point());
+      else
+        anAdditionalAttributes[anIt->first->id()] = anIt->second;
+    }
+    else if (anIt->first->id() == SketchPlugin_Ellipse::MINOR_RADIUS_ID()) {
+      ScalarWrapperPtr aScalar =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+      aNewEllipse->radmin = aScalar->scalar();
+    }
+    else
+      anAdditionalAttributes[anIt->first->id()] = anIt->second;
+  }
+
+  EntityWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewEllipse));
+  anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes);
+  return anEllipseWrapper;
+}
+
+EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
+                                   PlaneGCSSolver_Storage*   theStorage)
+{
+  std::shared_ptr<GCS::ArcOfEllipse> aNewArc(new GCS::ArcOfEllipse);
+
+  BooleanWrapperPtr isReversed;
+  std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
+
+  AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+    if (aPoint) {
+      if (anIt->first->id() == SketchPlugin_EllipticArc::CENTER_ID())
+        aNewArc->center = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_EllipticArc::FIRST_FOCUS_ID())
+        aNewArc->focus1 = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_EllipticArc::START_POINT_ID())
+        aNewArc->start = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_EllipticArc::END_POINT_ID())
+        aNewArc->end = *(aPoint->point());
+      else
+        anAdditionalAttributes[anIt->first->id()] = anIt->second;
+    }
+    else if (anIt->first->id() == SketchPlugin_EllipticArc::MINOR_RADIUS_ID()) {
+      ScalarWrapperPtr aScalar =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+      aNewArc->radmin = aScalar->scalar();
+    }
+    else if (anIt->first->id() == SketchPlugin_EllipticArc::REVERSED_ID())
+      isReversed = std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(anIt->second);
+    else
+      anAdditionalAttributes[anIt->first->id()] = anIt->second;
+  }
+
+  // Additional attributes of elliptic arc necessary for PlaneGCS solver (start and end angles)
+  aNewArc->startAngle = createParameter(theStorage);
+  aNewArc->endAngle = createParameter(theStorage);
+
+  EdgeWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
+  anEllipseWrapper->setReversed(isReversed);
+  anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes);
+  PlaneGCSSolver_Tools::recalculateArcParameters(anEllipseWrapper);
+
+  return anEllipseWrapper;
 }
 
 bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
@@ -208,7 +293,8 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th
   if (theOwnerName == SketchPlugin_Arc::ID()) {
     return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
            theAttrName == SketchPlugin_Arc::START_ID() ||
-           theAttrName == SketchPlugin_Arc::END_ID();
+           theAttrName == SketchPlugin_Arc::END_ID() ||
+           theAttrName == SketchPlugin_Arc::REVERSED_ID();
   }
   else if (theOwnerName == SketchPlugin_Circle::ID()) {
     return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
@@ -218,6 +304,31 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th
     return theAttrName == SketchPlugin_Line::START_ID() ||
            theAttrName == SketchPlugin_Line::END_ID();
   }
+  else if (theOwnerName == SketchPlugin_Ellipse::ID()) {
+    return theAttrName == SketchPlugin_Ellipse::CENTER_ID() ||
+           theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() ||
+           theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() ||
+           theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ||
+           theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() ||
+           theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() ||
+           theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() ||
+           theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
+           theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
+  }
+  else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
+    return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
+  }
 
   // suppose that all remaining features are points
   return theAttrName == SketchPlugin_Point::COORD_ID();
index 4e34e8badda0541b1bc291469cb213063b7b342a..416b338b05d4dadbedc3a8da7686886c34ece178 100644 (file)
@@ -21,7 +21,7 @@
 #include <Events_LongOp.h>
 
 // Multiplier to correlate IDs of SketchPlugin constraint and primitive PlaneGCS constraints
-static const int THE_CONSTRAINT_MULT = 10;
+static const int THE_CONSTRAINT_MULT = 100;
 
 
 PlaneGCSSolver_Solver::PlaneGCSSolver_Solver()
@@ -245,9 +245,12 @@ void PlaneGCSSolver_Solver::diagnose(const GCS::Algorithm& theAlgo)
 
 void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
 {
-  if (!myConstraints.empty() &&
-      myConstraints.find(CID_MOVEMENT) == myConstraints.end())
-    return;
+  bool hasOnlyMovement = true;
+  for (ConstraintMap::iterator anIt = myConstraints.begin();
+       anIt != myConstraints.end() && hasOnlyMovement; ++anIt)
+    hasOnlyMovement = anIt->first == CID_MOVEMENT;
+  if (!hasOnlyMovement)
+    return; // regular constraints are available too
 
   if (myFictiveConstraint)
     return; // no need several fictive constraints
@@ -266,12 +269,14 @@ void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
 void PlaneGCSSolver_Solver::removeFictiveConstraint()
 {
   if (myFictiveConstraint) {
-    myEquationSystem->removeConstraint(myFictiveConstraint);
+    myEquationSystem->clearByTag(myFictiveConstraint->getTag());
     myParameters.pop_back();
 
     GCS::VEC_pD aParams = myFictiveConstraint->params();
-    for (GCS::VEC_pD::iterator anIt = aParams.begin(); anIt != aParams.end(); ++ anIt)
-      delete *anIt;
+    for (GCS::VEC_pD::iterator anIt = aParams.begin(); anIt != aParams.end(); ++anIt) {
+      double* aPar = *anIt;
+      delete aPar;
+    }
     delete myFictiveConstraint;
     myFictiveConstraint = 0;
   }
index 2f98c88138f5b3814eea5ddea799ec05508d6c5c..4f546aacce57e886154834202d6e9f626bccaec8 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <PlaneGCSSolver_Storage.h>
 #include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
 #include <PlaneGCSSolver_ConstraintWrapper.h>
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
@@ -33,6 +34,7 @@
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_Projection.h>
 
 #include <cmath>
@@ -103,7 +105,7 @@ EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
 /// \brief Update value
 static bool updateValue(const double& theSource, double& theDest)
 {
-  static const double aTol = 1000. * tolerance;
+  static const double aTol = 1.e4 * tolerance;
   bool isUpdated = fabs(theSource - theDest) > aTol;
   if (isUpdated)
     theDest = theSource;
@@ -134,6 +136,15 @@ static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity
       isUpdated = updateValue(aScalar->value(), aValue);
       if (isUpdated)
         aWrapper->setValue(aValue);
+    } else {
+      AttributeBooleanPtr aBoolean =
+          std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
+      if (aBoolean) {
+        BooleanWrapperPtr aWrapper =
+            std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(theEntity);
+        isUpdated = aWrapper->value() != aBoolean->value();
+        aWrapper->setValue(aBoolean->value());
+      }
     }
   }
 
@@ -185,7 +196,7 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
     // (do not want to add several copies of it while adding attributes)
     aRelated = createFeature(theFeature, &aBuilder);
     myFeatureMap[theFeature] = aRelated;
-    createArcConstraints(aRelated);
+    createAuxiliaryConstraints(aRelated);
     isUpdated = true;
   }
 
@@ -193,7 +204,8 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
   std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
   for (; anAttrIt != anAttributes.end(); ++anAttrIt)
     if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
-        (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId())
+        (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() ||
+        (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId())
       isUpdated = update(*anAttrIt) || isUpdated;
 
   // check external attribute is changed
@@ -212,28 +224,8 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
     notify(theFeature);
 
   // update arc
-  if (aRelated && aRelated->type() == ENTITY_ARC) {
-    /// TODO: this code should be shared with FeatureBuilder somehow
-
-    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
-        std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
-    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
-
-    static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
-    std::shared_ptr<GeomAPI_Pnt2d> aCenter(
-        new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
-    std::shared_ptr<GeomAPI_Pnt2d> aStart(
-        new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
-
-    *anArc->rad = aStart->distance(aCenter);
-
-    std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
-    *anArc->startAngle = OX->angle(aDir);
-
-    aDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
-    *anArc->endAngle = OX->angle(aDir);
-  }
+  if (aRelated)
+    PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
 
   return isUpdated;
 }
@@ -278,7 +270,7 @@ void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
   if (theEntity->isExternal())
     return;
 
-  removeArcConstraints(theEntity);
+  removeAuxiliaryConstraints(theEntity);
 
   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
   mySketchSolver->removeParameters(aParameters);
@@ -295,17 +287,17 @@ void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
   mySketchSolver->addParameters(aParameters);
   theEntity->setExternal(false);
 
-  createArcConstraints(theEntity);
+  createAuxiliaryConstraints(theEntity);
 
   myNeedToResolve = true;
 }
 
 
-void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc)
+static void createArcConstraints(const EntityWrapperPtr& theArc,
+                                 const SolverPtr& theSolver,
+                                 const ConstraintID theConstraintID,
+                                 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
 {
-  if (!theArc || theArc->type() != ENTITY_ARC || theArc->isExternal())
-    return;
-
   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
 
@@ -323,21 +315,174 @@ void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc
       anArc->center, anArc->end, anArc->endAngle)));
 
   ConstraintWrapperPtr aWrapper(
-      new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
-  aWrapper->setId(++myConstraintLastID);
-  constraintsToSolver(aWrapper, mySketchSolver);
+    new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theArc] = aWrapper;
+}
+
+static void createEllipseConstraints(
+    const EntityWrapperPtr& theEllipse,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
+  std::shared_ptr<GCS::Ellipse> anEllipse =
+      std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
+
+  // Additional constaints to fix ellipse's extra points
+  std::list<GCSConstraintPtr> anEllipseConstraints;
+
+  const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
+  for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
+       anIt != anAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+    if (!aPoint)
+      continue;
+
+    GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
+    if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
+      anAlignmentX = GCS::EllipseFocus2X;
+    else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
+      anAlignmentX = GCS::EllipseNegativeMajorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
+      anAlignmentX = GCS::EllipsePositiveMajorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
+      anAlignmentX = GCS::EllipseNegativeMinorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
+      anAlignmentX = GCS::EllipsePositiveMinorX;
+
+    anEllipseConstraints.push_back(GCSConstraintPtr(
+        new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+        *anEllipse, *(aPoint->point()), anAlignmentX)));
+    anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
+    anEllipseConstraints.push_back(GCSConstraintPtr(
+        new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+        *anEllipse, *(aPoint->point()), anAlignmentY)));
+  }
+
+  // constraint to bind the major radius value
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
+      std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
+  ScalarWrapperPtr aMajorRadius =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
+      anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
+  anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
+
+  ConstraintWrapperPtr aWrapper(
+    new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  if (theSolver)
+    constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theEllipse] = aWrapper;
+}
+
+static void createEllipticArcConstraints(
+    const EntityWrapperPtr& theEllipticArc,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  // create base constraints for the ellipse without adding them to solver
+  createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
+
+  ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
+  std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
+
+  // constrain extremities of the elliptic arc
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
+  std::shared_ptr<GCS::ArcOfEllipse> anArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
+
+  aConstraint->setConstraints(anEllArcConstraints);
+  constraintsToSolver(aConstraint, theSolver);
+}
+
+void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
+{
+  if (!theEntity || theEntity->isExternal())
+    return;
 
-  myArcConstraintMap[theArc] = aWrapper;
+  if (theEntity->type() == ENTITY_ARC)
+    createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPSE)
+    createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
+    createEllipticArcConstraints(theEntity, mySketchSolver,
+                                 ++myConstraintLastID, myAuxConstraintMap);
+  }
 }
 
-void PlaneGCSSolver_Storage::removeArcConstraints(const EntityWrapperPtr& theArc)
+void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
 {
   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
-      aFound = myArcConstraintMap.find(theArc);
-  if (aFound != myArcConstraintMap.end()) {
+      aFound = myAuxConstraintMap.find(theEntity);
+  if (aFound != myAuxConstraintMap.end()) {
     mySketchSolver->removeConstraint(aFound->second->id());
-    myArcConstraintMap.erase(aFound);
+    myAuxConstraintMap.erase(aFound);
+  }
+}
+
+template <typename ARCTYPE>
+void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
+{
+  // tune start angle of the arc to be in [0, 2PI]
+  while (*theArc.startAngle < -PI)
+    *theArc.startAngle += 2.0 * PI;
+  while (*theArc.startAngle >= PI)
+    *theArc.startAngle -= 2.0 * PI;
+  // adjust end angle of the arc
+  if (theReversed) {
+    while (*theArc.endAngle > *theArc.startAngle)
+      *theArc.endAngle -= 2.0 * PI;
+    while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+  }
+  else {
+    while (*theArc.endAngle < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+    while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
+      *theArc.endAngle -= 2.0 * PI;
+  }
+}
+
+void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
+{
+  std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
+  for (; anIt != myAuxConstraintMap.end(); ++anIt) {
+    EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
+    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+    if (anArc)
+      adjustArcParametrization(*anArc, anEdge->isReversed());
+    else {
+      std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+          std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+      if (aEllArc)
+        adjustArcParametrization(*aEllArc, anEdge->isReversed());
+    }
   }
+
+  // update parameters of Middle point constraint for point on arc
+  std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
+  for (; aCIt != myConstraintMap.end(); ++aCIt)
+    if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
+      notify(aCIt->first);
+    }
 }
 
 
@@ -397,7 +542,7 @@ void PlaneGCSSolver_Storage::removeInvalidEntities()
         aDestroyer.remove(aFIter->second);
 
       // remove invalid arc
-      removeArcConstraints(aFIter->second);
+      removeAuxiliaryConstraints(aFIter->second);
     }
   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
index 3ac8e201e31be774171630d7be1a479b68af647b..eafa686c47620bee46177f3dd8d7568fbf534955 100644 (file)
@@ -88,7 +88,12 @@ public:
 
   /// \brief Check the storage has constraints
   virtual bool isEmpty() const
-  { return SketchSolver_Storage::isEmpty() && myArcConstraintMap.empty(); }
+  { return SketchSolver_Storage::isEmpty() && myAuxConstraintMap.empty(); }
+
+  /// \brief Make parametrization of arcs consistent.
+  ///        Forward arcs should have the last parameter greater than the first parameter.
+  ///        Reversed arcs should have the last parameter lesser than the first parameter.
+  virtual void adjustParametrizationOfArcs();
 
 private:
   /// \brief Convert feature using specified builder.
@@ -99,14 +104,17 @@ private:
   EntityWrapperPtr createAttribute(const AttributePtr&           theAttribute,
                                    PlaneGCSSolver_EntityBuilder* theBuilder);
 
-  void createArcConstraints(const EntityWrapperPtr& theArc);
-  void removeArcConstraints(const EntityWrapperPtr& theArc);
+  /// \brief Create additional constaints:
+  ///        * for arc to fix extra parameters;
+  ///        * for ellipse to keep auxiliary points on their places
+  void createAuxiliaryConstraints(const EntityWrapperPtr& theEntity);
+  void removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity);
 
 private:
   ConstraintID myConstraintLastID;   ///< identifier of last added constraint
 
-  /// additional constraints for correct processing of the arcs
-  std::map<EntityWrapperPtr, ConstraintWrapperPtr> myArcConstraintMap;
+  /// additional constraints for correct processing of the arcs, ellipses, elliptic arcs
+  std::map<EntityWrapperPtr, ConstraintWrapperPtr> myAuxConstraintMap;
 
   /// list of removed constraints to notify solver
   std::list<GCSConstraintPtr> myRemovedConstraints;
index ac112699d06ab45ca2f90a652d53c559760b17cd..a13a7b891b5e8f0a498f52edb457e64ba9d7f7cf 100644 (file)
@@ -26,6 +26,7 @@
 #include <SketchSolver_Constraint.h>
 #include <SketchSolver_ConstraintAngle.h>
 #include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchSolver_ConstraintCollinear.h>
 #include <SketchSolver_ConstraintDistance.h>
 #include <SketchSolver_ConstraintEqual.h>
@@ -33,6 +34,7 @@
 #include <SketchSolver_ConstraintLength.h>
 #include <SketchSolver_ConstraintMiddle.h>
 #include <SketchSolver_ConstraintMirror.h>
+#include <SketchSolver_ConstraintPerpendicular.h>
 #include <SketchSolver_ConstraintTangent.h>
 #include <SketchSolver_ConstraintMultiRotation.h>
 #include <SketchSolver_ConstraintMultiTranslation.h>
 #include <SketchPlugin_ConstraintMiddle.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
 
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
+
 #include <cmath>
 
 
@@ -69,6 +78,10 @@ static ConstraintWrapperPtr
   createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType,
                                 std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
                                 std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintPointsCollinear(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+                                  std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
+                                  std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint3);
 static ConstraintWrapperPtr
   createConstraintDistancePointPoint(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
                                      std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
@@ -106,13 +119,23 @@ static ConstraintWrapperPtr
                         std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theIntermed);
 static ConstraintWrapperPtr
   createConstraintMiddlePoint(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
-                              std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+                              std::shared_ptr<PlaneGCSSolver_EdgeWrapper>  theEntity,
+                              std::shared_ptr<PlaneGCSSolver_PointWrapper> theAuxParameters);
+static ConstraintWrapperPtr
+  createConstraintAngleBetweenCurves(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
+                                     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+                                     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity1,
+                                     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity2);
 
 static GCS::SET_pD scalarParameters(const ScalarWrapperPtr& theScalar);
 static GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint);
 static GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine);
 static GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle);
 static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc);
+static GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse);
+static GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc);
+
+static double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
 
 
 
@@ -120,7 +143,8 @@ static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc);
 
 SolverConstraintPtr PlaneGCSSolver_Tools::createConstraint(ConstraintPtr theConstraint)
 {
-  if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+  if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+      theConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintCollinear(theConstraint));
@@ -146,6 +170,8 @@ SolverConstraintPtr PlaneGCSSolver_Tools::createConstraint(ConstraintPtr theCons
     return SolverConstraintPtr(new SketchSolver_ConstraintMultiRotation(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintAngle::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
   }
   // All other types of constraints
   return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint));
@@ -181,17 +207,18 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
 
   std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint1 = GCS_POINT_WRAPPER(thePoint1);
   std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint2 = GCS_POINT_WRAPPER(thePoint2);
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity1 = GCS_EDGE_WRAPPER(theEntity1);
 
   switch (theType) {
   case CONSTRAINT_PT_PT_COINCIDENT:
     aResult = createConstraintCoincidence(aPoint1, aPoint2);
     break;
-  case CONSTRAINT_PT_ON_LINE:
-  case CONSTRAINT_PT_ON_CIRCLE:
-    aResult = createConstraintPointOnEntity(theType, aPoint1, GCS_EDGE_WRAPPER(theEntity1));
+  case CONSTRAINT_PT_ON_CURVE:
+    aResult = anEntity1 ? createConstraintPointOnEntity(theType, aPoint1, anEntity1):
+              createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1));
     break;
   case CONSTRAINT_MIDDLE_POINT:
-    aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1));
+    aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2);
     break;
   case CONSTRAINT_PT_PT_DISTANCE:
     aResult = createConstraintDistancePointPoint(GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2);
@@ -199,41 +226,43 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
   case CONSTRAINT_PT_LINE_DISTANCE:
     aResult = createConstraintDistancePointLine(GCS_SCALAR_WRAPPER(theValue),
                                                 aPoint1,
-                                                GCS_EDGE_WRAPPER(theEntity1));
+                                                anEntity1);
     break;
   case CONSTRAINT_HORIZONTAL_DISTANCE:
   case CONSTRAINT_VERTICAL_DISTANCE:
     aResult = createConstraintHVDistance(theType, GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2);
     break;
   case CONSTRAINT_RADIUS:
-    aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue),
-                                     GCS_EDGE_WRAPPER(theEntity1));
+    aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue), anEntity1);
     break;
   case CONSTRAINT_ANGLE:
     aResult = createConstraintAngle(theConstraint,
                   GCS_SCALAR_WRAPPER(theValue),
-                  GCS_EDGE_WRAPPER(theEntity1), GCS_EDGE_WRAPPER(theEntity2));
+                  anEntity1, GCS_EDGE_WRAPPER(theEntity2));
     break;
   case CONSTRAINT_FIXED:
     break;
   case CONSTRAINT_HORIZONTAL:
   case CONSTRAINT_VERTICAL:
-    aResult = createConstraintHorizVert(theType, GCS_EDGE_WRAPPER(theEntity1));
+    aResult = createConstraintHorizVert(theType, anEntity1);
     break;
   case CONSTRAINT_PARALLEL:
-    aResult = createConstraintParallel(GCS_EDGE_WRAPPER(theEntity1),
-                                       GCS_EDGE_WRAPPER(theEntity2));
+    aResult = createConstraintParallel(anEntity1, GCS_EDGE_WRAPPER(theEntity2));
     break;
   case CONSTRAINT_PERPENDICULAR:
-    aResult = createConstraintPerpendicular(GCS_EDGE_WRAPPER(theEntity1),
-                                            GCS_EDGE_WRAPPER(theEntity2));
+    aResult = createConstraintPerpendicular(anEntity1, GCS_EDGE_WRAPPER(theEntity2));
+    break;
+  case CONSTRAINT_PERPENDICULAR_CURVES:
+    aResult = createConstraintAngleBetweenCurves(GCS_SCALAR_WRAPPER(theValue),
+                  aPoint1, anEntity1, GCS_EDGE_WRAPPER(theEntity2));
     break;
   case CONSTRAINT_EQUAL_LINES:
+  case CONSTRAINT_EQUAL_ELLIPSES:
     anIntermediate = GCS_SCALAR_WRAPPER(theValue); // parameter is used to store length of lines
   case CONSTRAINT_EQUAL_LINE_ARC:
   case CONSTRAINT_EQUAL_RADIUS:
     aResult = createConstraintEqual(theType,
-                                    GCS_EDGE_WRAPPER(theEntity1),
+                                    anEntity1,
                                     GCS_EDGE_WRAPPER(theEntity2),
                                     anIntermediate);
     break;
@@ -280,6 +309,79 @@ std::shared_ptr<GeomAPI_Lin2d> PlaneGCSSolver_Tools::line(FeaturePtr theFeature)
   return std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart->pnt(), aEnd->pnt()));
 }
 
+std::shared_ptr<GeomAPI_Circ2d> PlaneGCSSolver_Tools::circle(EntityWrapperPtr theEntity)
+{
+  if (theEntity->type() != ENTITY_CIRCLE && theEntity->type() != ENTITY_ARC)
+    return std::shared_ptr<GeomAPI_Circ2d>();
+
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
+    std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity);
+  std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(anEntity->entity());
+  return std::shared_ptr<GeomAPI_Circ2d>(
+    new GeomAPI_Circ2d(*(aCirc->center.x), *(aCirc->center.y), *(aCirc->rad)));
+}
+
+std::shared_ptr<GeomAPI_Ellipse2d> PlaneGCSSolver_Tools::ellipse(EntityWrapperPtr theEntity)
+{
+  if (theEntity->type() != ENTITY_ELLIPSE && theEntity->type() != ENTITY_ELLIPTIC_ARC)
+    return std::shared_ptr<GeomAPI_Ellipse2d>();
+
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
+    std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity);
+  std::shared_ptr<GCS::Ellipse> anEllipse =
+      std::dynamic_pointer_cast<GCS::Ellipse>(anEntity->entity());
+
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter(
+      new GeomAPI_Pnt2d(*(anEllipse->center.x), *(anEllipse->center.y)));
+  std::shared_ptr<GeomAPI_Dir2d> anAxis(new GeomAPI_Dir2d(
+      *(anEllipse->focus1.x) - *(anEllipse->center.x),
+      *(anEllipse->focus1.y) - *(anEllipse->center.y)));
+
+  return std::shared_ptr<GeomAPI_Ellipse2d>(
+      new GeomAPI_Ellipse2d(aCenter, anAxis, anEllipse->getRadMaj(), *anEllipse->radmin));
+}
+
+void PlaneGCSSolver_Tools::recalculateArcParameters(EntityWrapperPtr theArc)
+{
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEdge =
+      std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
+  if (!anEdge)
+    return;
+
+  if (anEdge->type() == ENTITY_ARC) {
+    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+
+    GCS::Point aCenter = anArc->center;
+    GCS::Point aStartPnt = anArc->start;
+    GCS::Point aEndPnt = anArc->end;
+
+    *anArc->rad = distance(aCenter, aStartPnt);
+
+    static GeomDir2dPtr OX(new GeomAPI_Dir2d(1.0, 0.0));
+
+    GeomDir2dPtr aDir(new GeomAPI_Dir2d(*aStartPnt.x - *aCenter.x, *aStartPnt.y - *aCenter.y));
+    *anArc->startAngle = OX->angle(aDir);
+
+    aDir.reset(new GeomAPI_Dir2d(*aEndPnt.x - *aCenter.x, *aEndPnt.y - *aCenter.y));
+    *anArc->endAngle = OX->angle(aDir);
+  }
+  else if (anEdge->type() == ENTITY_ELLIPTIC_ARC) {
+    std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+        std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+    GeomPnt2dPtr aCenter(new GeomAPI_Pnt2d(*aEllArc->center.x, *aEllArc->center.y));
+    GeomPnt2dPtr aStartPnt(new GeomAPI_Pnt2d(*aEllArc->start.x, *aEllArc->start.y));
+    GeomPnt2dPtr aEndPnt(new GeomAPI_Pnt2d(*aEllArc->end.x, *aEllArc->end.y));
+
+    GeomDir2dPtr anAxis(new GeomAPI_Dir2d(*aEllArc->focus1.x - aCenter->x(),
+                                          *aEllArc->focus1.y - aCenter->y()));
+    GeomAPI_Ellipse2d anEllipse(aCenter, anAxis, aEllArc->getRadMaj(), *aEllArc->radmin);
+    anEllipse.parameter(aStartPnt, 1.e-4, *aEllArc->startAngle);
+    anEllipse.parameter(aEndPnt, 1.e-4, *aEllArc->endAngle);
+  }
+}
+
+
 
 GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity)
 {
@@ -295,6 +397,10 @@ GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity)
     return circleParameters(GCS_EDGE_WRAPPER(theEntity));
   case ENTITY_ARC:
     return arcParameters(GCS_EDGE_WRAPPER(theEntity));
+  case ENTITY_ELLIPSE:
+    return ellipseParameters(GCS_EDGE_WRAPPER(theEntity));
+  case ENTITY_ELLIPTIC_ARC:
+    return ellipticArcParameters(GCS_EDGE_WRAPPER(theEntity));
   default: break;
   }
   return GCS::SET_pD();
@@ -345,6 +451,14 @@ ConstraintWrapperPtr createConstraintPointOnEntity(
         new GCS::ConstraintP2PDistance(*(thePoint->point()), aCirc->center, aCirc->rad));
     break;
     }
+  case ENTITY_ELLIPSE:
+  case ENTITY_ELLIPTIC_ARC: {
+    std::shared_ptr<GCS::Ellipse> anEllipse =
+        std::dynamic_pointer_cast<GCS::Ellipse>(theEntity->entity());
+    aNewConstr = GCSConstraintPtr(
+        new GCS::ConstraintPointOnEllipse(*(thePoint->point()), *anEllipse));
+    break;
+    }
   default:
     return ConstraintWrapperPtr();
   }
@@ -352,21 +466,65 @@ ConstraintWrapperPtr createConstraintPointOnEntity(
   return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType));
 }
 
+ConstraintWrapperPtr createConstraintPointsCollinear(
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint3)
+{
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintPointOnLine(
+      *(thePoint1->point()), *(thePoint2->point()), *(thePoint3->point())));
+  return ConstraintWrapperPtr(
+      new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PT_ON_CURVE));
+}
+
+template <typename ARCTYPE>
+void createConstraintMiddlePointOnArc(ARCTYPE theArc,
+                                      GCSPointPtr thePoint,
+                                      std::shared_ptr<PlaneGCSSolver_PointWrapper> theAuxParameters,
+                                      std::list<GCSConstraintPtr>& theConstraints)
+{
+  double* u = theAuxParameters->point()->x;
+  double* diff = theAuxParameters->point()->y;
+  *u = (*theArc->startAngle + *theArc->endAngle) * 0.5;
+  *diff = (*theArc->endAngle - *theArc->startAngle) * 0.5;
+
+  theConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(*thePoint, thePoint->x, *theArc, u)));
+  theConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(*thePoint, thePoint->y, *theArc, u)));
+  theConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintDifference(theArc->startAngle, u, diff)));
+  theConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintDifference(u, theArc->endAngle, diff)));
+}
+
 ConstraintWrapperPtr createConstraintMiddlePoint(
     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
-    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
+    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> theAuxParameters)
 {
+  std::list<GCSConstraintPtr> aConstrList;
+
   GCSPointPtr aPoint = thePoint->point();
   std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
-  if (!aLine)
-    return ConstraintWrapperPtr();
-
-  std::list<GCSConstraintPtr> aConstrList;
-  aConstrList.push_back(
-      GCSConstraintPtr(new GCS::ConstraintPointOnPerpBisector(*aPoint, aLine->p1, aLine->p2)));
-  aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+  if (aLine) {
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+    aConstrList.push_back(
+        GCSConstraintPtr(new GCS::ConstraintPointOnPerpBisector(*aPoint, aLine->p1, aLine->p2)));
+  }
+  else {
+    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(theEntity->entity());
+    if (anArc)
+      createConstraintMiddlePointOnArc(anArc, aPoint, theAuxParameters, aConstrList);
+    else {
+      std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+          std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity->entity());
+      if (aEllArc)
+        createConstraintMiddlePointOnArc(aEllArc, aPoint, theAuxParameters, aConstrList);
+    }
+  }
 
-  return ConstraintWrapperPtr(
+  return aConstrList.empty() ? ConstraintWrapperPtr() : ConstraintWrapperPtr(
       new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_MIDDLE_POINT));
 }
 
@@ -496,12 +654,40 @@ ConstraintWrapperPtr createConstraintPerpendicular(
 {
   std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
   std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
-  GCSConstraintPtr aNewConstr(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2)));
+
+  std::shared_ptr<GCS::Circle> aCirc1 =
+      std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
+  std::shared_ptr<GCS::Circle> aCirc2 =
+      std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
+
+  GCSConstraintPtr aNewConstr;
+  if (aLine1 && aLine2)
+    aNewConstr.reset(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2)));
+  else {
+    if (aLine1 && aCirc2)
+      aCirc1 = aCirc2;
+    else if (aLine2 && aCirc1)
+      aLine1 = aLine2;
+
+    aNewConstr.reset(new GCS::ConstraintPointOnLine(aCirc1->center, *aLine1));
+  }
 
   return ConstraintWrapperPtr(
       new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PERPENDICULAR));
 }
 
+ConstraintWrapperPtr createConstraintAngleBetweenCurves(
+    std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity2)
+{
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintAngleViaPoint(
+      *theEntity1->entity(), *theEntity2->entity(), *thePoint->point(), theValue->scalar()));
+  return ConstraintWrapperPtr(
+      new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PERPENDICULAR_CURVES));
+}
+
 ConstraintWrapperPtr createConstraintEqual(
     const SketchSolver_ConstraintType& theType,
     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity1,
@@ -521,16 +707,28 @@ ConstraintWrapperPtr createConstraintEqual(
     aConstrList.push_back(GCSConstraintPtr(
         new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->scalar())));
     // update value of intermediate parameter
-    double x = *aLine1->p1.x - *aLine1->p2.x;
-    double y = *aLine1->p1.y - *aLine1->p2.y;
-    double aLen = sqrt(x*x + y*y);
-    theIntermed->setValue(aLen);
-  } else {
+    theIntermed->setValue(distance(aLine1->p1, aLine1->p2));
+  }
+  else if (theType == CONSTRAINT_EQUAL_ELLIPSES) {
+    std::shared_ptr<GCS::Ellipse> anEllipse1 =
+        std::dynamic_pointer_cast<GCS::Ellipse>(theEntity1->entity());
+    std::shared_ptr<GCS::Ellipse> anEllipse2 =
+        std::dynamic_pointer_cast<GCS::Ellipse>(theEntity2->entity());
+
+    aConstrList.push_back(GCSConstraintPtr(
+        new GCS::ConstraintEqual(anEllipse1->radmin, anEllipse2->radmin)));
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+        anEllipse1->center, anEllipse1->focus1, theIntermed->scalar())));
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+        anEllipse2->center, anEllipse2->focus1, theIntermed->scalar())));
+    // update value of intermediate parameter
+    theIntermed->setValue(distance(anEllipse1->center, anEllipse1->focus1));
+  }
+  else {
     std::shared_ptr<GCS::Circle> aCirc1 =
         std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
     std::shared_ptr<GCS::Circle> aCirc2 =
         std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
-
     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(aCirc1->rad, aCirc2->rad)));
   }
 
@@ -579,16 +777,47 @@ GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle)
 
 GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc)
 {
-  GCS::SET_pD aParams;
+  GCS::SET_pD aParams = circleParameters(theArc);
   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(theArc->entity());
-  aParams.insert(anArc->center.x);
-  aParams.insert(anArc->center.y);
   aParams.insert(anArc->start.x);
   aParams.insert(anArc->start.y);
   aParams.insert(anArc->end.x);
   aParams.insert(anArc->end.y);
   aParams.insert(anArc->startAngle);
   aParams.insert(anArc->endAngle);
-  aParams.insert(anArc->rad);
   return aParams;
 }
+
+GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse)
+{
+  GCS::SET_pD aParams;
+  std::shared_ptr<GCS::Ellipse> anEllipse =
+      std::dynamic_pointer_cast<GCS::Ellipse>(theEllipse->entity());
+  aParams.insert(anEllipse->center.x);
+  aParams.insert(anEllipse->center.y);
+  aParams.insert(anEllipse->focus1.x);
+  aParams.insert(anEllipse->focus1.y);
+  aParams.insert(anEllipse->radmin);
+  return aParams;
+}
+
+GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc)
+{
+  GCS::SET_pD aParams = ellipseParameters(theEllipticArc);
+  std::shared_ptr<GCS::ArcOfEllipse> anArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEllipticArc->entity());
+  aParams.insert(anArc->start.x);
+  aParams.insert(anArc->start.y);
+  aParams.insert(anArc->end.x);
+  aParams.insert(anArc->end.y);
+  aParams.insert(anArc->startAngle);
+  aParams.insert(anArc->endAngle);
+  return aParams;
+}
+
+double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
+{
+  double x = *thePnt1.x - *thePnt2.x;
+  double y = *thePnt1.y - *thePnt2.y;
+  return sqrt(x*x + y*y);
+}
index 4e5b666b67268986f7f77026cfd8058f12e10a1c..a02a9948c77a2302f86a4b7d48176b33f3d3f4ea 100644 (file)
 #include <SketchSolver_ConstraintMovement.h>
 #include <SketchPlugin_Constraint.h>
 
-#include <GeomAPI_Lin2d.h>
-#include <GeomAPI_Pnt2d.h>
+class GeomAPI_Circ2d;
+class GeomAPI_Ellipse2d;
+class GeomAPI_Lin2d;
+class GeomAPI_Pnt2d;
 
 /** \namespace  PlaneGCSSolver_Tools
  *  \ingroup    Plugins
@@ -68,11 +70,22 @@ namespace PlaneGCSSolver_Tools
   /// \brief Convert entity to line
   /// \return empty pointer if the entity is not a line
   std::shared_ptr<GeomAPI_Lin2d> line(EntityWrapperPtr theEntity);
+  /// \brief Convert entity to circle
+  /// \return empty pointer if the entity is not a circle
+  std::shared_ptr<GeomAPI_Circ2d> circle(EntityWrapperPtr theEntity);
+  /// \brief Convert entity to ellipse
+  /// \return empty pointer if the entity is not an ellipse
+  std::shared_ptr<GeomAPI_Ellipse2d> ellipse(EntityWrapperPtr theEntity);
 
   /// \brief Convert entity to line
   /// \return empty pointer if the entity is not a line
   std::shared_ptr<GeomAPI_Lin2d> line(FeaturePtr theFeature);
 
+  /// \brief Update start and end parameters of circular and elliptic arcs
+  ///        respectively to start and end points on the arc.
+  ///        For the circular arc, the radius is calculated too.
+  void recalculateArcParameters(EntityWrapperPtr theArc);
+
   /// brief Return list of parameters for the given entity
   GCS::SET_pD parameters(const EntityWrapperPtr& theEntity);
 };
index 4ed6b81e992743639bcd0e6c310473ba7e71a9c5..1f0466486c5573e0c5431902e4d74e22bde701b9 100644 (file)
@@ -23,6 +23,7 @@
 #include <SketchSolver_Constraint.h>
 
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintMiddle.h>
 
@@ -48,6 +49,7 @@ void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserv
 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
 {
   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+      theFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
       theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
       theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
     myCoincident.clear();
index 7d047ac8091f1a83ecf5bc37098628918dbcbae1..48c0fa5b80d63454f15ee4b12fa0a563c4b941d7 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintEqual.h>
@@ -76,7 +77,8 @@ void SketchSolver_Constraint::blockEvents(bool isBlocked)
 SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConstraint)
 {
   const std::string& aType = theConstraint->getKind();
-  if (aType == SketchPlugin_ConstraintCoincidence::ID())
+  if (aType == SketchPlugin_ConstraintCoincidence::ID() ||
+      aType == SketchPlugin_ConstraintCoincidenceInternal::ID())
     return CONSTRAINT_COINCIDENCE;
   else if (aType == SketchPlugin_ConstraintRigid::ID())
     return CONSTRAINT_FIXED;
index 9903b850efdb4ab8bee4b67503465c0bd7419456..2c4d8eed34c4ba26b201246f51442f8a96a4b7ce 100644 (file)
 #include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateCoincidence.h>
 
+#include <GeomDataAPI_Point2D.h>
+
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
 
 static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint,
                                             const StoragePtr& theStorage,
@@ -44,10 +50,148 @@ static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint,
     } else if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
       theExtremities[0] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::START_ID()));
       theExtremities[1] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::END_ID()));
+    } else if (aFeature->getKind() == SketchPlugin_EllipticArc::ID()) {
+      theExtremities[0] = theStorage->entity(
+          aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+      theExtremities[1] = theStorage->entity(
+          aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+    }
+  }
+}
+
+static void getPointOwnerAndParent(const AttributeRefAttrPtr theRefAttr,
+                                   AttributePoint2DPtr& thePoint,
+                                   FeaturePtr& theOwner,
+                                   FeaturePtr& theParent)
+{
+  AttributePtr anAttr = theRefAttr->attr();
+  if (theRefAttr->isObject()) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature(theRefAttr->object());
+    if (anOwner && anOwner->getKind() == SketchPlugin_Point::ID())
+      anAttr = anOwner->attribute(SketchPlugin_Point::COORD_ID());
+    else
+      return;
+  }
+  thePoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+  if (thePoint) {
+    theOwner = ModelAPI_Feature::feature(thePoint->owner());
+    if (theOwner) {
+      std::string aParentRefID;
+      if (theOwner->getKind() == SketchPlugin_Line::ID())
+        aParentRefID = SketchPlugin_Line::PARENT_ID();
+      else if (theOwner->getKind() == SketchPlugin_Point::ID())
+        aParentRefID = SketchPlugin_Point::PARENT_ID();
+      if (!aParentRefID.empty()) {
+        AttributeReferencePtr aParentRef = theOwner->reference(aParentRefID);
+        theParent = aParentRef ? ModelAPI_Feature::feature(aParentRef->value()) : FeaturePtr();
+      }
     }
   }
 }
 
+static void ellipseDiameters(FeaturePtr theEllipse,
+                             std::pair<std::string, std::string>& theMajorAxis,
+                             std::pair<std::string, std::string>& theMinorAxis)
+{
+  if (theEllipse->getKind() == SketchPlugin_Ellipse::ID()) {
+    theMajorAxis.first = SketchPlugin_Ellipse::MAJOR_AXIS_START_ID();
+    theMajorAxis.second = SketchPlugin_Ellipse::MAJOR_AXIS_END_ID();
+    theMinorAxis.first = SketchPlugin_Ellipse::MINOR_AXIS_START_ID();
+    theMinorAxis.second = SketchPlugin_Ellipse::MINOR_AXIS_END_ID();
+  } else if (theEllipse->getKind() == SketchPlugin_EllipticArc::ID()) {
+    theMajorAxis.first = SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID();
+    theMajorAxis.second = SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID();
+    theMinorAxis.first = SketchPlugin_EllipticArc::MINOR_AXIS_START_ID();
+    theMinorAxis.second = SketchPlugin_EllipticArc::MINOR_AXIS_END_ID();
+  }
+}
+
+static void findDiameterOnEllipse(FeaturePtr theConstruction,
+                                  FeaturePtr theEllipse,
+                                  AttributePtr& theStart,
+                                  AttributePtr& theEnd)
+{
+  AttributePtr anEllipseAttr;
+  const std::set<AttributePtr>& aRefs = theConstruction->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+       aRefIt != aRefs.end(); ++aRefIt) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+    if (anOwner && anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+      AttributeRefAttrPtr aRefAttr;
+      if ((*aRefIt)->id() == SketchPlugin_Constraint::ENTITY_A())
+        aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B());
+      else
+        aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A());
+      anEllipseAttr = aRefAttr->attr();
+      break;
+    }
+  }
+  if (!anEllipseAttr)
+    return;
+
+  std::pair<std::string, std::string> aMajorAxis, aMinorAxis;
+  ellipseDiameters(theEllipse, aMajorAxis, aMinorAxis);
+  if (anEllipseAttr->id() == aMajorAxis.first) {
+    theStart = anEllipseAttr;
+    theEnd = theEllipse->attribute(aMajorAxis.second);
+  }
+  else if (anEllipseAttr->id() == aMajorAxis.second) {
+    theStart = theEllipse->attribute(aMajorAxis.first);
+    theEnd = anEllipseAttr;
+  }
+  else if (anEllipseAttr->id() == aMinorAxis.first) {
+    theStart = anEllipseAttr;
+    theEnd = theEllipse->attribute(aMinorAxis.second);
+  }
+  else if (anEllipseAttr->id() == aMinorAxis.second) {
+    theStart = theEllipse->attribute(aMinorAxis.first);
+    theEnd = anEllipseAttr;
+  }
+}
+
+static void processEllipticArcExtremities(SketchSolver_ConstraintType& theType,
+                                          const ConstraintPtr& theConstraint,
+                                          const StoragePtr& theStorage,
+                                          std::vector<EntityWrapperPtr>& theAttributes,
+                                          EntityWrapperPtr theExtremities[2])
+{
+  AttributePoint2DPtr aPointA, aPointB;
+  FeaturePtr anOwnerA, anOwnerB;
+  FeaturePtr aParentA, aParentB;
+  getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()),
+                         aPointA, anOwnerA, aParentA);
+  getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()),
+                         aPointB, anOwnerB, aParentB);
+
+  AttributePtr anAxisStart, anAxisEnd, aPoint;
+  FeaturePtr aConstruction, anEllipticArc;
+  if (aParentA && aParentA == anOwnerB) {
+    aPoint = aPointB;
+    aConstruction = anOwnerA;
+    anEllipticArc = anOwnerB;
+  }
+  else if (aParentB && aParentB == anOwnerA) {
+    aPoint = aPointA;
+    aConstruction = anOwnerB;
+    anEllipticArc = anOwnerA;
+  }
+
+  if (!anEllipticArc || anEllipticArc->getKind() != SketchPlugin_EllipticArc::ID() ||
+      (aPoint->id() != SketchPlugin_EllipticArc::START_POINT_ID() &&
+       aPoint->id() != SketchPlugin_EllipticArc::END_POINT_ID()))
+    return;
+
+  findDiameterOnEllipse(aConstruction, anEllipticArc, anAxisStart, anAxisEnd);
+
+  if (anAxisStart && anAxisEnd) {
+    theAttributes[0] = theStorage->entity(aPoint);
+    theAttributes[1] = theStorage->entity(anAxisStart);
+    theAttributes[2] = theStorage->entity(anAxisEnd);
+    theType = CONSTRAINT_PT_ON_CURVE;
+    getCoincidentFeatureExtremities(theConstraint, theStorage, theExtremities);
+  }
+}
+
 
 void SketchSolver_ConstraintCoincidence::process()
 {
@@ -93,18 +237,15 @@ void SketchSolver_ConstraintCoincidence::getAttributes(
     return;
   }
 
-  if (theAttributes[1])
+  if (theAttributes[1]) {
     myType = CONSTRAINT_PT_PT_COINCIDENT;
-  else if (theAttributes[2]) {
-    // check the type of entity (line or circle)
-    SketchSolver_EntityType anEntType = theAttributes[2]->type();
-    if (anEntType == ENTITY_LINE)
-      myType = CONSTRAINT_PT_ON_LINE;
-    else if (anEntType == ENTITY_CIRCLE || anEntType == ENTITY_ARC)
-      myType = CONSTRAINT_PT_ON_CIRCLE;
-    else
-      myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-
+    // if elliptic arc boundary point is connected with one of ellipse characteristics,
+    // it should be changed from point-point coincidence to coincidence between point
+    // and axis of the ellipse to decrease only 1 DoF instead of 2 DoF and avoid overconstraint.
+    processEllipticArcExtremities(myType, myBaseConstraint, myStorage,
+                                  theAttributes, myFeatureExtremities);
+  } else if (theAttributes[2]) {
+    myType = CONSTRAINT_PT_ON_CURVE;
     // obtain extremity points of the coincident feature for further checking of multi-coincidence
     getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
   } else
@@ -117,6 +258,32 @@ void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr&      theFeatur
   PlaneGCSSolver_UpdateCoincidence* anUpdater =
       static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
   bool isAccepted = anUpdater->addCoincidence(myAttributes.front(), myAttributes.back());
+  // additionally process internal coincidence, set point coincident with ellipse/elliptic arc
+  // for correct processing further coincidences set by the user
+  if (isAccepted &&
+      myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+    AttributeRefAttrPtr aRefAttrA = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+    AttributeRefAttrPtr aRefAttrB = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+    if (aRefAttrA && aRefAttrB) {
+      AttributePoint2DPtr anAttrA, anAttrB;
+      FeaturePtr anOwnerA, anOwnerB;
+      FeaturePtr aParentA, aParentB;
+      getPointOwnerAndParent(aRefAttrA, anAttrA, anOwnerA, aParentA);
+      getPointOwnerAndParent(aRefAttrB, anAttrB, anOwnerB, aParentB);
+
+      EntityWrapperPtr aPoint, anEntity;
+      if (aParentA == anOwnerB) {
+        aPoint = myStorage->entity(anAttrA);
+        anEntity = myStorage->entity(anOwnerB);
+      }
+      else if (aParentB == anOwnerA) {
+        aPoint = myStorage->entity(anAttrB);
+        anEntity = myStorage->entity(anOwnerA);
+      }
+      if (aPoint && anEntity)
+        anUpdater->addCoincidence(aPoint, anEntity);
+    }
+  }
 
   // additionally check the point is coincident to extremity of coincident feature
   if (myFeatureExtremities[0] && myFeatureExtremities[1]) {
index 2cb98d4a52ec8bf1ca09e79a4a06e43c0ae423ec..40fa3800198cb7844f69da611cf102e6bc27928c 100644 (file)
@@ -38,6 +38,7 @@ void SketchSolver_ConstraintEqual::getAttributes(
   int aNbLines = 0;
   int aNbArcs = 0;
   int aNbCircs = 0;
+  int aNbEllipses = 0;
   bool isArcFirst = false; // in line-arc equivalence, the line should be first
   std::vector<EntityWrapperPtr>::iterator anAttrIt = theAttributes.begin() + 2;
   for (; anAttrIt != theAttributes.end(); ++anAttrIt) {
@@ -50,17 +51,27 @@ void SketchSolver_ConstraintEqual::getAttributes(
       ++aNbArcs;
       isArcFirst = (aNbLines == 0);
     }
+    else if (aType == ENTITY_ELLIPSE || aType == ENTITY_ELLIPTIC_ARC)
+      ++aNbEllipses;
   }
 
-  if (aNbLines + aNbArcs + aNbCircs != 2 ||
-     (aNbLines == aNbCircs && aNbArcs == 0)) {
+  if (aNbLines + aNbArcs + aNbCircs + aNbEllipses != 2 ||
+     (aNbArcs == 1 && aNbEllipses != 0) || aNbEllipses == 1) {
     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
     return;
   }
 
   switch (aNbLines) {
   case 0:
-    myType = CONSTRAINT_EQUAL_RADIUS;
+    if (aNbEllipses == 2) {
+      myType = CONSTRAINT_EQUAL_ELLIPSES;
+      std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+          std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+      myAuxValue = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
+      theValue = myAuxValue;
+    }
+    else
+      myType = CONSTRAINT_EQUAL_RADIUS;
     break;
   case 1:
     myType = CONSTRAINT_EQUAL_LINE_ARC;
@@ -85,3 +96,15 @@ void SketchSolver_ConstraintEqual::getAttributes(
     break;
   }
 }
+
+bool SketchSolver_ConstraintEqual::remove()
+{
+  if (myAuxValue) {
+    std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+        std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+    GCS::SET_pD aParams;
+    aParams.insert(myAuxValue->scalar());
+    aStorage->removeParameters(aParams);
+  }
+  return SketchSolver_Constraint::remove();
+}
index b7495d2d8d3f111870af70ff2b977c632d346d7f..146cf876486fab239e5aa20f2014f147a683b89b 100644 (file)
@@ -34,12 +34,20 @@ public:
       SketchSolver_Constraint(theConstraint)
   {}
 
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints
+  /// (like for multiple coincidence)
+  virtual bool remove();
+
 protected:
   /// \brief Generate list of attributes of constraint in order useful for constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
   /// \param[out] theAttributes list of attributes to be filled
   virtual void getAttributes(EntityWrapperPtr&              theValue,
                              std::vector<EntityWrapperPtr>& theAttributes);
+
+private:
+  ScalarWrapperPtr myAuxValue; ///< scalar value to store ellipses focus distance
 };
 
 #endif
index f61c8a49a73f0c2fef25146bdd5bd1fc72f989c2..a32e1966f49a200ca6016081b1c8e071062ab166 100644 (file)
@@ -141,6 +141,28 @@ GCS::VEC_pD toParameters(const EntityWrapperPtr& theEntity)
     aParameters.push_back(anArc->endAngle);
     break;
     }
+  case ENTITY_ELLIPSE: {
+    std::shared_ptr<GCS::Ellipse> anEllipse =
+        std::dynamic_pointer_cast<GCS::Ellipse>(anEntity->entity());
+    aParameters.push_back(anEllipse->center.x);
+    aParameters.push_back(anEllipse->center.y);
+    aParameters.push_back(anEllipse->focus1.x);
+    aParameters.push_back(anEllipse->focus1.y);
+    aParameters.push_back(anEllipse->radmin);
+    break;
+    }
+  case ENTITY_ELLIPTIC_ARC: {
+    std::shared_ptr<GCS::ArcOfEllipse> anEllArc =
+        std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEntity->entity());
+    aParameters.push_back(anEllArc->center.x);
+    aParameters.push_back(anEllArc->center.y);
+    aParameters.push_back(anEllArc->focus1.x);
+    aParameters.push_back(anEllArc->focus1.y);
+    aParameters.push_back(anEllArc->radmin);
+    aParameters.push_back(anEllArc->startAngle);
+    aParameters.push_back(anEllArc->endAngle);
+    break;
+    }
   default:
     break;
   }
index 9643b2aafc7a8f6e180b5ddb81ce2fdb3ec1d075..893747131c8025a66372d12b38bb231336a53ed8 100644 (file)
 
 #include <SketchSolver_ConstraintMiddle.h>
 #include <PlaneGCSSolver_ConstraintWrapper.h>
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateCoincidence.h>
 
+static bool isArc(EntityWrapperPtr theEntity)
+{
+  return theEntity->type() == ENTITY_ARC || theEntity->type() == ENTITY_ELLIPTIC_ARC;
+}
+
 void SketchSolver_ConstraintMiddle::getAttributes(
     EntityWrapperPtr& theValue,
     std::vector<EntityWrapperPtr>& theAttributes)
 {
   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+
+  // create auxiliary point if middle point on arc is specified
+  if (isArc(theAttributes[2])) {
+    std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+        std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+    myOddPoint = GCSPointPtr(new GCS::Point);
+    myOddPoint->x = aStorage->createParameter();
+    myOddPoint->y = aStorage->createParameter();
+    theAttributes[1] = PointWrapperPtr(new PlaneGCSSolver_PointWrapper(myOddPoint));
+  }
+}
+
+bool SketchSolver_ConstraintMiddle::remove()
+{
+  if (myOddPoint) {
+    std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+        std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+    GCS::SET_pD aParams;
+    aParams.insert(myOddPoint->x);
+    aParams.insert(myOddPoint->y);
+    aStorage->removeParameters(aParams);
+  }
+  return SketchSolver_ConstraintCoincidence::remove();
 }
 
 void SketchSolver_ConstraintMiddle::notify(const FeaturePtr&      theFeature,
                                            PlaneGCSSolver_Update* theUpdater)
 {
-  if (theFeature == myBaseConstraint && myInSolver)
-    return; // the constraint is already being updated
+  if (theFeature == myBaseConstraint && myInSolver) {
+    // the constraint is already being updated,
+    // update the middle point parameter if the constraint is "point-on-arc".
+    if (myOddPoint) {
+      EntityWrapperPtr anArcEntity =
+          isArc(myAttributes.front()) ? myAttributes.front() : myAttributes.back();
+      EdgeWrapperPtr anArcEdge =
+          std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anArcEntity);
+      if (anArcEdge) {
+        std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEdge->entity());
+        if (anArc) {
+          // recalculate parameters of middle point according to arc
+          *myOddPoint->x = (*anArc->startAngle + *anArc->endAngle) * 0.5;
+          *myOddPoint->y = (*anArc->endAngle - *anArc->startAngle) * 0.5;
+        }
+        else {
+          std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+              std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anArcEdge->entity());
+          if (aEllArc) {
+            // recalculate parameters of middle point according to arc
+            *myOddPoint->x = (*aEllArc->startAngle + *aEllArc->endAngle) * 0.5;
+            *myOddPoint->y = (*aEllArc->endAngle - *aEllArc->startAngle) * 0.5;
+          }
+        }
+      }
+    }
+    return;
+  }
 
   PlaneGCSSolver_UpdateCoincidence* anUpdater =
       static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
@@ -45,13 +105,8 @@ void SketchSolver_ConstraintMiddle::notify(const FeaturePtr&      theFeature,
         // remove previously adde constraint
         myStorage->removeConstraint(myBaseConstraint);
         // merge divided constraints into single object
-        std::list<GCSConstraintPtr> aGCSConstraints;
-        std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
-            std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(myMiddle);
-        aGCSConstraints.push_back(aConstraint->constraints().front());
-        aConstraint =
-            std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(mySolverConstraint);
-        aGCSConstraints.push_back(aConstraint->constraints().front());
+        std::list<GCSConstraintPtr> aGCSConstraints = myMiddle->constraints();
+        aGCSConstraints.push_front(mySolverConstraint->constraints().front());
 
         myMiddle = ConstraintWrapperPtr();
         mySolverConstraint = ConstraintWrapperPtr(
@@ -72,10 +127,11 @@ void SketchSolver_ConstraintMiddle::notify(const FeaturePtr&      theFeature,
           std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(mySolverConstraint);
       std::list<GCSConstraintPtr> aGCSConstraints = aConstraint->constraints();
 
-      myMiddle = ConstraintWrapperPtr(
-          new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.front(), CONSTRAINT_MIDDLE_POINT));
       mySolverConstraint = ConstraintWrapperPtr(
-          new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.back(), CONSTRAINT_MIDDLE_POINT));
+        new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.front(), CONSTRAINT_MIDDLE_POINT));
+      aGCSConstraints.pop_front();
+      myMiddle = ConstraintWrapperPtr(
+          new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints, CONSTRAINT_MIDDLE_POINT));
 
       // send middle constraint only
       myStorage->addConstraint(myBaseConstraint, myMiddle);
index 48e11560aebad9cd83b55bda5b00d2d012884fa8..3d63197857411bb8a203aee8876ba95b58bca5ee 100644 (file)
@@ -38,6 +38,9 @@ public:
   virtual void notify(const FeaturePtr&      theFeature,
                       PlaneGCSSolver_Update* theUpdater);
 
+  /// \brief Remove constraint
+  virtual bool remove();
+
 protected:
   /// \brief Generate list of attributes of constraint in order useful for constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
@@ -47,6 +50,7 @@ protected:
 
 private:
   ConstraintWrapperPtr myMiddle;
+  GCSPointPtr myOddPoint; ///< auxiliary point to adjust midpoint-on-arc
 };
 
 #endif
index cbf025ed5d6e154a7831988e6c4a7ff152dfb5ad..7f22fa947f3ca7b7203a6864ce2403f3038c7345 100644 (file)
 #include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateFeature.h>
 
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeRefList.h>
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_EllipticArc.h>
 
 
 static void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
@@ -192,6 +195,11 @@ void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
     theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
         theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
   }
+  else if (theOriginal->getKind() == SketchPlugin_EllipticArc::ID()) {
+    // orientation of arc
+    theMirrored->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(
+        !theOriginal->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->value());
+  }
 
   // mirror all initialized points of features
   std::list<AttributePtr>::iterator anIt0, anIt1;
index fdc4b0e78ff85afa6e34be69fb70fc3341219d67..8e38fa6b8303487f7acead82f677d97b0c9b0660 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 
 
 #include <GeomAPI_Pnt2d.h>
 
+#include <cmath>
+
+static GCS::Point createGCSPoint(double* x, double* y)
+{
+  GCS::Point aPoint;
+  aPoint.x = x;
+  aPoint.y = y;
+  return aPoint;
+}
+
 
 SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature)
   : SketchSolver_ConstraintFixed(ConstraintPtr()),
@@ -78,11 +90,14 @@ static bool isSimpleMove(FeaturePtr theMovedFeature, AttributePtr theDraggedPoin
 {
   bool isSimple = true;
 #ifdef CHANGE_RADIUS_WHILE_MOVE
-  if (theMovedFeature->getKind() == SketchPlugin_Circle::ID())
+  if (theMovedFeature->getKind() == SketchPlugin_Circle::ID() ||
+      theMovedFeature->getKind() == SketchPlugin_Ellipse::ID())
     isSimple = (theDraggedPoint.get() != 0);
-  else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID()) {
+  else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID() ||
+           theMovedFeature->getKind() == SketchPlugin_EllipticArc::ID()) {
     isSimple = (theDraggedPoint.get() != 0 &&
-                theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID());
+               (theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID() ||
+                theDraggedPoint->id() == SketchPlugin_EllipticArc::CENTER_ID()));
   }
 #endif
   return isSimple;
@@ -117,8 +132,14 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::initMovement()
   else {
     if (myDraggedPoint) // start or end point of arc has been moved
       aConstraint = fixArcExtremity(anEntity);
-    else // arc or circle has been moved
+    else if (anEntity->type() == ENTITY_CIRCLE || anEntity->type() == ENTITY_ARC) {
+      // arc or circle has been moved
       aConstraint = fixPointOnCircle(anEntity);
+    }
+    else if (anEntity->type() == ENTITY_ELLIPSE || anEntity->type() == ENTITY_ELLIPTIC_ARC) {
+      // ellipse or elliptic arc has been moved
+      aConstraint = fixPointOnEllipse(anEntity);
+    }
   }
 
   return aConstraint;
@@ -134,12 +155,21 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixArcExtremity(
       myStorage->entity(myMovedFeature));
   std::shared_ptr<GCS::Arc> anArc =
       std::dynamic_pointer_cast<GCS::Arc>(aCircularEntity->entity());
+  std::shared_ptr<GCS::ArcOfEllipse> anEllArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(aCircularEntity->entity());
 
   PointWrapperPtr aPoint =
       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theArcExtremity);
 
-  double* aParams[nbParams] = { aPoint->point()->x, aPoint->point()->y,
-                                anArc->center.x, anArc->center.y };
+  double* aParams[nbParams] = { aPoint->point()->x, aPoint->point()->y, 0, 0 };
+  if (anArc) {
+    aParams[2] = anArc->center.x;
+    aParams[3] = anArc->center.y;
+  }
+  else if (anEllArc) {
+    aParams[2] = anEllArc->center.x;
+    aParams[3] = anEllArc->center.y;
+  }
 
   std::list<GCSConstraintPtr> aConstraints;
   for (int i = 0; i < nbParams; ++i) {
@@ -172,9 +202,7 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnCircle(
   myFixedValues.push_back(*aCircular->center.y);
 
   // create a moved point
-  GCS::Point aPointOnCircle;
-  aPointOnCircle.x = &myFixedValues[0];
-  aPointOnCircle.y = &myFixedValues[1];
+  GCS::Point aPointOnCircle = createGCSPoint(&myFixedValues[0], &myFixedValues[1]);
 
   std::list<GCSConstraintPtr> aConstraints;
   // point-on-circle
@@ -197,6 +225,69 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnCircle(
       new PlaneGCSSolver_ConstraintWrapper(aConstraints, getType()));
 }
 
+ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnEllipse(
+    const EntityWrapperPtr& theConic)
+{
+  static const double scale = 0.01;
+  static const int nbParams = 6;
+  myFixedValues.reserve(nbParams); // moved point; center and focus of ellipse
+
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theConic);
+  std::shared_ptr<GCS::Ellipse> aConic = std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
+
+  // major axis direction
+  double dx = *aConic->focus1.x - *aConic->center.x;
+  double dy = *aConic->focus1.y - *aConic->center.y;
+  double norm = sqrt(dx * dx + dy* dy);
+  if (norm < tolerance) {
+    dx = 1.0;
+    dy = 0.0;
+  }
+  else {
+    dx /= norm;
+    dy /= norm;
+  }
+
+  double aMajorRad = aConic->getRadMaj();
+
+  // initialize fixed values
+  myFixedValues.push_back(*aConic->center.x + dx * aMajorRad);
+  myFixedValues.push_back(*aConic->center.y + dy * aMajorRad);
+  myFixedValues.push_back(*aConic->center.x);
+  myFixedValues.push_back(*aConic->center.y);
+  myFixedValues.push_back(*aConic->focus1.x);
+  myFixedValues.push_back(*aConic->focus1.y);
+
+  // create a moved point
+  GCS::Point aPointOnEllipse = createGCSPoint(&myFixedValues[0], &myFixedValues[1]);
+
+  std::list<GCSConstraintPtr> aConstraints;
+  // point-on-circle
+  GCSConstraintPtr aNewConstraint(
+    new GCS::ConstraintPointOnEllipse(aPointOnEllipse, *aConic));
+  aNewConstraint->rescale(scale);
+  aConstraints.push_back(aNewConstraint);
+  // fixed center (x)
+  aNewConstraint = GCSConstraintPtr(
+    new GCS::ConstraintEqual(&myFixedValues[2], aConic->center.x));
+  aNewConstraint->rescale(scale);
+  aConstraints.push_back(aNewConstraint);
+  // fixed center (y)
+  aNewConstraint = GCSConstraintPtr(
+    new GCS::ConstraintEqual(&myFixedValues[3], aConic->center.y));
+  aNewConstraint->rescale(scale);
+  aConstraints.push_back(aNewConstraint);
+  // focus on the major axis
+  GCS::Point aStartPoint = createGCSPoint(&myFixedValues[2], &myFixedValues[3]);
+  GCS::Point aEndPoint   = createGCSPoint(&myFixedValues[4], &myFixedValues[5]);
+  aNewConstraint = GCSConstraintPtr(
+    new GCS::ConstraintPointOnLine(aConic->focus1, aStartPoint, aEndPoint));
+  aNewConstraint->rescale(scale);
+  aConstraints.push_back(aNewConstraint);
+
+  return ConstraintWrapperPtr(
+    new PlaneGCSSolver_ConstraintWrapper(aConstraints, getType()));
+}
 
 void SketchSolver_ConstraintMovement::startPoint(
     const std::shared_ptr<GeomAPI_Pnt2d>& theStartPoint)
index 1735a70b0488bc1c5e562cbd1fd4bb06495166cf..bfbe1f1ed644f2fc442e11ef918c4cd33275ebcc 100644 (file)
@@ -66,9 +66,12 @@ protected:
   /// \brief Create constraint to fix moved arc extremity
   ConstraintWrapperPtr fixArcExtremity(const EntityWrapperPtr& theArcExtremity);
 
-  /// \brief Creat constraint to fix moved point on circle/arc
+  /// \brief Create constraint to fix moved point on circle/arc
   ConstraintWrapperPtr fixPointOnCircle(const EntityWrapperPtr& theCircular);
 
+  /// \brief Create constraint to fix moved point on ellipse/elliptic arc
+  ConstraintWrapperPtr fixPointOnEllipse(const EntityWrapperPtr& theConic);
+
 private:
   FeaturePtr       myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL)
   AttributePtr     myDraggedPoint; ///< one of the feature points which has been moved
diff --git a/src/SketchSolver/SketchSolver_ConstraintPerpendicular.cpp b/src/SketchSolver/SketchSolver_ConstraintPerpendicular.cpp
new file mode 100644 (file)
index 0000000..4109bb5
--- /dev/null
@@ -0,0 +1,411 @@
+// 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 <SketchSolver_ConstraintPerpendicular.h>
+#include <SketchSolver_Error.h>
+
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_Tools.h>
+#include <PlaneGCSSolver_UpdateCoincidence.h>
+
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Ellipse2d.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMiddle.h>
+
+#include <cmath>
+
+#define GCS_EDGE_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(x)
+#define GCS_POINT_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(x)
+
+/// \brief Obtain constrained features
+static void getFeatures(const ConstraintPtr& theConstraint,
+                        FeaturePtr& theFeature1,
+                        FeaturePtr& theFeature2);
+
+/// \brief Check whether the entities has only one shared point or less.
+///        Return list of coincident points.
+static std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1,
+                                                       FeaturePtr theFeature2);
+
+/// \brief Collect points coincident with each of two features
+static std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
+
+static void calculateIntersectionPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
+                                       GCSPointPtr& theIntersectionPoint);
+
+/// sets angle to 90 or -90 degrees
+static void adjustAngleBetweenCurves(const GCSCurvePtr& theCurve1,
+                                     const GCSCurvePtr& theCurve2,
+                                     const GCSPointPtr& thePoint,
+                                     double*            theAngle);
+
+
+void SketchSolver_ConstraintPerpendicular::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage) {
+    // Not enough parameters are assigned
+    return;
+  }
+
+  EntityWrapperPtr aValue;
+  std::vector<EntityWrapperPtr> anAttributes;
+  SketchSolver_Constraint::getAttributes(aValue, anAttributes);
+  if (!myErrorMsg.empty())
+    return;
+
+  rebuild();
+  if (!myErrorMsg.empty())
+    return;
+
+  myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
+}
+
+void SketchSolver_ConstraintPerpendicular::rebuild()
+{
+  if (mySolverConstraint)
+    myStorage->removeConstraint(myBaseConstraint);
+
+  std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+  mySolverConstraint = ConstraintWrapperPtr();
+  mySharedPoint = AttributePtr();
+  if (myAuxPoint) {
+    GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+    aStorage->removeParameters(aParams);
+    myAuxPoint = EntityWrapperPtr();
+  }
+
+  // Check the quantity of entities of each type and their order (arcs first)
+  int aNbLines = 0;
+  int aNbCircles = 0;
+  int aNbOther = 0;
+  std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
+  for (; anEntIt != myAttributes.end(); ++anEntIt) {
+    if (!(*anEntIt).get())
+      continue;
+    if ((*anEntIt)->type() == ENTITY_LINE)
+      ++aNbLines;
+    else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE)
+      ++aNbCircles;
+    else if ((*anEntIt)->type() != ENTITY_POINT)
+      ++aNbOther;
+  }
+
+  if (aNbLines + aNbCircles + aNbOther == 2) {
+    if (aNbOther > 0)
+      myType = CONSTRAINT_PERPENDICULAR_CURVES;
+  }
+  else {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  }
+
+  FeaturePtr aFeature1, aFeature2;
+  getFeatures(myBaseConstraint, aFeature1, aFeature2);
+
+  // check number of coincident points
+  std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeature1, aFeature2);
+  // Try to find non-boundary points coincident with both features.
+  // It is necesasry to create perpendicularity with ellipse
+  if (aCoincidentPoints.empty() && aNbOther > 0)
+    aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
+
+  EntityWrapperPtr aSharedPointEntity;
+  std::list<GCSConstraintPtr> anAuxConstraints;
+  if (!aCoincidentPoints.empty()) {
+    mySharedPoint = *aCoincidentPoints.begin();
+    aSharedPointEntity = myStorage->entity(mySharedPoint);
+  }
+  else if (aNbOther > 0) {
+    // create auxiliary point
+    GCSPointPtr aPoint(new GCS::Point);
+    aPoint->x = aStorage->createParameter();
+    aPoint->y = aStorage->createParameter();
+    calculateIntersectionPoint(myAttributes.front(), myAttributes.back(), aPoint);
+
+    myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
+    aSharedPointEntity = myAuxPoint;
+
+    // create auxiliary coincident constraints for tangency with ellipse
+    EntityWrapperPtr aDummy;
+    ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+        CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
+    anAuxConstraints = aCoincidence->constraints();
+    aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+        CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
+    anAuxConstraints.insert(anAuxConstraints.end(),
+        aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+  }
+
+  ScalarWrapperPtr anAngleWrapper;
+  if (aSharedPointEntity) {
+    adjustAngleBetweenCurves(GCS_EDGE_WRAPPER(myAttributes.front())->entity(),
+                             GCS_EDGE_WRAPPER(myAttributes.back())->entity(),
+                             GCS_POINT_WRAPPER(aSharedPointEntity)->point(), &myCurveCurveAngle);
+    anAngleWrapper.reset(new PlaneGCSSolver_ScalarWrapper(&myCurveCurveAngle));
+  }
+
+  mySolverConstraint = PlaneGCSSolver_Tools::createConstraint(myBaseConstraint, myType,
+      anAngleWrapper, aSharedPointEntity, EntityWrapperPtr(),
+      myAttributes.front(), myAttributes.back());
+
+  if (!anAuxConstraints.empty()) {
+    anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(),
+        mySolverConstraint->constraints().end());
+    mySolverConstraint->setConstraints(anAuxConstraints);
+  }
+
+  myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
+}
+
+void SketchSolver_ConstraintPerpendicular::notify(const FeaturePtr&      theFeature,
+                                                  PlaneGCSSolver_Update* theUpdater)
+{
+  if (theFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
+    return;
+
+  // base constraint may become invalid (for example, during undo)
+  if (!myBaseConstraint->data() || !myBaseConstraint->data()->isValid())
+    return;
+
+  FeaturePtr aTgFeat1, aTgFeat2;
+  getFeatures(myBaseConstraint, aTgFeat1, aTgFeat2);
+
+  bool isRebuild = false;
+  if (theFeature->data() && theFeature->data()->isValid()) {
+    // the constraint has been created
+    if (!mySharedPoint) {
+      // features has no shared point, check whether coincidence constraint binds these features)
+      int aNbCoincidentFeatures = 0;
+      for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+        AttributeRefAttrPtr aRefAttr = theFeature->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+        if (!aRefAttr)
+          continue;
+
+        ObjectPtr anObj;
+        if (aRefAttr->isObject())
+          anObj = aRefAttr->object();
+        else
+          anObj = aRefAttr->attr()->owner();
+
+        FeaturePtr aFeature = ModelAPI_Feature::feature(anObj);
+        if (aFeature == aTgFeat1 || aFeature == aTgFeat2)
+          ++aNbCoincidentFeatures;
+      }
+
+      if (aNbCoincidentFeatures == 2)
+        isRebuild = true;
+    }
+  }
+
+  if (!isRebuild) {
+    if (mySharedPoint) {
+      // The features are tangent in the shared point, but the coincidence has been removed/updated.
+      // Check if the coincidence is the same.
+      std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
+      isRebuild = true;
+      std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
+      for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
+        if (*anIt == mySharedPoint)
+          isRebuild = false; // the coincidence is still exists => nothing to change
+    }
+    else {
+      // check both features have a coincident point
+      std::set<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
+      isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty());
+    }
+  }
+
+  if (isRebuild)
+    rebuild();
+}
+
+
+
+
+// ==================   Auxiliary functions   =================================
+void getFeatures(const ConstraintPtr& theConstraint,
+                 FeaturePtr&          theFeature1,
+                 FeaturePtr&          theFeature2)
+{
+  AttributeRefAttrPtr aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+  theFeature1 = ModelAPI_Feature::feature(aRefAttr->object());
+  aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+  theFeature2 = ModelAPI_Feature::feature(aRefAttr->object());
+}
+
+static std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+  const std::set<AttributePtr>& aRefs1 = theFeature1->data()->refsToMe();
+  const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
+
+  std::set<FeaturePtr> aCoincidences;
+  std::set<AttributePtr>::const_iterator anIt;
+
+  // collect coincidences referred to the first feature
+  for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
+    FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
+    if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+      aCoincidences.insert(aRef);
+  }
+
+  // leave only coincidences referred to the second feature
+  std::set<FeaturePtr> aCoincidencesBetweenFeatures;
+  for (anIt = aRefs2.begin(); anIt != aRefs2.end(); ++anIt) {
+    FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
+    if (aCoincidences.find(aRef) != aCoincidences.end())
+      aCoincidencesBetweenFeatures.insert(aRef);
+  }
+
+  return aCoincidencesBetweenFeatures;
+}
+
+std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+  std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
+  // collect points only
+  std::set<AttributePtr> aCoincidentPoints;
+  std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
+  for (; aCIt != aCoincidences.end(); ++ aCIt) {
+    AttributeRefAttrPtr aRefAttrA = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
+    AttributeRefAttrPtr aRefAttrB = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_B());
+    if (!aRefAttrA || aRefAttrA->isObject() ||
+        !aRefAttrB || aRefAttrB->isObject())
+      continue;
+
+    AttributePtr anAttrA = aRefAttrA->attr();
+    AttributePtr anAttrB = aRefAttrB->attr();
+    if (anAttrA->id() != SketchPlugin_Arc::CENTER_ID() &&
+        anAttrA->id() != SketchPlugin_Circle::CENTER_ID() &&
+        anAttrB->id() != SketchPlugin_Arc::CENTER_ID() &&
+        anAttrB->id() != SketchPlugin_Circle::CENTER_ID()) {
+      aCoincidentPoints.insert(anAttrA);
+      aCoincidentPoints.insert(anAttrB);
+    }
+  }
+  return aCoincidentPoints;
+}
+
+static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)
+{
+  std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
+  const std::list<ResultPtr>& aResults = theFeature->results();
+  for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+      anIt != aResults.end(); ++anIt) {
+    const std::set<AttributePtr>& aResRefs = (*anIt)->data()->refsToMe();
+    aRefs.insert(aResRefs.begin(), aResRefs.end());
+  }
+  return aRefs;
+}
+
+// collect all points coincident with the feature
+static std::set<AttributePtr> pointsOnFeature(FeaturePtr theFeature)
+{
+  std::set<AttributePtr> aPoints;
+
+  std::set<AttributePtr> aRefs = refsToFeatureAndResults(theFeature);
+  for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+    FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
+    if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+                 aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) {
+      for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+        AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+        if (aRefAttr) {
+          AttributePtr anAttr = aRefAttr->attr();
+          if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+                        anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+            aPoints.insert(anAttr);
+        }
+      }
+    }
+  }
+  return aPoints;
+}
+
+std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+  std::set<AttributePtr> aPointsOnF1 = pointsOnFeature(theFeature1);
+  std::set<AttributePtr> aPointsOnF2 = pointsOnFeature(theFeature2);
+
+  std::set<AttributePtr> aCommonPoints;
+  for (std::set<AttributePtr>::iterator anIt = aPointsOnF1.begin();
+       anIt != aPointsOnF1.end(); ++anIt)
+    if (aPointsOnF2.find(*anIt) != aPointsOnF2.end())
+      aCommonPoints.insert(*anIt);
+  return aCommonPoints;
+}
+
+void adjustAngleBetweenCurves(const GCSCurvePtr& theCurve1,
+                              const GCSCurvePtr& theCurve2,
+                              const GCSPointPtr& thePoint,
+                              double*            theAngle)
+{
+  double anAngle = GCS::System().calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
+  // bring angle to [-pi..pi]
+  if (anAngle >  PI) anAngle -= 2.0 * PI;
+  if (anAngle < -PI) anAngle += 2.0 * PI;
+  // set angle value according to the current angle between curves
+  if (anAngle >= 0)
+    *theAngle = PI / 2.;
+  else
+    *theAngle = -PI / 2.;
+}
+
+void calculateIntersectionPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
+                                GCSPointPtr& theIntersectionPoint)
+{
+  std::shared_ptr<GeomAPI_Ellipse2d> anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1);
+  EntityWrapperPtr aCurve2 = theCurve2;
+  if (!anEllipse) {
+    // try converting to ellipse the second curve
+    anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2);
+    if (!anEllipse)
+      return; // no one curve is ellipse
+    aCurve2 = theCurve1;
+  }
+
+  GeomPnt2dPtr aP1, aP2;
+  if (aCurve2->type() == ENTITY_LINE) {
+    std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aCurve2);
+    anEllipse->distance(aLine, aP1, aP2);
+  }
+  else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) {
+    std::shared_ptr<GeomAPI_Circ2d> aCircle = PlaneGCSSolver_Tools::circle(aCurve2);
+    anEllipse->distance(aCircle, aP1, aP2);
+  }
+  else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTIC_ARC) {
+    std::shared_ptr<GeomAPI_Ellipse2d> anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2);
+    anEllipse->distance(anEl2, aP1, aP2);
+  }
+
+  if (aP1 && aP2) {
+    *theIntersectionPoint->x = 0.5 * (aP1->x() + aP2->x());
+    *theIntersectionPoint->y = 0.5 * (aP1->y() + aP2->y());
+  }
+}
diff --git a/src/SketchSolver/SketchSolver_ConstraintPerpendicular.h b/src/SketchSolver/SketchSolver_ConstraintPerpendicular.h
new file mode 100644 (file)
index 0000000..822c702
--- /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 SketchSolver_ConstraintPerpendicular_H_
+#define SketchSolver_ConstraintPerpendicular_H_
+
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintPerpendicular
+ *  \ingroup Plugins
+ *  \brief   Convert perpendicularity constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
+{
+public:
+  /// Constructor based on SketchPlugin constraint
+  SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint),
+      myCurveCurveAngle(0.0)
+  {}
+
+  /// \brief Notify this object about the feature is changed somewhere
+  virtual void notify(const FeaturePtr&      theFeature,
+                      PlaneGCSSolver_Update* theUpdater);
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of solver constraints
+  virtual void process();
+
+  /// \brief Remove current constraint from the storage and build is again
+  void rebuild();
+
+private:
+  double myCurveCurveAngle;
+  AttributePtr mySharedPoint;
+  EntityWrapperPtr myAuxPoint;
+};
+
+#endif
index eaa0e2c41696068e8d5507a1b17dc759beccc3b8..18d95f8ec9d5c533dcaf88caf62f091719155b7b 100644 (file)
 
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
 #include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateCoincidence.h>
 
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Lin2d.h>
 #include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Ellipse2d.h>
+
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_ConstraintMiddle.h>
 
 #include <cmath>
 
@@ -47,6 +54,9 @@ static std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeatureP
 static std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1,
                                                        FeaturePtr theFeature2);
 
+/// \brief Collect points coincident with each of two features
+static std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
+
 /// \brief Check if two connected arcs have centers
 ///        in same direction relatively to connection point
 static bool isArcArcTangencyInternal(EntityWrapperPtr theArc1,
@@ -59,11 +69,14 @@ static ConstraintWrapperPtr
                         double*          theAngle = 0);
 
 static ConstraintWrapperPtr
-  createArcArcTangency(EntityWrapperPtr theEntity1,
-                       EntityWrapperPtr theEntity2,
-                       bool             theInternalTangency,
-                       EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
-                       double*          theAngle = 0);
+  createCurveCurveTangency(EntityWrapperPtr theEntity1,
+                           EntityWrapperPtr theEntity2,
+                           bool             theInternalTangency,
+                           EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
+                           double*          theAngle = 0);
+
+static void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
+                                   GCSPointPtr& theTangencyPoint);
 
 
 void SketchSolver_ConstraintTangent::process()
@@ -92,12 +105,21 @@ void SketchSolver_ConstraintTangent::rebuild()
   if (mySolverConstraint)
     myStorage->removeConstraint(myBaseConstraint);
 
+  std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
   mySolverConstraint = ConstraintWrapperPtr();
   mySharedPoint = AttributePtr();
+  if (myAuxPoint) {
+    GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+    aStorage->removeParameters(aParams);
+    myAuxPoint = EntityWrapperPtr();
+  }
 
   // Check the quantity of entities of each type and their order (arcs first)
   int aNbLines = 0;
   int aNbCircles = 0;
+  int aNbEllipses = 0;
   std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
   for (; anEntIt != myAttributes.end(); ++anEntIt) {
     if (!(*anEntIt).get())
@@ -106,17 +128,19 @@ void SketchSolver_ConstraintTangent::rebuild()
       ++aNbLines;
     else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE)
       ++aNbCircles;
+    else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC)
+      ++aNbEllipses;
   }
 
-  if (aNbCircles < 1) {
+  if (aNbCircles + aNbEllipses < 1) {
     myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
     return;
   }
   if (aNbLines == 1 && aNbCircles == 1) {
     myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
   }
-  else if (aNbCircles == 2) {
-    myType = CONSTRAINT_TANGENT_CIRCLE_CIRCLE;
+  else if (aNbLines + aNbCircles + aNbEllipses == 2) {
+    myType = CONSTRAINT_TANGENT_CURVE_CURVE;
     isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
   }
   else {
@@ -134,26 +158,58 @@ void SketchSolver_ConstraintTangent::rebuild()
     return;
   }
 
+  // Try to find non-boundary points coincident with both features.
+  // It is necesasry to create tangency with ellipse
+  if (aCoincidentPoints.empty() && aNbEllipses > 0)
+    aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
+
   EntityWrapperPtr aSharedPointEntity;
+  std::list<GCSConstraintPtr> anAuxConstraints;
   if (!aCoincidentPoints.empty()) {
     mySharedPoint = *aCoincidentPoints.begin();
     aSharedPointEntity = myStorage->entity(mySharedPoint);
   }
+  else if (aNbEllipses > 0) {
+    // create auxiliary point
+    GCSPointPtr aPoint(new GCS::Point);
+    aPoint->x = aStorage->createParameter();
+    aPoint->y = aStorage->createParameter();
+    calculateTangencyPoint(myAttributes.front(), myAttributes.back(), aPoint);
+
+    myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
+    aSharedPointEntity = myAuxPoint;
+
+    // create auxiliary coincident constraints for tangency with ellipse
+    EntityWrapperPtr aDummy;
+    ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+        CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
+    anAuxConstraints = aCoincidence->constraints();
+    aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+        CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
+    anAuxConstraints.insert(anAuxConstraints.end(),
+        aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+  }
 
   if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
     mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(),
                                            aSharedPointEntity, &myCurveCurveAngle);
   } else {
-    mySolverConstraint = createArcArcTangency(myAttributes.front(), myAttributes.back(),
+    mySolverConstraint = createCurveCurveTangency(myAttributes.front(), myAttributes.back(),
                             isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
   }
 
+  if (!anAuxConstraints.empty()) {
+    anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(),
+        mySolverConstraint->constraints().end());
+    mySolverConstraint->setConstraints(anAuxConstraints);
+  }
+
   myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
 }
 
 void SketchSolver_ConstraintTangent::adjustConstraint()
 {
-  if (myType == CONSTRAINT_TANGENT_CIRCLE_CIRCLE) {
+  if (myType == CONSTRAINT_TANGENT_CURVE_CURVE) {
     EntityWrapperPtr anEntity1 =
         myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
     EntityWrapperPtr anEntity2 =
@@ -204,15 +260,22 @@ void SketchSolver_ConstraintTangent::notify(const FeaturePtr&      theFeature,
     }
   }
 
-  if (mySharedPoint && !isRebuild) {
-    // The features are tangent in the shared point, but the coincidence has been removed/updated.
-    // Check if the coincidence is the same.
-    std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
-    isRebuild = true;
-    std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
-    for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
-      if (*anIt == mySharedPoint)
-        isRebuild = false; // the coincidence is still exists => nothing to change
+  if (!isRebuild) {
+    if (mySharedPoint) {
+      // The features are tangent in the shared point, but the coincidence has been removed/updated.
+      // Check if the coincidence is the same.
+      std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
+      isRebuild = true;
+      std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
+      for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
+        if (*anIt == mySharedPoint)
+          isRebuild = false; // the coincidence is still exists => nothing to change
+    }
+    else {
+      // check both features have a coincident point
+      std::set<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
+      isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty());
+    }
   }
 
   if (isRebuild)
@@ -285,6 +348,56 @@ std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeatureP
   return aCoincidentPoints;
 }
 
+static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)
+{
+  std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
+  const std::list<ResultPtr>& aResults = theFeature->results();
+  for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+      anIt != aResults.end(); ++anIt) {
+    const std::set<AttributePtr>& aResRefs = (*anIt)->data()->refsToMe();
+    aRefs.insert(aResRefs.begin(), aResRefs.end());
+  }
+  return aRefs;
+}
+
+// collect all points coincident with the feature
+static std::set<AttributePtr> pointsOnFeature(FeaturePtr theFeature)
+{
+  std::set<AttributePtr> aPoints;
+
+  std::set<AttributePtr> aRefs = refsToFeatureAndResults(theFeature);
+  for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+    FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
+    if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+                 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
+                 aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) {
+      for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+        AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+        if (aRefAttr) {
+          AttributePtr anAttr = aRefAttr->attr();
+          if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+                        anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+            aPoints.insert(anAttr);
+        }
+      }
+    }
+  }
+  return aPoints;
+}
+
+std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+  std::set<AttributePtr> aPointsOnF1 = pointsOnFeature(theFeature1);
+  std::set<AttributePtr> aPointsOnF2 = pointsOnFeature(theFeature2);
+
+  std::set<AttributePtr> aCommonPoints;
+  for (std::set<AttributePtr>::iterator anIt = aPointsOnF1.begin();
+       anIt != aPointsOnF1.end(); ++anIt)
+    if (aPointsOnF2.find(*anIt) != aPointsOnF2.end())
+      aCommonPoints.insert(*anIt);
+  return aCommonPoints;
+}
+
 bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2)
 {
   std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(
@@ -358,30 +471,65 @@ ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1,
       new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE));
 }
 
-ConstraintWrapperPtr createArcArcTangency(EntityWrapperPtr theEntity1,
-                                          EntityWrapperPtr theEntity2,
-                                          bool             theInternalTangency,
-                                          EntityWrapperPtr theSharedPoint,
-                                          double*          theAngle)
+ConstraintWrapperPtr createCurveCurveTangency(EntityWrapperPtr theEntity1,
+                                              EntityWrapperPtr theEntity2,
+                                              bool             theInternalTangency,
+                                              EntityWrapperPtr theSharedPoint,
+                                              double*          theAngle)
 {
-  std::shared_ptr<GCS::Circle> aCirc1 =
-    std::dynamic_pointer_cast<GCS::Circle>(GCS_EDGE_WRAPPER(theEntity1)->entity());
-  std::shared_ptr<GCS::Circle> aCirc2 =
-    std::dynamic_pointer_cast<GCS::Circle>(GCS_EDGE_WRAPPER(theEntity2)->entity());
+  GCSCurvePtr aCurve1 =
+    std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity1)->entity());
+  GCSCurvePtr aCurve2 =
+    std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity2)->entity());
 
   GCSConstraintPtr aNewConstr;
   if (theSharedPoint) {
     GCSPointPtr aPoint =
         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
 
-    adjustAngleBetweenCurves(aCirc1, aCirc2, aPoint, theAngle);
+    adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle);
     aNewConstr =
-        GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCirc1, *aCirc2, *aPoint, theAngle));
+        GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCurve1, *aCurve2, *aPoint, theAngle));
   } else {
+    std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(aCurve1);
+    std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(aCurve2);
     aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
                                   aCirc1->rad, aCirc2->rad, theInternalTangency));
   }
 
   return ConstraintWrapperPtr(
-      new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_CIRCLE));
+      new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CURVE_CURVE));
+}
+
+void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
+                            GCSPointPtr& theTangencyPoint)
+{
+  std::shared_ptr<GeomAPI_Ellipse2d> anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1);
+  EntityWrapperPtr aCurve2 = theCurve2;
+  if (!anEllipse) {
+    // try converting to ellipse the second curve
+    anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2);
+    if (!anEllipse)
+      return; // no one curve is ellipse
+    aCurve2 = theCurve1;
+  }
+
+  GeomPnt2dPtr aP1, aP2;
+  if (aCurve2->type() == ENTITY_LINE) {
+    std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aCurve2);
+    anEllipse->distance(aLine, aP1, aP2);
+  }
+  else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) {
+    std::shared_ptr<GeomAPI_Circ2d> aCircle = PlaneGCSSolver_Tools::circle(aCurve2);
+    anEllipse->distance(aCircle, aP1, aP2);
+  }
+  else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTIC_ARC) {
+    std::shared_ptr<GeomAPI_Ellipse2d> anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2);
+    anEllipse->distance(anEl2, aP1, aP2);
+  }
+
+  if (aP1 && aP2) {
+    *theTangencyPoint->x = 0.5 * (aP1->x() + aP2->x());
+    *theTangencyPoint->y = 0.5 * (aP1->y() + aP2->y());
+  }
 }
index 6af491ec770e5452bb4550a2da9a729b6685d33d..57424b293492e0284afa606dc63c178c4499d1c7 100644 (file)
@@ -55,6 +55,7 @@ private:
   bool isArcArcInternal;
   double myCurveCurveAngle;
   AttributePtr mySharedPoint;
+  EntityWrapperPtr myAuxPoint;
 };
 
 #endif
index a4f9ea53cfbc84a6845cb17e2c0f254c6e73f8dd..e6e3a002ce3f500f4e53583791224a85a4616f0b 100644 (file)
@@ -99,7 +99,7 @@ class SketchSolver_Error
   /// Crash in SolveSpace
   inline static const std::string& SOLVESPACE_CRASH()
   {
-    static const std::string MY_ERROR_VALUE("Caution: SolveSpace crash! Constraints are wrong");
+    static const std::string MY_ERROR_VALUE("Caution: SolveSpace crashed! Constraints are wrong");
     return MY_ERROR_VALUE;
   }
   /// Constraint has wrong type
index 5a66f99b006ed8b2f3764f0d53d404b6223737d2..ab9b38fc2df6789e841b275e22e425f2805d9e19 100644 (file)
@@ -33,6 +33,8 @@
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
 
+#include <Config_Translator.h>
+
 
 static void sendMessage(const char* theMessageName)
 {
@@ -179,6 +181,7 @@ static SolverConstraintPtr move(StoragePtr theStorage,
     SolverConstraintPtr(aConstraint)->process(theStorage, theEventsBlocked);
     if (aConstraint->error().empty()) {
       aConstraint->startPoint(theFrom);
+      theStorage->adjustParametrizationOfArcs();
       theSketchSolver->initialize();
       aConstraint->moveTo(theTo);
       theStorage->setNeedToResolve(true);
@@ -236,8 +239,10 @@ bool SketchSolver_Group::resolveConstraints()
 
     PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK;
     try {
-      if (!isGroupEmpty)
+      if (!isGroupEmpty) {
+        myStorage->adjustParametrizationOfArcs();
         aResult = mySketchSolver->solve();
+      }
       if (aResult == PlaneGCSSolver_Solver::STATUS_FAILED &&
           !myTempConstraints.empty()) {
         mySketchSolver->undo();
@@ -348,15 +353,29 @@ bool SketchSolver_Group::resolveConstraints()
 // ============================================================================
 void SketchSolver_Group::computeDoF()
 {
-  std::ostringstream aDoFMsg;
+  std::string aDoFMsg;
+  static const std::string aMsgContext("Sketch");
   int aDoF = mySketchSolver->dof();
   /// "DoF = 0" content of string value is used in PartSet by Sketch edit
   /// If it is changed, it should be corrected also there
-  if (aDoF == 0)
-    aDoFMsg << "Sketch is fully fixed (DoF = 0)";
-  else
-    aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
-  mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
+  //if (aDoF == 0) {
+  //  static const std::string aMsgDoF("Sketch is fully fixed (DoF = 0)");
+  //  aDoFMsg = Config_Translator::translate(aMsgContext, aMsgDoF);
+  //} else {
+  //  static const std::string aMsgDoF("DoF (degrees of freedom) = %1");
+  //  Events_InfoMessage aMsg(aMsgContext, aMsgDoF);
+  //  aMsg.addParameter(aDoF);
+  //  aDoFMsg = Config_Translator::translate(aMsg);
+  //}
+  //// store Unicode value for translated message about DoF
+  //size_t aLen = aDoFMsg.size();
+  //std::wstring aWStr(aLen, L'#');
+  //mbstowcs(&aWStr[0], aDoFMsg.c_str(), aLen);
+  //mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aWStr);
+
+  std::ostringstream aStr;
+  aStr << aDoF;
+  mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aStr.str());
 
   if (aDoF > 0 && myDOF <= 0)
     sendMessage(EVENT_SKETCH_UNDER_CONSTRAINED, mySketch, aDoF);
index 4d483105843642a9bff4be766c9ff31b0983c3c1..0757abfb7f2abf3f060ff3559a7fec4f09f70831 100644 (file)
@@ -150,6 +150,11 @@ public:
   /// \brief Notify all subscribers about update of the feature
   void notify(const FeaturePtr& theFeature) const;
 
+  /// \brief Make parametrization of arcs consistent.
+  ///        Forward arcs should have the last parameter greater than the first parameter.
+  ///        Reversed arcs should have the last parameter lesser than the first parameter.
+  virtual void adjustParametrizationOfArcs() = 0;
+
 protected:
   /// \brief Convert result to feature or attribute if theResult is linked to center of circle/arc
   static void resultToFeatureOrAttribute(const ObjectPtr& theResult,
index 9d2ebc74f373b6a769dd8a9a14271734782c5c3c..acb900786804de168feac34909cc66b4af60a0ac 100644 (file)
@@ -12,8 +12,8 @@
       <translation>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.</translation>
     </message>
     <message>
-      <source>Caution: SolveSpace crash! Constraints are wrong</source>
-      <translation>Caution: SolveSpace crash! Constraints are wrong</translation>
+      <source>Caution: SolveSpace crashed! Constraints are wrong</source>
+      <translation>Caution: SolveSpace crashed! Constraints are wrong</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>
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 2eecd66c1e8331b9f3e1a77fab5b1640b4f3cf90..b895b6d6be67b50f88ae1e4a81f4e24c345ed297 100644 (file)
@@ -205,6 +205,9 @@ bool SketcherPrs_LengthDimension::readyToDisplay(ModelAPI_Feature* theConstraint
                                                  const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                                  gp_Pnt& thePnt1, gp_Pnt& thePnt2)
 {
+  if (!thePlane)
+    return false;
+
   DataPtr aData = theConstraint->data();
   if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
     // The constraint is length
index 314c74cb283f94240d26868b9fb39ffceb17e4c2..acd166cb9343a2fa375c219f22e53c6f9605e4c8 100644 (file)
@@ -29,6 +29,7 @@
 #include <GeomAPI_Curve.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Lin.h>
+#include <GeomAPI_Vertex.h>
 
 
 IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Perpendicular, SketcherPrs_SymbolPrs);
@@ -72,22 +73,10 @@ bool SketcherPrs_Perpendicular::updateIfReadyToDisplay(double theStep, bool with
   GeomEdgePtr aEdge1(new GeomAPI_Edge(aShp1));
   GeomEdgePtr aEdge2(new GeomAPI_Edge(aShp2));
 
-  std::shared_ptr<GeomAPI_Lin> aLin1 = aEdge1->line();
-  std::shared_ptr<GeomAPI_Lin> aLin2 = aEdge2->line();
-
-  std::shared_ptr<GeomAPI_Pnt> aPnt = aLin1->intersect(aLin2);
-  double aParam1 = aLin1->projParam(aPnt);
-  double aParam2 = aLin2->projParam(aPnt);
-
-  GeomAPI_Curve aCurve1(aShp1);
-  GeomAPI_Curve aCurve2(aShp2);
-  bool isInside1 = (aParam1 >= (aCurve1.startParam() - Precision::Confusion())) &&
-    (aParam1 <= (aCurve1.endParam() + Precision::Confusion()));
-  bool isInside2 = (aParam2 >= (aCurve2.startParam() - Precision::Confusion())) &&
-    (aParam2 <= (aCurve2.endParam() + Precision::Confusion()));
-
-  if (!(isInside1 && isInside2))
-    aPnt = std::shared_ptr<GeomAPI_Pnt>();
+  GeomShapePtr anInter = aEdge1->intersect(aEdge2);
+  std::shared_ptr<GeomAPI_Pnt> aPnt;
+  if (anInter && anInter->isVertex())
+    aPnt = anInter->vertex()->point();
 
   // Compute position of symbols
   SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
@@ -105,14 +94,13 @@ bool SketcherPrs_Perpendicular::updateIfReadyToDisplay(double theStep, bool with
 void SketcherPrs_Perpendicular::drawLines(const Handle(Prs3d_Presentation)& thePrs,
                                           Quantity_Color theColor) const
 {
-  Handle(Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup(thePrs);
-
-  Handle(Graphic3d_AspectLine3d) aLineAspect =
-    new Graphic3d_AspectLine3d(theColor, Aspect_TOL_SOLID, 2);
-  aGroup->SetPrimitivesAspect(aLineAspect);
-
   // Draw constrained lines
-  addLine(aGroup, SketchPlugin_Constraint::ENTITY_A());
-  addLine(aGroup, SketchPlugin_Constraint::ENTITY_B());
+  for (int i = 0; i < 2; ++i) {
+    ObjectPtr anObj =
+        SketcherPrs_Tools::getResult(myConstraint, SketchPlugin_Constraint::ATTRIBUTE(i));
+    GeomShapePtr aShape = SketcherPrs_Tools::getShape(anObj);
+    if (!aShape)
+      return;
+    drawShape(aShape, thePrs, theColor);
+  }
 }
-
index 0a546233d9b33060c9ba1257475d3cd95622f06d..7aacd2002093c332c992a444deaac12f75898e03 100644 (file)
 #include "SketcherPrs_PositionMgr.h"
 #include "SketcherPrs_Tools.h"
 
-#include <GeomAPI_Edge.h>
-#include <GeomAPI_Curve.h>
-#include <GeomAPI_Vertex.h>
-#include <GeomAPI_Dir.h>
 #include <GeomAPI_Ax3.h>
 #include <GeomAPI_Circ.h>
+#include <GeomAPI_Curve.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Dir.h>
 #include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Vertex.h>
 
 #include <GeomDataAPI_Point2D.h>
 
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Line.h>
 #include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintTangent.h>
 
 #include <TopoDS_Vertex.hxx>
 #include <Geom_Curve.hxx>
@@ -189,7 +191,7 @@ gp_Vec getVector(ObjectPtr theShape, GeomDirPtr theDir, gp_Pnt theP)
     std::shared_ptr<GeomAPI_Curve> aCurve =
       std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape));
 
-    if (aCurve->isCircle()) {
+    if (aCurve->isCircle() || aCurve->isEllipse()) {
       Handle(Geom_Curve) aCurv = aCurve->impl<Handle_Geom_Curve>();
       GeomAPI_ProjectPointOnCurve anExtr(theP, aCurv);
       double aParam = anExtr.LowerDistanceParameter();
@@ -328,8 +330,7 @@ std::list<ObjectPtr> getCurves(const GeomPointPtr& thePnt, const SketcherPrs_Sym
         if (aDist <= Precision::Confusion())
           aList.push_back(aFeature->firstResult());
       }
-    } else if ((aFeature->getKind() == SketchPlugin_Circle::ID()) ||
-              (aFeature->getKind() == SketchPlugin_Arc::ID())) {
+    } else {
       GeomCurvePtr aCurve;
       ObjectPtr aResObj;
       std::list<ResultPtr> aResults = aFeature->results();
@@ -343,10 +344,16 @@ std::list<ObjectPtr> getCurves(const GeomPointPtr& thePnt, const SketcherPrs_Sym
         }
       }
       if (aCurve.get()) {
-        double aStart = aCurve->startParam();
-        double aEnd = aCurve->endParam();
-        GeomCirclePtr  aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
-        GeomPointPtr aProjPnt = aCircle->project(thePnt);
+        GeomPointPtr aProjPnt;
+        if (aFeature->getKind() == SketchPlugin_Circle::ID() ||
+            aFeature->getKind() == SketchPlugin_Arc::ID()) {
+          GeomCirclePtr aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
+          aProjPnt = aCircle->project(thePnt);
+        }
+        else if (aFeature->getKind() == SketchPlugin_Ellipse::ID()) {
+          GeomEllipsePtr anEllipse = GeomEllipsePtr(new GeomAPI_Ellipse(aCurve));
+          aProjPnt = anEllipse->project(thePnt);
+        }
         if (aProjPnt && thePnt->distance(aProjPnt) <= Precision::Confusion())
           aList.push_back(aResObj);
       }
index de8c26897ccac5dea6927af09ba4911514cb403e..1e23091c2525213cc852c06a88188be815752c0e 100644 (file)
@@ -185,9 +185,11 @@ IF (${UPDATE_TRANSLATION})
                            ${TEXT_RESOURCES}
                            OPTIONS -extensions cpp -no-recursive
                           )
-ELSE(${UPDATE_TRANSLATION)
-    QT5_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES})
-ENDIF(${UPDATE_TRANSLATION)
+ELSE(${UPDATE_TRANSLATION})
+    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 644027633cb26a7673b98cdf51769f905a44f937..2c2b87f4c8d7df3b455baf1f843369b8c135c28c 100644 (file)
@@ -251,28 +251,28 @@ QAction* XGUI_ActionsMgr::operationStateAction(OperationStateActionId theId)
       case Accept:
       case AcceptAll: {
         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_ok.png"),
-                            "Apply" /*empty to show error*/, aParent);
+                            tr("Apply"), aParent);
       }
       break;
       case AcceptPlus: {
         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_ok-plus.png"),
-                            "Apply and continue" /*empty to show error*/, aParent);
+                            tr("Apply and continue"), aParent);
       }
       break;
       case Abort:
       case AbortAll: {
-        aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_cancel.png"), "Cancel",
+        aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_cancel.png"), tr("Cancel"),
                                                  aParent);
       }
       break;
       case Help: {
-        aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_help.png"), "Help",
+        aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_help.png"), tr("Help"),
                                                  aParent);
       }
       break;
       case Preview: {
         aResult = ModuleBase_Tools::createAction(QIcon(), tr("See preview"),
-                                                 aParent, 0, 0, "Compute preview");
+                                                 aParent, 0, 0, tr("Compute preview"));
         aResult->setStatusTip(aResult->toolTip());
       }
       break;
index 226aa30dda252dfedcba4bca6b533df7f10a1a5d..00cf24153ffbe8d7edd5e460e3d74bbe0ab5b0de 100644 (file)
@@ -293,7 +293,6 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
     bool hasCompositeOwner = false;
     bool hasResultInHistory = false;
     bool hasFolder = false;
-    bool canBeDeleted = true;
     ModuleBase_Tools::checkObjects(aObjects, hasResult, hasFeature, hasParameter,
                                    hasCompositeOwner, hasResultInHistory, hasFolder);
     //Process Feature
@@ -333,13 +332,7 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
         if( aMgr->activeDocument() == aObject->document() )
         {
           action("RENAME_CMD")->setEnabled(true);
-          if (aObject->groupName() == ModelAPI_ResultConstruction::group()) {
-            FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
-            canBeDeleted = aFeature->isInHistory();
-            action("DELETE_CMD")->setEnabled(canBeDeleted);
-          }
-          else
-            action("DELETE_CMD")->setEnabled(!hasCompositeOwner);
+          action("DELETE_CMD")->setEnabled(!hasCompositeOwner);
           action("CLEAN_HISTORY_CMD")->setEnabled(!hasCompositeOwner &&
                                                   (hasFeature || hasParameter));
         }
@@ -353,16 +346,9 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
         action("SHOW_ONLY_CMD")->setEnabled(true);
         action("SHADING_CMD")->setEnabled(true);
         action("WIREFRAME_CMD")->setEnabled(true);
-
-        foreach(ObjectPtr aObj, aObjects) {
-          FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
-          if (!aFeature->isInHistory()) {
-            canBeDeleted = false;
-            break;
-          }
-        }
-        action("DELETE_CMD")->setEnabled(canBeDeleted);
       }
+      if (hasFeature && myWorkshop->canMoveFeature())
+        action("MOVE_CMD")->setEnabled(true);
     } // end multi-selection
 
     // Check folder management commands state if only features are selected
@@ -462,8 +448,8 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
         break;
       }
     if (!hasCompositeOwner && allActive ) {
-      if (hasResult || hasFeature || hasParameter)  // #2924 results can be erased
-        action("DELETE_CMD")->setEnabled(canBeDeleted);
+      if (hasResult || hasFeature || hasParameter) // #2924 results can be erased
+        action("DELETE_CMD")->setEnabled(true);
     }
     if (!hasCompositeOwner && allActive && (hasFeature|| hasParameter))
       action("CLEAN_HISTORY_CMD")->setEnabled(true);
@@ -609,8 +595,7 @@ void XGUI_ContextMenuMgr::updateViewerMenu()
   if (myWorkshop->canChangeProperty("TRANSPARENCY_CMD"))
     action("TRANSPARENCY_CMD")->setEnabled(true);
 
-  // Delete command is not used in viewer pop-up menu
-  action("DELETE_CMD")->setEnabled(false);
+  action("DELETE_CMD")->setEnabled(true);
 }
 
 void XGUI_ContextMenuMgr::connectObjectBrowser()
@@ -784,7 +769,7 @@ void XGUI_ContextMenuMgr::addObjBrowserMenu(QMenu* theMenu) const
       aActions.append(action("ADD_OUT_FOLDER_BEFORE_CMD"));
       aActions.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
       aActions.append(mySeparator3);
-      //aActions.append(action("MOVE_CMD"));
+      aActions.append(action("MOVE_CMD"));
       aActions.append(action("COLOR_CMD"));
       aActions.append(action("DEFLECTION_CMD"));
       aActions.append(action("TRANSPARENCY_CMD"));
index 2b1c9a1ab470310e6f801f5dbda772c9a4760d9d..ccad93e0e2325f4d0a776c4c8a9044ebb5b3af85 100644 (file)
@@ -618,12 +618,6 @@ bool XGUI_Displayer::enableUpdateViewer(const bool isEnabled)
   return aWasEnabled;
 }
 
-//**************************************************************
-bool XGUI_Displayer::isUpdateEnabled() const
-{
-  return myViewerBlockedRecursiveCount == 0;
-}
-
 //**************************************************************
 void XGUI_Displayer::updateViewer() const
 {
@@ -1061,8 +1055,6 @@ void XGUI_Displayer::displayTrihedron(bool theToDisplay) const
     if (getCallBack()) getCallBack()->Remove(aTrihedron);
     #endif
   }
-
-  updateViewer();
 }
 
 //**************************************************************
index 62362084acfc89d1c771c78a0dc228952cce1978..45ea2eecbc7ba1f6dcafc3a6055b9537f84bca61 100644 (file)
@@ -277,7 +277,10 @@ public:
   bool enableUpdateViewer(const bool isEnabled);
 
   /// Returns true if the viewer update is not blocked
-  bool isUpdateEnabled() const;
+  bool isUpdateEnabled() const
+  {
+    return myViewerBlockedRecursiveCount == 0;
+  }
 
   /// Updates the viewer
   void updateViewer() const;
index 1f945e65d0295150e6e7419f88649ee939a1fa29..40ba050549eabf419e600ade300c4ef91c91286d 100644 (file)
@@ -201,12 +201,12 @@ void XGUI_ErrorMgr::updateToolTip(ModuleBase_ModelWidget* theWidget,
     if (aLabel) continue;
 
     // Get the original tool tip of the widget
-    QString aTTip = aWidget->toolTip().section("Errors:\n", 0, 0).trimmed();
+    QString aTTip = aWidget->toolTip().section(tr("Errors:") + "\n", 0, 0).trimmed();
     // Add the error message into the tool tip
     if (!theError.isEmpty()) {
       if (!aTTip.isEmpty())
         aTTip.append('\n');
-      aTTip += "Errors:\n" + theError;
+      aTTip += tr("Errors:") + "\n" + theError;
     }
     aWidget->setToolTip(aTTip);
     //aWidget->setStyleSheet(anError.isEmpty() ? "" : "background-color:pink;");
index 088f1eddc645a6cfb0fb623699c2b82dba9b4e6d..6d615ac06dbe53dce38181ce38f964017dc631b9 100644 (file)
@@ -138,8 +138,8 @@ XGUI_InspectionPanel::XGUI_InspectionPanel(QWidget* theParent, XGUI_SelectionMgr
   mySubShapesTab->setHorizontalHeaderLabels(aTitles);
 
   QStringList aSubShapes;
-  aSubShapes << "SHAPE" << "COMPOUND" << "COMPSOLID" <<
-    "SOLID" << "SHELL" << "FACE" << "WIRE" << "EDGE" << "VERTEX";
+  aSubShapes << tr("SHAPE") << tr("COMPOUND") << tr("COMPSOLID") <<
+    tr("SOLID") << tr("SHELL") << tr("FACE") << tr("WIRE") << tr("EDGE") << tr("VERTEX");
   int i = 0;
   foreach(QString aType, aSubShapes) {
     QTableWidgetItem* aItem = new QTableWidgetItem(aType);
index 8a6fce040eea66438bf3e15a06400e3e6f1acc27..a568936349dfa115714c355388a6fe79529d07f4 100644 (file)
@@ -40,6 +40,7 @@
 #endif
 
 #include <ModuleBase_IModule.h>
+#include <ModuleBase_Tools.h>
 
 #include <QObject>
 #include <QAction>
@@ -74,15 +75,18 @@ void XGUI_MenuMgr::addFeature(const std::shared_ptr<Config_FeatureMessage>& theM
 #endif
     return;
   }
+  QString aWchName = ModuleBase_Tools::translate("workshop", theMessage->workbenchId());
+  theMessage->setToolBarId(ModuleBase_Tools::translate("workshop",
+      theMessage->workbenchId()).toStdString());
 #ifdef HAVE_SALOME
-  std::shared_ptr<XGUI_MenuWorkbench> aWorkbench = findWorkbench(theMessage->workbenchId());
+  std::string aWchNameString = aWchName.toStdString();
+  std::shared_ptr<XGUI_MenuWorkbench> aWorkbench = findWorkbench(aWchNameString);
   std::shared_ptr<XGUI_MenuGroup> aGroup = aWorkbench->findGroup(theMessage->groupId());
   aGroup->setFeatureInfo(theMessage);
 #else
   ActionInfo aFeatureInfo;
   aFeatureInfo.initFrom(theMessage);
 
-  QString aWchName = QString::fromStdString(theMessage->workbenchId());
   QStringList aNestedFeatures =
       QString::fromStdString(theMessage->nestedFeatures()).split(" ", QString::SkipEmptyParts);
   QList<QAction*> aNestedActList;
index 3146a923c7689a119960e1027790039593b4e25a..f159dd4b5f4bc086dd509b611c3911148626e51b 100644 (file)
@@ -678,7 +678,7 @@ bool XGUI_OperationMgr::onKeyReleased(QObject *theObject, QKeyEvent* theEvent)
             aContext->HilightNextDetected(aView);
           else if ((theEvent->key() == Qt::Key_P))
             aContext->HilightPreviousDetected(aView);
-          //aViewer->updateHighlight();
+          aViewer->updateHighlight();
           isAccepted = true;
         }
       }
index 8b5ccaf65b408673ae09be020965f1dddbbdd80b..4138cc25cdc39eddadbbe8021d49755e7e715dbd 100644 (file)
@@ -207,7 +207,7 @@ void XGUI_PropertyPanel::updateContentWidget(FeaturePtr theFeature)
     eachWidget->restoreValue();
   }
   // the repaint is used here to immediately react in GUI to the values change.
-  repaint();
+  update();
 }
 
 void XGUI_PropertyPanel::createContentPanel(FeaturePtr theFeature)
index 62433d9f380451aef343020b9b7ee09017f3fa8b..10b1d84e5711f80688e74293a18063176e00669a 100644 (file)
@@ -549,14 +549,16 @@ void XGUI_SelectionActivate::deactivateTrihedron(const bool theUpdateViewer) con
 void XGUI_SelectionActivate::deactivateTrihedronInSelectionModes()
 {
   Handle(AIS_InteractiveContext) aContext = AISContext();
-  Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(getTrihedron());
-  /// deactivate trihedron in selection modes
-  TColStd_ListOfInteger aTColModes;
-  aContext->ActivatedModes(aTrihedron, aTColModes);
-  TColStd_ListIteratorOfListOfInteger itr( aTColModes );
-  for (; itr.More(); itr.Next() ) {
-    Standard_Integer aMode = itr.Value();
-    aContext->Deactivate(aTrihedron, aMode);
+  if (!aContext.IsNull()) {
+    Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(getTrihedron());
+    /// deactivate trihedron in selection modes
+    TColStd_ListOfInteger aTColModes;
+    aContext->ActivatedModes(aTrihedron, aTColModes);
+    TColStd_ListIteratorOfListOfInteger itr(aTColModes);
+    for (; itr.More(); itr.Next()) {
+      Standard_Integer aMode = itr.Value();
+      aContext->Deactivate(aTrihedron, aMode);
+    }
   }
 }
 
index 0523975fffdf12e70b31c72fc608c725eb6c8fa2..fbff53c41f2180237f277379746c294925d51237 100644 (file)
@@ -486,16 +486,18 @@ void XGUI_ViewerProxy::displayHighlight(FeaturePtr theFeature, const TopoDS_Shap
   }
 }
 
-void XGUI_ViewerProxy::eraseHighlight()
+bool XGUI_ViewerProxy::eraseHighlight()
 {
   Handle(AIS_InteractiveContext) aContext = AISContext();
   Handle(AIS_InteractiveObject) anAISIO;
   AIS_ListIteratorOfListOfInteractive aLIt;
+  bool isErased = myHighlights.Extent() > 0;
   for (aLIt.Initialize(myHighlights); aLIt.More(); aLIt.Next()) {
     anAISIO = aLIt.Value();
     aContext->Remove(anAISIO, false);
   }
   myHighlights.Clear();
+  return isErased;
 }
 
 void XGUI_ViewerProxy::updateHighlight()
@@ -525,14 +527,15 @@ void XGUI_ViewerProxy::updateHighlight()
           else {
             myResult = ResultPtr();
           }
-          aContext->UpdateCurrentViewer();
+          update();
         }
         isDisplayed = aRes.get();
       }
     }
     if (!isDisplayed) {
-      eraseHighlight();
-      aContext->UpdateCurrentViewer();
+      if (eraseHighlight()) {
+        update();
+      }
       myResult = ResultPtr();
     }
   }
@@ -723,4 +726,27 @@ void XGUI_ViewerProxy::setupColorScale()
 //      aView3d->DepthFitAll();
 //  }
 //#endif
-//}
\ No newline at end of file
+//}
+
+
+#ifdef HAVE_SALOME
+void XGUI_ViewerProxy::setFitter(OCCViewer_Fitter* theFitter)
+{
+  myWorkshop->salomeConnector()->viewer()->setFitter(theFitter);
+}
+
+OCCViewer_Fitter* XGUI_ViewerProxy::fitter() const
+{
+  return myWorkshop->salomeConnector()->viewer()->fitter();
+}
+#else
+void XGUI_ViewerProxy::setFitter(AppElements_Fitter* theFitter)
+{
+  myWorkshop->mainWindow()->viewer()->setFitter(theFitter);
+}
+
+AppElements_Fitter* XGUI_ViewerProxy::fitter() const
+{
+  return myWorkshop->mainWindow()->viewer()->fitter();
+}
+#endif
index bb3a445d5ddc6f6fa97a81e6232221c8bcc3bc35..19e23ac3bff3a7d737d150fc29f7a158adb3338d 100644 (file)
 #include <AIS_Trihedron.hxx>
 #include <AIS_ListOfInteractive.hxx>
 
-#ifndef HAVE_SALOME
+#ifdef HAVE_SALOME
+#include <OCCViewer_ViewModel.h>
+#else
+  #include <AppElements_Viewer.h>
   #include <AppElements_ViewWindow.h>
 #endif
 
+
+
 class XGUI_Workshop;
 /**
  * \ingroup GUI
@@ -164,6 +169,14 @@ Q_OBJECT
   // Fit all along Z (perpendicular to display)
   //virtual void Zfitall();
 
+#ifdef HAVE_SALOME
+  virtual void setFitter(OCCViewer_Fitter* theFitter);
+  virtual OCCViewer_Fitter* fitter() const;
+#else
+  virtual void setFitter(AppElements_Fitter* theFitter);
+  virtual AppElements_Fitter* fitter() const;
+#endif
+
 signals:
   /// Emits by mouse entering the view port
   void enterViewPort();
@@ -203,7 +216,7 @@ private slots:
 
  private:
    void displayHighlight(FeaturePtr theFeature, const TopoDS_Shape& theIgnoreShape);
-   void eraseHighlight();
+   bool eraseHighlight();
 
 
   XGUI_Workshop* myWorkshop;
index df5c48cb13c153a11760d59bac5b59329ef848f6..2c6787a1972f3032076019be00cc33d7fca060c8 100644 (file)
@@ -219,11 +219,16 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
 
   // Load translations
   QStringList aLangs;
-  aLangs << "*_en.ts"; // load by default eng translations
+#ifdef MAKE_TRANSLATION
   QString aCurrLang = aResMgr->stringValue("language", "language", "en");
-  if(aCurrLang != "en") {
+  if(aCurrLang == "en") {
+    aLangs << "*_en.ts";
+  } else {
     aLangs << "*_" + aCurrLang + ".ts"; // then replace with translated files
   }
+#else
+  aLangs << "*_en.ts"; // load by default eng translations
+#endif
 
   foreach(QString aLang, aLangs) {
     QStringList aFilters;
@@ -268,7 +273,7 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
 
 #ifndef HAVE_SALOME
   connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
-  onTrihedronVisibilityChanged(true);
+  myDisplayer->displayTrihedron(true);
 #endif
 
   connect(myEventsListener, SIGNAL(errorOccurred(std::shared_ptr<Events_InfoMessage>)),
@@ -752,12 +757,13 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation)
   myModule->propertyPanelDefined(theOperation);
 
 #ifndef DEBUG_FEATURE_NAME
-  myPropertyPanel->setWindowTitle(theOperation->getDescription()->description());
+  myPropertyPanel->setWindowTitle(ModuleBase_Tools::translate("workshop",
+    theOperation->getDescription()->description().toStdString()));
 #else
   std::string aFeatureName = aFeature->name();
   myPropertyPanel->setWindowTitle(QString("%1: %2")
-    .arg(theOperation->getDescription()->description())
-    .arg(aFeatureName.c_str()));
+    .arg(translate(theOperation->getDescription()->description()))
+    .arg(translate(aFeatureName.c_str())));
 #endif
 
   myErrorMgr->setPropertyPanel(myPropertyPanel);
@@ -1069,8 +1075,10 @@ void XGUI_Workshop::onPreferences()
 void XGUI_Workshop::onTrihedronVisibilityChanged(bool theState)
 {
   XGUI_Displayer* aDisplayer = displayer();
-  if (aDisplayer)
+  if (aDisplayer) {
     aDisplayer->displayTrihedron(theState);
+    aDisplayer->updateViewer();
+  }
 }
 
 //******************************************************
@@ -1237,6 +1245,7 @@ void XGUI_Workshop::onValuesChanged()
 void XGUI_Workshop::onWidgetObjectUpdated()
 {
   operationMgr()->onValidateOperation();
+  myDisplayer->updateViewer();
 }
 
 //******************************************************
@@ -1812,6 +1821,19 @@ void XGUI_Workshop::deleteObjects()
   if (!(hasResult || hasFeature || hasParameter || hasFolder))
     return;
 
+  // Remove from the list non-deletable objects: infinite constuctions which are not in history
+  bool notDelete = true;
+  QObjectPtrList::iterator aIt;
+  for (aIt = anObjects.begin(); aIt != anObjects.end(); aIt++) {
+    ObjectPtr aObj = (*aIt);
+    ResultConstructionPtr aConstr = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aObj);
+    FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
+    notDelete = (!aFeature->isInHistory()) && aConstr->isInfinite();
+    if (notDelete) {
+      anObjects.removeAll(aObj);
+      aIt--;
+    }
+  }
   // delete objects
   std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
   std::set<FeaturePtr> aFeatures;
@@ -1867,6 +1889,8 @@ void XGUI_Workshop::deleteObjects()
     operationMgr()->commitOperation();
   else
     operationMgr()->abortOperation(operationMgr()->currentOperation());
+
+  myDisplayer->updateViewer();
 }
 
 //**************************************************************
@@ -1960,7 +1984,8 @@ void XGUI_Workshop::cleanHistory()
     QString anUnusedNames = aNames.join(", ");
 
     QString anActionId = "CLEAN_HISTORY_CMD";
-    QString aDescription = contextMenuMgr()->action(anActionId)->text();
+    QString aDescription = ModuleBase_Tools::translate("workshop",
+        contextMenuMgr()->action(anActionId)->text().toStdString());
 
     QMessageBox aMessageBox(desktop());
     aMessageBox.setWindowTitle(aDescription);
@@ -2017,6 +2042,10 @@ void XGUI_Workshop::cleanHistory()
 }
 
 //**************************************************************
+bool compareFeature(const FeaturePtr& theF1, const FeaturePtr& theF2) {
+  DocumentPtr aDoc = theF1->document();
+  return aDoc->index(theF1) < aDoc->index(theF2);
+}
 void XGUI_Workshop::moveObjects()
 {
   if (!abortAllOperations())
@@ -2024,10 +2053,6 @@ void XGUI_Workshop::moveObjects()
 
   SessionPtr aMgr = ModelAPI_Session::get();
 
-  QString anActionId = "MOVE_CMD";
-  QString aDescription = contextMenuMgr()->action(anActionId)->text();
-  aMgr->startOperation(aDescription.toStdString());
-
   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
   // It is necessary to clear selection in order to avoid selection changed event during
   // moving and negative consequences connected with processing of already moved items
@@ -2038,9 +2063,17 @@ void XGUI_Workshop::moveObjects()
   if (!XGUI_Tools::canRemoveOrRename(desktop(), aFeatures))
     return;
 
+  QString anActionId = "MOVE_CMD";
+  QString aDescription = contextMenuMgr()->action(anActionId)->text();
+  aMgr->startOperation(aDescription.toStdString());
+
+  // Sort features by index in document
+  std::list<FeaturePtr> aFList(aFeatures.begin(), aFeatures.end());
+  aFList.sort(compareFeature);
+
   DocumentPtr anActiveDocument = aMgr->activeDocument();
   FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true);
-  std::set<FeaturePtr>::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end();
+  std::list<FeaturePtr>::const_iterator anIt = aFList.begin(), aLast = aFList.end();
   for (; anIt != aLast; anIt++) {
     FeaturePtr aFeature = *anIt;
     if (!aFeature.get() || !myModule->canApplyAction(aFeature, anActionId))
@@ -2050,6 +2083,7 @@ void XGUI_Workshop::moveObjects()
     aCurrentFeature = anActiveDocument->currentFeature(true);
   }
   aMgr->finishOperation();
+  updateCommandStatus();
 }
 
 //**************************************************************
@@ -2454,7 +2488,7 @@ void XGUI_Workshop::changeTransparency(const QObjectPtrList& theObjects)
 
   // 2. show the dialog to change the value
   XGUI_PropertyDialog* aDlg = new XGUI_PropertyDialog(desktop());
-  aDlg->setWindowTitle("Transparency");
+  aDlg->setWindowTitle(tr("Transparency"));
   XGUI_TransparencyWidget* aTransparencyWidget = new XGUI_TransparencyWidget(aDlg);
   connect(aTransparencyWidget, SIGNAL(transparencyValueChanged()),
           this, SLOT(onTransparencyValueChanged()));
index 6de634520b08b91152bd49a87a3373bf3ac2ceec..e420a5aec4814eb9666bf2eb4eb07e7780967bf5 100644 (file)
@@ -358,7 +358,9 @@ void XGUI_WorkshopListener::
   if (aRedisplayed || isCustomized) {
     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_EMPTY_AIS_PRESENTATION));
 
-    aDisplayer->updateViewer();
+    // Do not update viewer here because it can be called in a loop
+    // In this case Update has to be called after redisplay event
+    //aDisplayer->updateViewer();
   }
 }
 
index 3f0661c06764b8fdfe48ca85b1ac680192a516c2..f01fbe61fa5a9d15beda81bfb4b895e2acff52de 100644 (file)
@@ -6,47 +6,47 @@
     <message>
         <location filename="XGUI_Tools.cpp" line="154"/>
         <source>Warning</source>
-        <translation type="unfinished"></translation>
+        <translation>Attention</translation>
     </message>
     <message>
         <location filename="XGUI_Tools.cpp" line="213"/>
         <source>Name %2 already exists in %1.</source>
-        <translation type="unfinished"></translation>
+        <translation>Le nom %2 existe déjà dans %1.</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="170"/>
         <source>Move to the end</source>
-        <translation type="unfinished"></translation>
+        <translation>Aller à la fin</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="177"/>
         <source>SHAPER files (*.shaper *.cadbld)</source>
-        <translation type="unfinished"></translation>
+        <translation>Fichiers SHAPER (*.shaper *.cadbld)</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="178"/>
         <source>SHAPER files (*.shaper)</source>
-        <translation type="unfinished"></translation>
+        <translation>Fichiers SHAPER (*.shaper)</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="181"/>
         <source>CAD Builder files (*.cadbld);;All files (*.*)</source>
-        <translation type="unfinished"></translation>
+        <translation>Fichiers CAD Builder (*.cadbld);;Tous les fichiers (*. *)</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="182"/>
         <source>CAD Builder files (*.cadbld)</source>
-        <translation type="unfinished"></translation>
+        <translation>Fichiers CAD Builder (*.cadbld)</translation>
     </message>
     <message>
         <location filename="XGUI_OperationMgr.cpp" line="893"/>
         <source>Abort operation</source>
-        <translation type="unfinished"></translation>
+        <translation>Abandonner l&apos;opération</translation>
     </message>
     <message>
         <location filename="XGUI_OperationMgr.cpp" line="904"/>
         <source>Validate operation</source>
-        <translation type="unfinished"></translation>
+        <translation>Valider l&apos;opération</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_ActionsMgr.cpp" line="194"/>
         <source>Shortcut %1 is already defined. Ignore.</source>
-        <translation type="unfinished"></translation>
+        <translation>Le raccourci %1 est déjà défini. Ignorer.</translation>
+    </message>
+    <message>
+        <location filename="XGUI_ActionsMgr.cpp" line="254"/>
+        <source>Apply</source>
+        <translation>Appliquer</translation>
+    </message>
+    <message>
+        <location filename="XGUI_ActionsMgr.cpp" line="259"/>
+        <source>Apply and continue</source>
+        <translation>Appliquer et continuer</translation>
+    </message>
+    <message>
+        <location filename="XGUI_ActionsMgr.cpp" line="264"/>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <location filename="XGUI_ActionsMgr.cpp" line="269"/>
+        <source>Help</source>
+        <translation>Aide</translation>
     </message>
     <message>
         <location filename="XGUI_ActionsMgr.cpp" line="274"/>
         <source>See preview</source>
-        <translation type="unfinished"></translation>
+        <translation>Voir l&apos;aperçu</translation>
+    </message>
+    <message>
+        <location filename="XGUI_ActionsMgr.cpp" line="275"/>
+        <source>Compute preview</source>
+        <translation>Calculer l&apos;aperçu avant impression</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_ColorDialog.cpp" line="35"/>
         <source>Color</source>
-        <translation type="unfinished"></translation>
+        <translation>Couleur</translation>
     </message>
     <message>
         <location filename="XGUI_ColorDialog.cpp" line="53"/>
         <source>Random</source>
-        <translation type="unfinished"></translation>
+        <translation>Aléatoire</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="88"/>
         <source>Delete</source>
-        <translation type="unfinished"></translation>
+        <translation>Effacer</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="95"/>
         <source>Rename</source>
-        <translation type="unfinished"></translation>
+        <translation>Renommer</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="104"/>
         <source>Clean history</source>
-        <translation type="unfinished"></translation>
+        <translation>Vider l’historique</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="107"/>
         <source>Color...</source>
-        <translation type="unfinished"></translation>
+        <translation>Couleur...</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="110"/>
         <source>Deflection...</source>
-        <translation type="unfinished"></translation>
+        <translation>Déviation...</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="114"/>
         <source>Transparency...</source>
-        <translation type="unfinished"></translation>
+        <translation>Transparence...</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="117"/>
         <source>Show</source>
-        <translation type="unfinished"></translation>
+        <translation>Afficher</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="120"/>
         <source>Show only</source>
-        <translation type="unfinished"></translation>
+        <translation>Montrer seulement</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="124"/>
         <source>Hide</source>
-        <translation type="unfinished"></translation>
+        <translation>Cacher</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="128"/>
         <source>Hide all</source>
-        <translation type="unfinished"></translation>
+        <translation>Cacher tout</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="132"/>
         <source>Shading</source>
-        <translation type="unfinished"></translation>
+        <translation>Ombrage</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="135"/>
         <source>Wireframe</source>
-        <translation type="unfinished"></translation>
+        <translation>Fil de fer</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="148"/>
         <source>Vertices</source>
-        <translation type="unfinished"></translation>
+        <translation>Sommets</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="153"/>
         <source>Edges</source>
-        <translation type="unfinished"></translation>
+        <translation>Arêtes</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="158"/>
         <source>Faces</source>
-        <translation type="unfinished"></translation>
+        <translation>Faces</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="163"/>
         <source>Results</source>
-        <translation type="unfinished"></translation>
+        <translation>Résultats</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="171"/>
         <source>Select results</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionnez les résultats</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="175"/>
         <source>Select parent feature</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner une entité parente</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="179"/>
         <source>TInspector</source>
-        <translation type="unfinished"></translation>
+        <translation>TInspector</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="185"/>
         <source>Insert a folder before</source>
-        <translation type="unfinished"></translation>
+        <translation>Insérer un dossier avant</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="189"/>
         <source>Move into the previous folder</source>
-        <translation type="unfinished"></translation>
+        <translation>Déplacer dans le dossier précédent</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="193"/>
         <source>Move into the next folder</source>
-        <translation type="unfinished"></translation>
+        <translation>Se déplacer dans le dossier suivant</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="197"/>
         <source>Move out before the folder</source>
-        <translation type="unfinished"></translation>
+        <translation>Sortir avant le dossier</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="201"/>
         <source>Move out after the folder</source>
-        <translation type="unfinished"></translation>
+        <translation>Sortir après le dossier</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="205"/>
         <source>Set view by inverted normal to face</source>
-        <translation type="unfinished"></translation>
+        <translation>Définir la vue par normale inversée à la face</translation>
     </message>
     <message>
         <location filename="XGUI_ContextMenuMgr.cpp" line="209"/>
         <source>Set view by normal to face</source>
-        <translation type="unfinished"></translation>
+        <translation>Définir la vue par la normale à la face</translation>
     </message>
     <message>
-        <location filename="XGUI_ContextMenuMgr.cpp" line="811"/>
+        <location filename="XGUI_ContextMenuMgr.cpp" line="806"/>
         <source>Selection mode</source>
-        <translation type="unfinished"></translation>
+        <translation>Mode de sélection</translation>
     </message>
     <message>
-        <location filename="XGUI_ContextMenuMgr.cpp" line="864"/>
+        <location filename="XGUI_ContextMenuMgr.cpp" line="859"/>
         <source>Windows</source>
-        <translation type="unfinished"></translation>
+        <translation>Fenêtres</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_ObjectsBrowser.cpp" line="203"/>
         <source>History change</source>
-        <translation type="unfinished"></translation>
+        <translation>Changement l&apos;historique</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_DeflectionDialog.cpp" line="35"/>
         <source>Deflection</source>
-        <translation type="unfinished"></translation>
+        <translation>Déviation</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_ErrorDialog.cpp" line="37"/>
         <source>Application errors</source>
-        <translation type="unfinished"></translation>
+        <translation>Erreurs d&apos;application</translation>
+    </message>
+</context>
+<context>
+    <name>XGUI_ErrorMgr</name>
+    <message>
+        <location filename="XGUI_ErrorMgr.cpp" line="204"/>
+        <location filename="XGUI_ErrorMgr.cpp" line="209"/>
+        <source>Errors:</source>
+        <translation>Erreurs:</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_FacesPanel.cpp" line="54"/>
         <source>Hide Faces</source>
-        <translation type="unfinished"></translation>
+        <translation>Masquer les faces</translation>
     </message>
     <message>
         <location filename="XGUI_FacesPanel.cpp" line="63"/>
         <source>Transparent</source>
-        <translation type="unfinished"></translation>
+        <translation>Transparent</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="115"/>
         <source>Inspection Panel</source>
-        <translation type="unfinished"></translation>
+        <translation>Panneau d&apos;inspection</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="125"/>
         <source>Object</source>
-        <translation type="unfinished"></translation>
+        <translation>Objet</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="137"/>
         <source>Sub-shapes</source>
-        <translation type="unfinished"></translation>
+        <translation>Sous-formes</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="137"/>
         <source>Number</source>
-        <translation type="unfinished"></translation>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="141"/>
+        <source>SHAPE</source>
+        <translation>FORME</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="141"/>
+        <source>COMPOUND</source>
+        <translation>ASSEMBLAGE</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="141"/>
+        <source>COMPSOLID</source>
+        <translation>COMPSOLIDE</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="142"/>
+        <source>SOLID</source>
+        <translation>SOLIDE</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="142"/>
+        <source>SHELL</source>
+        <translation>COQUE</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="142"/>
+        <source>FACE</source>
+        <translation>FACE</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="142"/>
+        <source>WIRE</source>
+        <translation>CONTOUR</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="142"/>
+        <source>EDGE</source>
+        <translation>BORD</translation>
+    </message>
+    <message>
+        <location filename="XGUI_InspectionPanel.cpp" line="142"/>
+        <source>VERTEX</source>
+        <translation>SOMMET</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="165"/>
         <source>Type:</source>
-        <translation type="unfinished"></translation>
+        <translation>Type:</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="340"/>
         <source>Vertex</source>
-        <translation type="unfinished"></translation>
+        <translation>Sommet</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="343"/>
         <source>Coordinates</source>
-        <translation type="unfinished"></translation>
+        <translation>Coordonnées</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="352"/>
         <source>Degenerated</source>
-        <translation type="unfinished"></translation>
+        <translation>Dégénéré</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="359"/>
         <source>Line segment</source>
-        <translation type="unfinished"></translation>
+        <translation>Segment de ligne</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="371"/>
         <location filename="XGUI_InspectionPanel.cpp" line="624"/>
         <location filename="XGUI_InspectionPanel.cpp" line="662"/>
         <source>Center</source>
-        <translation type="unfinished"></translation>
+        <translation>Centre</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="372"/>
         <location filename="XGUI_InspectionPanel.cpp" line="458"/>
         <location filename="XGUI_InspectionPanel.cpp" line="615"/>
         <source>Normal</source>
-        <translation type="unfinished"></translation>
+        <translation>Normale</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="373"/>
         <location filename="XGUI_InspectionPanel.cpp" line="676"/>
         <location filename="XGUI_InspectionPanel.cpp" line="692"/>
         <source>Dimensions</source>
-        <translation type="unfinished"></translation>
+        <translation>Dimensions</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="374"/>
         <location filename="XGUI_InspectionPanel.cpp" line="626"/>
         <location filename="XGUI_InspectionPanel.cpp" line="638"/>
         <source>Radius</source>
-        <translation type="unfinished"></translation>
+        <translation>Rayon</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="388"/>
         <location filename="XGUI_InspectionPanel.cpp" line="665"/>
         <source>Major radius</source>
-        <translation type="unfinished"></translation>
+        <translation>Rayon majeur</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="389"/>
         <location filename="XGUI_InspectionPanel.cpp" line="666"/>
         <source>Minor radius</source>
-        <translation type="unfinished"></translation>
+        <translation>Rayon mineur</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="393"/>
         <source>Edge</source>
-        <translation type="unfinished"></translation>
+        <translation>Bord</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="398"/>
         <source>Start point</source>
-        <translation type="unfinished"></translation>
+        <translation>Point de départ</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="399"/>
         <source>End point</source>
-        <translation type="unfinished"></translation>
+        <translation>Point final</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="408"/>
         <source>Closed</source>
-        <translation type="unfinished"></translation>
+        <translation>Fermé</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="413"/>
         <source>Polygon</source>
-        <translation type="unfinished"></translation>
+        <translation>Polygone</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="417"/>
         <source>Point</source>
-        <translation type="unfinished"></translation>
+        <translation>Point</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="421"/>
         <source>Wire</source>
-        <translation type="unfinished"></translation>
+        <translation>Contour</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="456"/>
         <source>Rectangle</source>
-        <translation type="unfinished"></translation>
+        <translation>Rectangle</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="457"/>
         <source>Corner</source>
-        <translation type="unfinished"></translation>
+        <translation>Coin</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="460"/>
         <location filename="XGUI_InspectionPanel.cpp" line="677"/>
         <location filename="XGUI_InspectionPanel.cpp" line="693"/>
         <source>Width</source>
-        <translation type="unfinished"></translation>
+        <translation>Largeur</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="461"/>
         <location filename="XGUI_InspectionPanel.cpp" line="679"/>
         <location filename="XGUI_InspectionPanel.cpp" line="695"/>
         <source>Height</source>
-        <translation type="unfinished"></translation>
+        <translation>Hauteur</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="470"/>
         <source>Plane</source>
-        <translation type="unfinished"></translation>
+        <translation>Plan</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="476"/>
         <location filename="XGUI_InspectionPanel.cpp" line="507"/>
         <location filename="XGUI_InspectionPanel.cpp" line="547"/>
         <source>Sphere</source>
-        <translation type="unfinished"></translation>
+        <translation>Sphère</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="481"/>
         <location filename="XGUI_InspectionPanel.cpp" line="512"/>
         <location filename="XGUI_InspectionPanel.cpp" line="552"/>
         <source>Cylinder</source>
-        <translation type="unfinished"></translation>
+        <translation>Cylindre</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="486"/>
         <location filename="XGUI_InspectionPanel.cpp" line="517"/>
         <location filename="XGUI_InspectionPanel.cpp" line="557"/>
         <source>Cone</source>
-        <translation type="unfinished"></translation>
+        <translation>Cône</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="491"/>
         <location filename="XGUI_InspectionPanel.cpp" line="522"/>
         <location filename="XGUI_InspectionPanel.cpp" line="562"/>
         <source>Torus</source>
-        <translation type="unfinished"></translation>
+        <translation>Tore</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="494"/>
         <source>Face</source>
-        <translation type="unfinished"></translation>
+        <translation>Face</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="528"/>
         <location filename="XGUI_InspectionPanel.cpp" line="568"/>
         <source>Box</source>
-        <translation type="unfinished"></translation>
+        <translation>Boîte</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="530"/>
         <location filename="XGUI_InspectionPanel.cpp" line="570"/>
         <source>Rotated Box</source>
-        <translation type="unfinished"></translation>
+        <translation>Boîte tournée</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="534"/>
         <source>Shell</source>
-        <translation type="unfinished"></translation>
+        <translation>Coque</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="574"/>
         <source>Solid</source>
-        <translation type="unfinished"></translation>
+        <translation>Solide</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="604"/>
         <source>Bounding box</source>
-        <translation type="unfinished"></translation>
+        <translation>Boîte englobante</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="605"/>
         <source>Minimal corner</source>
-        <translation type="unfinished"></translation>
+        <translation>Coin minimal</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="606"/>
         <source>Maximal corner</source>
-        <translation type="unfinished"></translation>
+        <translation>Coin maximal</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="614"/>
         <source>Origin</source>
-        <translation type="unfinished"></translation>
+        <translation>Origine</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="635"/>
         <location filename="XGUI_InspectionPanel.cpp" line="675"/>
         <location filename="XGUI_InspectionPanel.cpp" line="689"/>
         <source>Position</source>
-        <translation type="unfinished"></translation>
+        <translation>Position</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="636"/>
         <location filename="XGUI_InspectionPanel.cpp" line="649"/>
         <location filename="XGUI_InspectionPanel.cpp" line="663"/>
         <source>Axis</source>
-        <translation type="unfinished"></translation>
+        <translation>Axe</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="651"/>
         <source>Radius 1</source>
-        <translation type="unfinished"></translation>
+        <translation>Rayon 1</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="652"/>
         <source>Radius 2</source>
-        <translation type="unfinished"></translation>
+        <translation>Rayon 2</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="678"/>
         <location filename="XGUI_InspectionPanel.cpp" line="694"/>
         <source>Depth</source>
-        <translation type="unfinished"></translation>
+        <translation>Profondeur</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="690"/>
         <source>Z axis</source>
-        <translation type="unfinished"></translation>
+        <translation>Axe Z</translation>
     </message>
     <message>
         <location filename="XGUI_InspectionPanel.cpp" line="691"/>
         <source>X axis</source>
-        <translation type="unfinished"></translation>
+        <translation>Axe X</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_ObjectsBrowser.cpp" line="396"/>
         <source>Part set</source>
-        <translation type="unfinished"></translation>
+        <translation>Ensemble</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_OperationMgr.cpp" line="254"/>
         <source>All active operations will be aborted.</source>
-        <translation type="unfinished"></translation>
+        <translation>Toutes les opérations actives seront annulées.</translation>
     </message>
     <message>
         <location filename="XGUI_OperationMgr.cpp" line="259"/>
         <source>Please validate all your active operations before saving.</source>
-        <translation type="unfinished"></translation>
+        <translation>Veuillez valider toutes vos opérations actives avant de sauvegarder.</translation>
     </message>
     <message>
         <location filename="XGUI_OperationMgr.cpp" line="341"/>
         <source>%1 operation will be aborted.</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 opération sera abandonnée.</translation>
     </message>
     <message>
         <location filename="XGUI_OperationMgr.cpp" line="348"/>
         <source>Please validate your %1 before saving.</source>
-        <translation type="unfinished"></translation>
+        <translation>Veuillez valider votre %1 avant de sauvegarder.</translation>
     </message>
 </context>
 <context>
         <location filename="XGUI_PropertyPanel.cpp" line="73"/>
         <location filename="XGUI_PropertyPanel.cpp" line="167"/>
         <source>Property Panel</source>
-        <translation type="unfinished"></translation>
+        <translation>Panneau de propriété</translation>
     </message>
 </context>
 <context>
     <message>
         <location filename="XGUI_TransparencyWidget.cpp" line="39"/>
         <source>Opaque</source>
-        <translation type="unfinished"></translation>
+        <translation>Opaque</translation>
     </message>
     <message>
         <location filename="XGUI_TransparencyWidget.cpp" line="45"/>
         <source>Transparent</source>
-        <translation type="unfinished"></translation>
+        <translation>Transparent</translation>
     </message>
 </context>
 <context>
         <location filename="XGUI_Workshop.cpp" line="427"/>
         <location filename="XGUI_Workshop.cpp" line="489"/>
         <source>Undo</source>
-        <translation type="unfinished"></translation>
+        <translation>Annuler</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="428"/>
         <location filename="XGUI_Workshop.cpp" line="489"/>
         <source>Undo last command</source>
-        <translation type="unfinished"></translation>
+        <translation>Annuler la dernière commande</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="432"/>
         <source>INF_DESK_TOOLBAR_STANDARD</source>
-        <translation type="unfinished"></translation>
+        <translation>AA</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="438"/>
         <location filename="XGUI_Workshop.cpp" line="498"/>
         <source>Redo</source>
-        <translation type="unfinished"></translation>
+        <translation>Refaire</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="438"/>
         <location filename="XGUI_Workshop.cpp" line="498"/>
         <source>Redo last command</source>
-        <translation type="unfinished"></translation>
+        <translation>Refaire la dernière commande</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="460"/>
         <source>Export native...</source>
-        <translation type="unfinished"></translation>
+        <translation>Exporter natif...</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="461"/>
         <source>Export the current document into a native file</source>
-        <translation type="unfinished"></translation>
+        <translation>Exporter le document actuel dans un fichier natif</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="466"/>
         <source>Import native...</source>
-        <translation type="unfinished"></translation>
+        <translation>Importer natif...</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="467"/>
         <source>Import native file</source>
-        <translation type="unfinished"></translation>
+        <translation>Importer un fichier natif</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="479"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="479"/>
         <source>Save the document</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer le document</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="484"/>
         <source>Save as...</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer sous...</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="484"/>
         <source>Save the document into a file</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer le document dans un fichier</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="506"/>
         <source>Open...</source>
-        <translation type="unfinished"></translation>
+        <translation>Ouvrir...</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="506"/>
         <source>Open a new document</source>
-        <translation type="unfinished"></translation>
+        <translation>Ouvrir un nouveau document</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="511"/>
         <source>Auto rebuild</source>
-        <translation type="unfinished"></translation>
+        <translation>Reconstruction automatique</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="512"/>
         <source>Blocks immediate apply of modifications</source>
-        <translation type="unfinished"></translation>
+        <translation>Bloque l&apos;application immédiate des modifications</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="517"/>
         <source>Preferences</source>
-        <translation type="unfinished"></translation>
+        <translation>Préférences</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="517"/>
         <source>Edit preferences</source>
-        <translation type="unfinished"></translation>
+        <translation>Modifier les préférences</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="521"/>
         <source>Exit</source>
-        <translation type="unfinished"></translation>
+        <translation>Quitter</translation>
     </message>
     <message>
         <location filename="XGUI_Workshop.cpp" line="521"/>
         <source>Exit application</source>
-        <translation type="unfinished"></translation>
+        <translation>Quitter l’application</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="930"/>
-        <location filename="XGUI_Workshop.cpp" line="1029"/>
+        <location filename="XGUI_Workshop.cpp" line="931"/>
+        <location filename="XGUI_Workshop.cpp" line="1034"/>
         <source>Save current file</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer le fichier courant</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="931"/>
+        <location filename="XGUI_Workshop.cpp" line="932"/>
         <source>The document is modified, save before opening another?</source>
-        <translation type="unfinished"></translation>
+        <translation>Le document est modifié, sauvegarder avant d&apos;en ouvrir un autre ?</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="942"/>
+        <location filename="XGUI_Workshop.cpp" line="946"/>
         <source>Open file</source>
-        <translation type="unfinished"></translation>
+        <translation>Fichier ouvert</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="1109"/>
+        <location filename="XGUI_Workshop.cpp" line="1117"/>
         <source>Select name to save file...</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionnez le nom pour enregistrer le fichier...</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="1772"/>
+        <location filename="XGUI_Workshop.cpp" line="1782"/>
         <source>Show object</source>
-        <translation type="unfinished"></translation>
+        <translation>Montrer l&apos;objet</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="1773"/>
+        <location filename="XGUI_Workshop.cpp" line="1783"/>
         <source>&apos;%1&apos;
  are hidden by %2:
 Remove objects from the panel to be displayed?</source>
-        <translation type="unfinished"></translation>
+        <translation>&apos;%1&apos;
+ est caché par %2 :
+Supprimer des objets du panneau à afficher ?</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="956"/>
+        <location filename="XGUI_Workshop.cpp" line="961"/>
         <source>Warning</source>
-        <translation type="unfinished"></translation>
+        <translation>Attention</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="956"/>
+        <location filename="XGUI_Workshop.cpp" line="961"/>
         <source>Unable to open the file.</source>
-        <translation type="unfinished"></translation>
+        <translation>Impossible d&apos;ouvrir le fichier.</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="1029"/>
+        <location filename="XGUI_Workshop.cpp" line="1034"/>
         <source>The document is modified, save before exit?</source>
-        <translation type="unfinished"></translation>
+        <translation>Le document est modifié, enregistrer avant de quitter ?</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="1241"/>
+        <location filename="XGUI_Workshop.cpp" line="1251"/>
         <source>Information about module &quot;%1&quot; doesn&apos;t exist.</source>
-        <translation type="unfinished"></translation>
+        <translation>Les informations sur le module &quot;%1&quot; n&apos;existent pas.</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="1402"/>
+        <location filename="XGUI_Workshop.cpp" line="1412"/>
         <source>Object browser</source>
-        <translation type="unfinished"></translation>
+        <translation>Navigateur d&apos;objet</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="2005"/>
+        <location filename="XGUI_Workshop.cpp" line="2031"/>
         <source>All features are relevant, there is nothing to be deleted</source>
-        <translation type="unfinished"></translation>
+        <translation>Toutes les fonctionnalités sont pertinentes, il n&apos;y a rien à supprimer</translation>
+    </message>
+    <message>
+        <location filename="XGUI_Workshop.cpp" line="2486"/>
+        <source>Transparency</source>
+        <translation>Transparence</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="2827"/>
+        <location filename="XGUI_Workshop.cpp" line="2866"/>
         <source>Find results</source>
-        <translation type="unfinished"></translation>
+        <translation>Trouver des résultats</translation>
     </message>
     <message>
-        <location filename="XGUI_Workshop.cpp" line="2828"/>
+        <location filename="XGUI_Workshop.cpp" line="2867"/>
         <source>Results not found</source>
-        <translation type="unfinished"></translation>
+        <translation>Résultats non trouvés</translation>
     </message>
 </context>
 </TS>
diff --git a/test.models/stair_with_cycle.py b/test.models/stair_with_cycle.py
new file mode 100644 (file)
index 0000000..d0d676e
--- /dev/null
@@ -0,0 +1,89 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+h_marche=18
+model.addParameter(Part_1_doc, "h_marche", str(h_marche))
+model.addParameter(Part_1_doc, "angle", "35")
+nb_marches=25
+h_totale=nb_marches*(h_marche+1)
+
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(13.86513942972648, 15.13114452817127, 113.484609238901, 23.84671880293715)
+SketchLine_2 = Sketch_1.addLine(124.230417176185, 14, 124.230417176185, 0)
+SketchLine_3 = Sketch_1.addLine(model.selection("EDGE", "PartSet/OX"))
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.result())
+SketchConstraintCoincidence_1.setName("SketchConstraintCoincidence_2")
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchArc_1 = Sketch_1.addArc(15.1889430421138, 0, 0, 0, 13.86513942972648, 15.13114452817127, True)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.result(), SketchArc_1.center())
+SketchConstraintCoincidence_2.setName("SketchConstraintCoincidence_3")
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.startPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_3.setName("SketchConstraintCoincidence_4")
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_1.endPoint())
+SketchConstraintCoincidence_4.setName("SketchConstraintCoincidence_5")
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchArc_1.results()[1])
+SketchArc_2 = Sketch_1.addArc(114.3460855070856, 14, 124.230417176185, 14, 113.484609238901, 23.84671880293715, False)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.startPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_5.setName("SketchConstraintCoincidence_6")
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_1.endPoint())
+SketchConstraintCoincidence_6.setName("SketchConstraintCoincidence_7")
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchLine_2.result())
+SketchConstraintTangent_3 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchLine_1.result())
+SketchConstraintMirror_1_objects = [SketchArc_1.results()[1], SketchLine_1.result(), SketchArc_2.results()[1], SketchLine_2.result()]
+SketchConstraintMirror_1 = Sketch_1.addMirror(SketchLine_3.result(), SketchConstraintMirror_1_objects)
+[SketchArc_3, SketchLine_4, SketchArc_4, SketchLine_5] = SketchConstraintMirror_1.mirrored()
+SketchConstraintAngle_1 = Sketch_1.setAngleBackward(SketchLine_1.result(), SketchLine_3.result(), 5)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 100)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 14)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_1_2f-SketchArc_3_2f-SketchLine_4f-SketchArc_4_2f-SketchLine_5f-SketchLine_2r-SketchArc_2_2f-SketchLine_1r")], model.selection(), 5, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_1"), True)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_2.addCircle(15.1889430421138, 0, 9.469961851384218)
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintCoincidence_7.setName("SketchConstraintCoincidence_8")
+model.do()
+# 1st step :
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_1_2f")], model.selection(), h_totale, 0)
+Axis_4 = model.addAxis(Part_1_doc, model.selection("FACE", "Extrusion_2_1/Generated_Face&Sketch_2/SketchCircle_1_2"))
+model.do()
+# Cycle : use previous step to get the next one, translated and rotated
+stairFeature = Extrusion_1
+# 15 steps now to fille the whole cylinder, but it may be changed
+for step in range(nb_marches):
+  Translation = model.addTranslation(Part_1_doc, [stairFeature.result()], model.selection("EDGE", "PartSet/OZ"), "h_marche")
+  Recover = model.addRecover(Part_1_doc, Translation, [stairFeature.result()])
+  Rotation = model.addRotation(Part_1_doc, [Translation.result()], model.selection("EDGE", "Axis_1"), "angle")
+  model.do() # next transaction
+  stairFeature = Rotation # store the next step feature to translate/rotate it in the next iteration
+
+#====================================================================================
+model.end()
+
+assert(Part_1_doc.size("Bodies") == nb_marches + 2)
+model.testResultsVolumes(stairFeature, [23382.6888388])
+
+assert(model.checkPythonDump())