]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge remote-tracking branch 'remotes/origin/master' into Dev_2.8.0
authorazv <azv@opencascade.com>
Thu, 21 Sep 2017 07:06:06 +0000 (10:06 +0300)
committerazv <azv@opencascade.com>
Thu, 21 Sep 2017 07:06:06 +0000 (10:06 +0300)
# Conflicts:
# CMakeCommon/FindTInspector.cmake
# env.sh
# src/GeomAPI/GeomAPI_Edge.cpp
# src/Model/Model_AttributeSelection.cpp
# src/ModelAPI/ModelAPI_Events.cpp
# src/PythonAPI/model/sketcher/tools.py
# src/SketchAPI/SketchAPI_Sketch.cpp
# src/SketchPlugin/CMakeLists.txt
# src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.cpp
# src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.h
# src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.cpp
# src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.h
# src/SketchPlugin/SketchPlugin_Ellipse.cpp
# src/SketchPlugin/SketchPlugin_Ellipse.h
# src/SketchPlugin/SketchPlugin_MacroEllipse.h
# src/SketchSolver/SketchSolver_ConstraintDistance.cpp
# src/SketchSolver/SketchSolver_ConstraintMovement.cpp
# src/SketchSolver/SketchSolver_Manager.cpp
# src/XGUI/XGUI_Workshop.cpp

223 files changed:
CMakeLists.txt
src/ConstructionAPI/ConstructionAPI_Point.cpp
src/ConstructionAPI/ConstructionAPI_Point.h
src/ConstructionPlugin/CMakeLists.txt
src/ConstructionPlugin/ConstructionPlugin_Plugin.cpp
src/ConstructionPlugin/ConstructionPlugin_Point.cpp
src/ConstructionPlugin/ConstructionPlugin_Point.h
src/ConstructionPlugin/ConstructionPlugin_Validators.cpp
src/ConstructionPlugin/ConstructionPlugin_Validators.h
src/ConstructionPlugin/Test/TestAxisCreation.py
src/ConstructionPlugin/Test/TestPoint.py [deleted file]
src/ConstructionPlugin/Test/TestPointName.py
src/ConstructionPlugin/Test/TestPoint_LineAndPlane.py [new file with mode: 0644]
src/ConstructionPlugin/Test/TestPoint_XYZ.py [new file with mode: 0644]
src/ConstructionPlugin/point_widget.xml
src/GeomAPI/CMakeLists.txt
src/GeomAPI/GeomAPI_Ax2.h
src/GeomAPI/GeomAPI_Ax3.h
src/GeomAPI/GeomAPI_Circ.cpp
src/GeomAPI/GeomAPI_Circ.h
src/GeomAPI/GeomAPI_Curve.h
src/GeomAPI/GeomAPI_Dir.h
src/GeomAPI/GeomAPI_Edge.cpp
src/GeomAPI/GeomAPI_Edge.h
src/GeomAPI/GeomAPI_Ellipse.cpp [new file with mode: 0644]
src/GeomAPI/GeomAPI_Ellipse.h [new file with mode: 0644]
src/GeomAPI/GeomAPI_Ellipse2d.cpp [new file with mode: 0644]
src/GeomAPI/GeomAPI_Ellipse2d.h [new file with mode: 0644]
src/GeomAPI/GeomAPI_Lin.h
src/GeomAPI/GeomAPI_Pln.cpp
src/GeomAPI/GeomAPI_Pln.h
src/GeomAPI/GeomAPI_Pnt.h
src/GeomAPI/GeomAPI_Pnt2d.h
src/GeomAPI/GeomAPI_Shape.cpp
src/GeomAPI/GeomAPI_Shape.h
src/GeomAPI/GeomAPI_Vertex.h
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/InitializationPlugin/InitializationPlugin_Plugin.cpp
src/Model/Model_AttributeSelection.cpp
src/Model/Model_AttributeSelection.h
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_AttributeSelection.h
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ModelAPI/Test/TestUndoRedo.py
src/ModelHighAPI/ModelHighAPI.i
src/ModelHighAPI/ModelHighAPI_RefAttr.cpp
src/ModelHighAPI/ModelHighAPI_RefAttr.h
src/ModuleBase/ModuleBase_WidgetEditor.cpp
src/ModuleBase/ModuleBase_WidgetEditor.h
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_CenterPrs.cpp [new file with mode: 0644]
src/PartSet/PartSet_CenterPrs.h [new file with mode: 0644]
src/PartSet/PartSet_ExternalPointsMgr.cpp [new file with mode: 0644]
src/PartSet/PartSet_ExternalPointsMgr.h [new file with mode: 0644]
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherMgr.h
src/PartSet/PartSet_Tools.cpp
src/PartSet/PartSet_Tools.h
src/PartSet/PartSet_WidgetPoint2d.cpp
src/PartSet/PartSet_WidgetSketchLabel.cpp
src/PartSet/PartSet_WidgetSketchLabel.h
src/PythonAPI/model/sketcher/__init__.py
src/PythonAPI/model/sketcher/tests.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/tools.py
src/SketchAPI/SketchAPI_Constraint.cpp
src/SketchAPI/SketchAPI_Projection.cpp
src/SketchAPI/SketchAPI_Projection.h
src/SketchAPI/SketchAPI_Rectangle.cpp
src/SketchAPI/SketchAPI_Rectangle.h
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Arc.cpp
src/SketchPlugin/SketchPlugin_Arc.h
src/SketchPlugin/SketchPlugin_Circle.cpp
src/SketchPlugin/SketchPlugin_Circle.h
src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp
src/SketchPlugin/SketchPlugin_ConstraintAngle.h
src/SketchPlugin/SketchPlugin_ConstraintBase.cpp
src/SketchPlugin/SketchPlugin_ConstraintBase.h
src/SketchPlugin/SketchPlugin_ConstraintCollinear.cpp
src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp
src/SketchPlugin/SketchPlugin_ConstraintDistance.h
src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintEqual.cpp
src/SketchPlugin/SketchPlugin_ConstraintHorizontal.cpp
src/SketchPlugin/SketchPlugin_ConstraintLength.cpp
src/SketchPlugin/SketchPlugin_ConstraintLength.h
src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp
src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp
src/SketchPlugin/SketchPlugin_ConstraintParallel.cpp
src/SketchPlugin/SketchPlugin_ConstraintPerpendicular.cpp
src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp
src/SketchPlugin/SketchPlugin_ConstraintRadius.h
src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp
src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp
src/SketchPlugin/SketchPlugin_ConstraintVertical.cpp
src/SketchPlugin/SketchPlugin_Ellipse.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Ellipse.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Feature.h
src/SketchPlugin/SketchPlugin_IntersectionPoint.cpp
src/SketchPlugin/SketchPlugin_IntersectionPoint.h
src/SketchPlugin/SketchPlugin_Line.cpp
src/SketchPlugin/SketchPlugin_Line.h
src/SketchPlugin/SketchPlugin_MacroArc.h
src/SketchPlugin/SketchPlugin_MacroCircle.h
src/SketchPlugin/SketchPlugin_MacroEllipse.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroEllipse.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MultiRotation.cpp
src/SketchPlugin/SketchPlugin_MultiTranslation.cpp
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_Split.h
src/SketchPlugin/SketchPlugin_Trim.h
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/Test/TestArcBehavior.py
src/SketchPlugin/Test/TestConstraintCoincidence.py
src/SketchPlugin/Test/TestConstraintDistance.py
src/SketchPlugin/Test/TestConstraintDistanceBehavior.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintDistanceHorizontal.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintDistanceVertical.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintFixed.py
src/SketchPlugin/Test/TestConstraintHorizontalValidator.py [new file with mode: 0644]
src/SketchPlugin/Test/TestConstraintMiddlePoint.py
src/SketchPlugin/Test/TestConstraintTangent.py
src/SketchPlugin/Test/TestCreateArcByCenterStartEnd.py
src/SketchPlugin/Test/TestCreateArcByTangentEdge.py
src/SketchPlugin/Test/TestCreateArcByThreePoints.py
src/SketchPlugin/Test/TestCreateArcChangeType.py
src/SketchPlugin/Test/TestCreateCircleByCenterAndPassed.py
src/SketchPlugin/Test/TestCreateCircleByThreePoints.py
src/SketchPlugin/Test/TestCreateCircleChangeType.py
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned01.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned02.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned03.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned04.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned05.py [new file with mode: 0644]
src/SketchPlugin/Test/TestFillet.py
src/SketchPlugin/Test/TestFilletInteracting.py
src/SketchPlugin/Test/TestMoveArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMoveCircle.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMoveLine.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMovePoint.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMovementComplex.py [new file with mode: 0644]
src/SketchPlugin/Test/TestProjection.py
src/SketchPlugin/Test/TestProjectionIntoResult.py [new file with mode: 0644]
src/SketchPlugin/Test/TestSignedDistancePointLine.py [new file with mode: 0644]
src/SketchPlugin/Test/TestSignedDistancePointPoint.py [new file with mode: 0644]
src/SketchPlugin/icons/distance_h.png [new file with mode: 0644]
src/SketchPlugin/icons/distance_v.png [new file with mode: 0644]
src/SketchPlugin/icons/ellipse.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_ConstraintDistance.cpp
src/SketchSolver/SketchSolver_ConstraintDistance.h
src/SketchSolver/SketchSolver_ConstraintMovement.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintMovement.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Error.h
src/SketchSolver/SketchSolver_Group.cpp
src/SketchSolver/SketchSolver_Group.h
src/SketchSolver/SketchSolver_Manager.cpp
src/SketchSolver/SketchSolver_Manager.h
src/SketchSolver/SketchSolver_Storage.h
src/SketcherPrs/SketcherPrs_Collinear.cpp
src/SketcherPrs/SketcherPrs_Collinear.h
src/SketcherPrs/SketcherPrs_Equal.cpp
src/SketcherPrs/SketcherPrs_Equal.h
src/SketcherPrs/SketcherPrs_Factory.cpp
src/SketcherPrs/SketcherPrs_Factory.h
src/SketcherPrs/SketcherPrs_HVDirection.cpp
src/SketcherPrs/SketcherPrs_HVDirection.h
src/SketcherPrs/SketcherPrs_LengthDimension.cpp
src/SketcherPrs/SketcherPrs_Middle.cpp
src/SketcherPrs/SketcherPrs_Middle.h
src/SketcherPrs/SketcherPrs_Mirror.cpp
src/SketcherPrs/SketcherPrs_Mirror.h
src/SketcherPrs/SketcherPrs_Parallel.cpp
src/SketcherPrs/SketcherPrs_Parallel.h
src/SketcherPrs/SketcherPrs_Perpendicular.cpp
src/SketcherPrs/SketcherPrs_Perpendicular.h
src/SketcherPrs/SketcherPrs_PositionMgr.cpp
src/SketcherPrs/SketcherPrs_PositionMgr.h
src/SketcherPrs/SketcherPrs_Rigid.cpp
src/SketcherPrs/SketcherPrs_Rigid.h
src/SketcherPrs/SketcherPrs_SymbolPrs.cpp
src/SketcherPrs/SketcherPrs_SymbolPrs.h
src/SketcherPrs/SketcherPrs_Tangent.cpp
src/SketcherPrs/SketcherPrs_Tangent.h
src/SketcherPrs/SketcherPrs_Transformation.cpp
src/SketcherPrs/SketcherPrs_Transformation.h
src/XGUI/XGUI_ContextMenuMgr.cpp
src/XGUI/XGUI_DataModel.cpp
src/XGUI/XGUI_DataModel.h
src/XGUI/XGUI_ObjectsBrowser.cpp
src/XGUI/XGUI_ObjectsBrowser.h
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_pictures.qrc
src/XGUI/pictures/eyeclosed.png [new file with mode: 0644]
src/XGUI/pictures/eyemiclosed.png [new file with mode: 0644]
src/XGUI/pictures/eyeopen.png [new file with mode: 0644]

index c1cd3ebf2a5582ffe418aa819a4292d7703cfda3..9475e015fe68cab8df6632a56ae29290d4d584e9 100644 (file)
@@ -82,6 +82,9 @@ ELSE(${HAVE_SALOME})
     SET(SHAPER_INSTALL_TUI_DOC doc CACHE INTERNAL "" FORCE)
 ENDIF(${HAVE_SALOME})
 
+# Sketcher: Change radius of circular edges while dragging a point on the edge
+SET(SKETCHER_CHANGE_RADIUS_WHEN_MOVE FALSE)
+
 ADD_SUBDIRECTORY (src/Config)
 ADD_SUBDIRECTORY (src/Events)
 ADD_SUBDIRECTORY (src/Model)
index 2656c55dc23528881c5478826f72b9b76ec86ae2..48222cfc4e3c5384f6452d83744718b1778d0e0e 100644 (file)
@@ -56,7 +56,7 @@ ConstructionAPI_Point::ConstructionAPI_Point(const std::shared_ptr<ModelAPI_Feat
   if(initialize()) {
     setByDistanceOnEdge(theEdge, theDistanceValue, theDistancePercent, theReverse);
   }
-}
+}*/
 
 //==================================================================================================
 ConstructionAPI_Point::ConstructionAPI_Point(const std::shared_ptr<ModelAPI_Feature>& theFeature,
@@ -67,19 +67,19 @@ ConstructionAPI_Point::ConstructionAPI_Point(const std::shared_ptr<ModelAPI_Feat
   if(initialize()) {
     GeomAPI_Shape::ShapeType aType1 = getShapeType(theObject1);
     GeomAPI_Shape::ShapeType aType2 = getShapeType(theObject2);
-
+    /*
     if(aType1 == GeomAPI_Shape::VERTEX && aType2 == GeomAPI_Shape::FACE) {
       // If first object is vertex and second object is face then set by projection.
       setByProjection(theObject1, theObject2);
     } else if(aType1 == GeomAPI_Shape::EDGE && aType2 == GeomAPI_Shape::EDGE) {
       // If both objects are edges then set by lines intersection.
       setByLinesIntersection(theObject1, theObject2);
-    } else if(aType1 == GeomAPI_Shape::EDGE && aType2 == GeomAPI_Shape::FACE) {
+    } else */if(aType1 == GeomAPI_Shape::EDGE && aType2 == GeomAPI_Shape::FACE) {
       // If first object is edge and second object is face then set by line and plane intersection.
       setByLineAndPlaneIntersection(theObject1, theObject2);
     }
   }
-}*/
+}
 
 //==================================================================================================
 ConstructionAPI_Point::~ConstructionAPI_Point()
@@ -96,6 +96,7 @@ void ConstructionAPI_Point::setByXYZ(const ModelHighAPI_Double& theX,
   fillAttribute(theX, myx);
   fillAttribute(theY, myy);
   fillAttribute(theZ, myz);
+  fillAttribute(ConstructionPlugin_Point::CREATION_METHOD_BY_XYZ(), mycreationMethod);
 
   execute(false);
 }
@@ -135,32 +136,40 @@ void ConstructionAPI_Point::setByLinesIntersection(const ModelHighAPI_Selection&
   fillAttribute(theEdge2, mysecondLine);
 
   execute();
-}
+}*/
 
 //==================================================================================================
 void ConstructionAPI_Point::setByLineAndPlaneIntersection(const ModelHighAPI_Selection& theEdge,
                                                           const ModelHighAPI_Selection& theFace)
 {
-  fillAttribute(ConstructionPlugin_Point::CREATION_METHOD_BY_LINE_AND_PLANE_INTERSECTION(), mycreationMethod);
+  fillAttribute(
+    ConstructionPlugin_Point::CREATION_METHOD_BY_LINE_AND_PLANE_INTERSECTION(), mycreationMethod);
   fillAttribute(theEdge, myintersectionLine);
   fillAttribute(theFace, myintersectionPlane);
-
+  fillAttribute("", useOffset()); // not used by default
   execute();
-}*/
+}
 
 //==================================================================================================
 void ConstructionAPI_Point::dump(ModelHighAPI_Dumper& theDumper) const
 {
-  // TODO: all types of points
-
   FeaturePtr aBase = feature();
   const std::string& aDocName = theDumper.name(aBase->document());
-
-  AttributeDoublePtr anAttrX = aBase->real(ConstructionPlugin_Point::X());
-  AttributeDoublePtr anAttrY = aBase->real(ConstructionPlugin_Point::Y());
-  AttributeDoublePtr anAttrZ = aBase->real(ConstructionPlugin_Point::Z());
-  theDumper << aBase << " = model.addPoint(" << aDocName << ", "
-            << anAttrX << ", " << anAttrY << ", " << anAttrZ << ")" << std::endl;
+  const std::string& aMeth = creationMethod()->value();
+
+  // common part
+  theDumper << aBase << " = model.addPoint(" << aDocName << ", ";
+
+  if (aMeth == "" || // default is XYZ
+      aMeth == ConstructionPlugin_Point::CREATION_METHOD_BY_XYZ()) {
+    theDumper << x() << ", " << y() << ", " << z() << ")" << std::endl;
+  } else if (aMeth == ConstructionPlugin_Point::CREATION_METHOD_BY_LINE_AND_PLANE_INTERSECTION()) {
+    theDumper << intersectionLine() << ", " <<intersectionPlane() ;
+    if (!useOffset()->value().empty()) { // call method with defined offset
+      theDumper << ", " << offset() << ", " << reverseOffset();
+    }
+    theDumper << ")" << std::endl;
+  }
 }
 
 //==================================================================================================
@@ -180,17 +189,32 @@ PointPtr addPoint(const std::shared_ptr<ModelAPI_Document> & thePart,
                   const bool theDistancePercent,
                   const bool theReverse)
 {
-  // TODO(spo): check that thePart is not empty
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ConstructionAPI_Point::ID());
   return PointPtr(new ConstructionAPI_Point(aFeature, theEdge, theDistanceValue, theDistancePercent, theReverse));
-}
+}*/
 
 //==================================================================================================
 PointPtr addPoint(const std::shared_ptr<ModelAPI_Document> & thePart,
                   const ModelHighAPI_Selection& theObject1,
                   const ModelHighAPI_Selection& theObject2)
 {
-  // TODO(spo): check that thePart is not empty
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ConstructionAPI_Point::ID());
   return PointPtr(new ConstructionAPI_Point(aFeature, theObject1, theObject2));
-}*/
+}
+
+//==================================================================================================
+PointPtr addPoint(const std::shared_ptr<ModelAPI_Document> & thePart,
+                  const ModelHighAPI_Selection& theObject1,
+                  const ModelHighAPI_Selection& theObject2,
+                  const ModelHighAPI_Double& theDistanceValue,
+                  const bool theReverse)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ConstructionAPI_Point::ID());
+  PointPtr anAPI(new ConstructionAPI_Point(aFeature, theObject1, theObject2));
+
+  fillAttribute(ConstructionPlugin_Point::USE_OFFSET(), anAPI->useOffset());
+  fillAttribute(theDistanceValue, anAPI->offset());
+  fillAttribute(theReverse, anAPI->reverseOffset());
+
+  return anAPI;
+}
index eb5f06719b1d431eb960d7465d2cffa03a4dd9ed..322176c4a771da37892a58d1dd92790ada02ffea 100644 (file)
@@ -56,21 +56,33 @@ public:
                         const ModelHighAPI_Double& theDistanceValue,
                         const bool theDistancePercent = false,
                         const bool theReverse = false);
-
-  /// Constructor with values.
+  */
+  /// Constructor with values: intersected objects.
   CONSTRUCTIONAPI_EXPORT
   ConstructionAPI_Point(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                         const ModelHighAPI_Selection& theObject1,
-                        const ModelHighAPI_Selection& theObject2);*/
+                        const ModelHighAPI_Selection& theObject2);
 
   /// Destructor.
   CONSTRUCTIONAPI_EXPORT
   virtual ~ConstructionAPI_Point();
 
-  INTERFACE_3(ConstructionPlugin_Point::ID(),
+  INTERFACE_9(ConstructionPlugin_Point::ID(),
               x, ConstructionPlugin_Point::X(), ModelAPI_AttributeDouble, /** X attribute */,
               y, ConstructionPlugin_Point::Y(), ModelAPI_AttributeDouble, /** Y attribute */,
-              z, ConstructionPlugin_Point::Z(), ModelAPI_AttributeDouble, /** Z attribute */)
+              z, ConstructionPlugin_Point::Z(), ModelAPI_AttributeDouble, /** Z attribute */,
+              creationMethod, ConstructionPlugin_Point::CREATION_METHOD(),
+              ModelAPI_AttributeString, /** Creation method */,
+              intersectionLine, ConstructionPlugin_Point::INTERSECTION_LINE(),
+              ModelAPI_AttributeSelection, /** Line for intersection */,
+              intersectionPlane, ConstructionPlugin_Point::INTERSECTION_PLANE(),
+              ModelAPI_AttributeSelection, /** Plane for intersection */,
+              useOffset, ConstructionPlugin_Point::USE_OFFSET(),
+              ModelAPI_AttributeString, /** Use offset */,
+              offset, ConstructionPlugin_Point::OFFSET(),
+              ModelAPI_AttributeDouble, /** Offset */,
+              reverseOffset, ConstructionPlugin_Point::REVERSE_OFFSET(),
+              ModelAPI_AttributeBoolean, /** Reverse offset */)
 
 
   /// Set point values.
@@ -95,11 +107,11 @@ public:
   CONSTRUCTIONAPI_EXPORT
   void setByLinesIntersection(const ModelHighAPI_Selection& theEdge1,
                               const ModelHighAPI_Selection& theEdge2);
-
+  */
   /// Set line and plane for intersections.
   CONSTRUCTIONAPI_EXPORT
   void setByLineAndPlaneIntersection(const ModelHighAPI_Selection& theEdge,
-                                     const ModelHighAPI_Selection& theFace);*/
+                                     const ModelHighAPI_Selection& theFace);
 
   /// Dump wrapped feature
   CONSTRUCTIONAPI_EXPORT
@@ -125,12 +137,22 @@ PointPtr addPoint(const std::shared_ptr<ModelAPI_Document> & thePart,
                   const ModelHighAPI_Double& theDistanceValue,
                   const bool theDistancePercent = false,
                   const bool theReverse = false);
+*/
+/// \ingroup CPPHighAPI
+/// \brief Create Point feature as an intersection of selected plane (or planar face) and edge
+CONSTRUCTIONAPI_EXPORT
+PointPtr addPoint(const std::shared_ptr<ModelAPI_Document> & thePart,
+                  const ModelHighAPI_Selection& theObject1,
+                  const ModelHighAPI_Selection& theObject2);
 
 /// \ingroup CPPHighAPI
-/// \brief Create Point feature
+/// \brief Create Point feature as an intersection of selected plane (or planar face) and edge
+/// with positive distance from the plane and flag to reverse the offset direction.
 CONSTRUCTIONAPI_EXPORT
 PointPtr addPoint(const std::shared_ptr<ModelAPI_Document> & thePart,
                   const ModelHighAPI_Selection& theObject1,
-                  const ModelHighAPI_Selection& theObject2);*/
+                  const ModelHighAPI_Selection& theObject2,
+                  const ModelHighAPI_Double& theDistanceValue,
+                  const bool theReverse = false);
 
 #endif /* SRC_CONSTRUCTIONAPI_CONSTRUCTIONAPI_POINT_H_ */
index 96e79cedaa33870eb7a8299f7b3ba5fa4b57b7e4..0cbcec0492bf9101f1f075eb76bc8e953d89dea0 100644 (file)
@@ -77,6 +77,7 @@ INCLUDE_DIRECTORIES(
 
 ADD_UNIT_TESTS(TestAxisCreation.py
                UnitTestAxis.py
-               TestPoint.py
+               TestPoint_XYZ.py
+               TestPoint_LineAndPlane.py
                TestPointName.py
                TestPlane.py)
index 04864cfb6543d5bb365d4daea83eaa5d86e7db4f..9f18a33189327e9f0087eb70356275be36520717 100644 (file)
@@ -42,8 +42,8 @@ ConstructionPlugin_Plugin::ConstructionPlugin_Plugin()
   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
   aFactory->registerValidator("ConstructionPlugin_ValidatorPointLines",
                               new ConstructionPlugin_ValidatorPointLines());
-  aFactory->registerValidator("ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel",
-                              new ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel());
+  aFactory->registerValidator("ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel",
+                              new ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel());
   aFactory->registerValidator("ConstructionPlugin_ValidatorPlaneThreePoints",
                               new ConstructionPlugin_ValidatorPlaneThreePoints());
   aFactory->registerValidator("ConstructionPlugin_ValidatorPlaneLinePoint",
index 43f2e78e2fb503ad75e2348a517a2290ad0c5da0..f08cd5fa42661a5d97b3d325f02e52af0fa71928 100644 (file)
 #include <ModelAPI_ResultConstruction.h>
 
 #include <GeomAlgoAPI_PointBuilder.h>
+#include <GeomAlgoAPI_ShapeTools.h>
 
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Vertex.h>
+#include <GeomAPI_Pln.h>
 
 //==================================================================================================
 ConstructionPlugin_Point::ConstructionPlugin_Point()
@@ -47,12 +49,12 @@ const std::string& ConstructionPlugin_Point::getKind()
 //==================================================================================================
 void ConstructionPlugin_Point::initAttributes()
 {
-  //data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
-
   data()->addAttribute(X(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(Y(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(Z(), ModelAPI_AttributeDouble::typeId());
 
+  data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
+
   /*data()->addAttribute(EDGE(), ModelAPI_AttributeSelection::typeId());
   data()->addAttribute(DISTANCE_VALUE(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(DISTANCE_PERCENT(), ModelAPI_AttributeBoolean::typeId());
@@ -63,32 +65,38 @@ void ConstructionPlugin_Point::initAttributes()
 
   data()->addAttribute(FIRST_LINE(), ModelAPI_AttributeSelection::typeId());
   data()->addAttribute(SECOND_LINE(), ModelAPI_AttributeSelection::typeId());
-
+*/
   data()->addAttribute(INTERSECTION_LINE(), ModelAPI_AttributeSelection::typeId());
-  data()->addAttribute(INTERSECTION_PLANE(), ModelAPI_AttributeSelection::typeId());*/
+  data()->addAttribute(INTERSECTION_PLANE(), ModelAPI_AttributeSelection::typeId());
+
+  data()->addAttribute(USE_OFFSET(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(OFFSET(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(REVERSE_OFFSET(), ModelAPI_AttributeBoolean::typeId());
 }
 
 //==================================================================================================
 void ConstructionPlugin_Point::execute()
 {
-  GeomShapePtr aShape = createByXYZ();
-
-  /*GeomShapePtr aShape;
+  GeomShapePtr aShape;
 
-  std::string aCreationMethod = string(CREATION_METHOD())->value();
+   // to support compatibility with old documents where aCreationMethod did not exist
+  std::string aCreationMethod =
+    string(CREATION_METHOD()).get() && !string(CREATION_METHOD())->value().empty() ?
+    string(CREATION_METHOD())->value() : CREATION_METHOD_BY_XYZ();
   if(aCreationMethod == CREATION_METHOD_BY_XYZ()) {
     aShape = createByXYZ();
-  } else if(aCreationMethod == CREATION_METHOD_BY_DISTANCE_ON_EDGE()) {
+  }/* else if(aCreationMethod == CREATION_METHOD_BY_DISTANCE_ON_EDGE()) {
     aShape = createByDistanceOnEdge();
   } else if(aCreationMethod == CREATION_METHOD_BY_PROJECTION()) {
     aShape = createByProjection();
   } else if(aCreationMethod == CREATION_METHOD_BY_LINES_INTERSECTION()) {
     aShape = createByLinesIntersection();
-  } else if(aCreationMethod == CREATION_METHOD_BY_LINE_AND_PLANE_INTERSECTION()) {
+  }*/ else if(aCreationMethod == CREATION_METHOD_BY_LINE_AND_PLANE_INTERSECTION()) {
     aShape = createByLineAndPlaneIntersection();
-  }*/
+  }
 
   if(!aShape.get()) {
+    setError("Error: intersection not found.");
     return;
   }
 
@@ -180,12 +188,13 @@ std::shared_ptr<GeomAPI_Vertex> ConstructionPlugin_Point::createByLinesIntersect
 
   return GeomAlgoAPI_PointBuilder::vertexByIntersection(aFirstEdge, aSecondEdge);
 }
+*/
 
 //==================================================================================================
 std::shared_ptr<GeomAPI_Vertex> ConstructionPlugin_Point::createByLineAndPlaneIntersection()
 {
   // Get line.
-  AttributeSelectionPtr aLineSelection= selection(INTERSECTION_LINE());
+  AttributeSelectionPtr aLineSelection = selection(INTERSECTION_LINE());
   GeomShapePtr aLineShape = aLineSelection->value();
   if(!aLineShape.get()) {
     aLineShape = aLineSelection->context()->shape();
@@ -200,5 +209,14 @@ std::shared_ptr<GeomAPI_Vertex> ConstructionPlugin_Point::createByLineAndPlaneIn
   }
   std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(aPlaneShape));
 
-  return GeomAlgoAPI_PointBuilder::vertexByIntersection(anEdge, aFace);
-}*/
+  if (!string(USE_OFFSET())->value().empty()) {
+    double anOffset = real(OFFSET())->value();
+    if (boolean(REVERSE_OFFSET())->value())
+      anOffset = -anOffset;
+    if (fabs(anOffset) > 1.e-9) { // move face
+      aFace->translate(aFace->getPlane()->direction(), anOffset);
+    }
+  }
+
+  return GeomAlgoAPI_ShapeTools::intersect(anEdge, aFace);
+}
index e9efd6ab023e4ce7637d0019be600e4491a951c7..a9f59d31de4f1c92c91e9afe33f1ec29e4bfe7e4 100644 (file)
@@ -27,6 +27,8 @@
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Result.h>
 
+#include <math.h>
+
 class GeomAPI_Vertex;
 
 /// \class ConstructionPlugin_Point
@@ -45,7 +47,7 @@ public:
     return CONSTRUCTION_POINT_KIND;
   }
 
-  /*/// Attribute name for creation method.
+  /// Attribute name for creation method.
   inline static const std::string& CREATION_METHOD()
   {
     static const std::string MY_CREATION_METHOD_ID("creation_method");
@@ -58,7 +60,7 @@ public:
     static const std::string MY_CREATION_METHOD_ID("by_xyz");
     return MY_CREATION_METHOD_ID;
   }
-
+  /*
   /// Attribute name for creation method.
   inline static const std::string& CREATION_METHOD_BY_DISTANCE_ON_EDGE()
   {
@@ -79,13 +81,13 @@ public:
     static const std::string MY_CREATION_METHOD_ID("by_lines_intersection");
     return MY_CREATION_METHOD_ID;
   }
-
+  */
   /// Attribute name for creation method.
   inline static const std::string& CREATION_METHOD_BY_LINE_AND_PLANE_INTERSECTION()
   {
     static const std::string MY_CREATION_METHOD_ID("by_line_and_plane_intersection");
     return MY_CREATION_METHOD_ID;
-  }*/
+  }
 
   /// Attribute name for X coordinate.
   inline static const std::string& X()
@@ -163,6 +165,7 @@ public:
     static const std::string ATTR_ID("second_line");
     return ATTR_ID;
   }
+  */
 
   /// Attribute name for selected intersection line.
   inline static const std::string& INTERSECTION_LINE()
@@ -176,7 +179,28 @@ public:
   {
     static const std::string ATTR_ID("intersection_plane");
     return ATTR_ID;
-  }*/
+  }
+
+  /// Attribute name for use offset for the intersection plane.
+  inline static const std::string& USE_OFFSET()
+  {
+    static const std::string ATTR_ID("use_offset");
+    return ATTR_ID;
+  }
+
+  /// Attribute name for offset for the intersection plane.
+  inline static const std::string& OFFSET()
+  {
+    static const std::string ATTR_ID("offset");
+    return ATTR_ID;
+  }
+
+  /// Attribute name for reverse offset for the intersection plane.
+  inline static const std::string& REVERSE_OFFSET()
+  {
+    static const std::string ATTR_ID("reverse_offset");
+    return ATTR_ID;
+  }
 
   /// Creates a new part document if needed.
   CONSTRUCTIONPLUGIN_EXPORT virtual void execute();
@@ -198,8 +222,8 @@ private:
   std::shared_ptr<GeomAPI_Vertex> createByXYZ();
   /*std::shared_ptr<GeomAPI_Vertex> createByDistanceOnEdge();
   std::shared_ptr<GeomAPI_Vertex> createByProjection();
-  std::shared_ptr<GeomAPI_Vertex> createByLinesIntersection();
-  std::shared_ptr<GeomAPI_Vertex> createByLineAndPlaneIntersection();*/
+  std::shared_ptr<GeomAPI_Vertex> createByLinesIntersection();*/
+  std::shared_ptr<GeomAPI_Vertex> createByLineAndPlaneIntersection();
 
 };
 
index 33d98d704ebe2c0fbf29907d5b0d1ed3fcf7cb8a..a3bd2bd539eb5efe4821d70451e09bd7e6da32cd 100644 (file)
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Pln.h>
 #include <GeomAPI_Vertex.h>
+#include <GeomAlgoAPI_ShapeTools.h>
 
 #include <ModelAPI_AttributeSelection.h>
 #include <ModelAPI_AttributeBoolean.h>
 
 #include <Events_InfoMessage.h>
 
+static std::shared_ptr<GeomAPI_Edge> getEdge(const GeomShapePtr theShape);
 static std::shared_ptr<GeomAPI_Lin> getLin(const GeomShapePtr theShape);
 static std::shared_ptr<GeomAPI_Pln> getPln(const GeomShapePtr theShape);
 static std::shared_ptr<GeomAPI_Pnt> getPnt(const GeomShapePtr theShape);
@@ -94,7 +96,7 @@ bool ConstructionPlugin_ValidatorPointLines::isValid(const AttributePtr& theAttr
 }
 
 //==================================================================================================
-bool ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel::isValid(
+bool ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel::isValid(
     const AttributePtr& theAttribute,
     const std::list<std::string>& theArguments,
     Events_InfoMessage& theError) const
@@ -105,7 +107,7 @@ bool ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel::isValid(
     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
   AttributeSelectionPtr anAttribute2 = aFeature->selection(theArguments.front());
 
-  std::shared_ptr<GeomAPI_Lin> aLin;
+  std::shared_ptr<GeomAPI_Edge> anEdge;
   std::shared_ptr<GeomAPI_Pln> aPln;
 
   GeomShapePtr aShape1 = anAttribute1->value();
@@ -127,20 +129,23 @@ bool ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel::isValid(
     aShape2 = aContext2->shape();
   }
 
-  aLin = getLin(aShape1);
+  bool isPlaneFirst = false;
+  anEdge = getEdge(aShape1);
   aPln = getPln(aShape2);
-  if(!aLin.get() || !aPln.get()) {
-    aLin = getLin(aShape2);
+  if(!anEdge.get() || !aPln.get()) {
+    anEdge = getEdge(aShape2);
     aPln = getPln(aShape1);
+    isPlaneFirst = true;
   }
 
-  if(!aLin.get() || !aPln.get()) {
+  if(!anEdge.get() || !aPln.get()) {
     theError = "Wrong shape types selected.";
     return false;
   }
 
-  if(aPln->isParallel(aLin)) {
-    theError = "Plane and line are parallel.";
+  std::shared_ptr<GeomAPI_Face> aPlaneFace(new GeomAPI_Face(isPlaneFirst ? aShape1 : aShape2));
+  if(GeomAlgoAPI_ShapeTools::isParallel(anEdge, aPlaneFace)) {
+    theError = "Plane and edge are parallel.";
     return false;
   }
 
@@ -381,6 +386,17 @@ bool ConstructionPlugin_ValidatorAxisTwoNotParallelPlanes::isValid(
   return true;
 }
 
+std::shared_ptr<GeomAPI_Edge> getEdge(const GeomShapePtr theShape)
+{
+  if(!theShape->isEdge()) {
+    return std::shared_ptr<GeomAPI_Edge>();
+  }
+
+  std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
+
+  return anEdge;
+}
+
 std::shared_ptr<GeomAPI_Lin> getLin(const GeomShapePtr theShape)
 {
   std::shared_ptr<GeomAPI_Lin> aLin;
index cb13f6abbccde02d84d77556381071236697e85b..3254672de855045b8786492e870c7e97ecd00c63 100644 (file)
@@ -38,10 +38,10 @@ public:
                         Events_InfoMessage& theError) const;
 };
 
-/// \class ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel
+/// \class ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel
 /// \ingroup Validators
-/// \brief A validator for selection line and plane for point by intersection.
-class ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel: public ModelAPI_AttributeValidator
+/// \brief A validator for selection edge and plane for point by intersection.
+class ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel: public ModelAPI_AttributeValidator
 {
 public:
   //! \return True if the attribute is valid.
index 80db16361a6e0beb3f7ebe76cb52795ad0cec711..a645c548e03fff88011f13993285b2e4e50b1485 100644 (file)
@@ -52,6 +52,7 @@ assert(aPointFeatureData is not None)
 aPointFeatureData.real("x").setValue(0.)
 aPointFeatureData.real("y").setValue(0.)
 aPointFeatureData.real("z").setValue(0.)
+aPointFeatureData.string("creation_method").setValue("by_xyz")
 aPointFeature.execute()
 aSession.finishOperation()
 aPoint1Result = aPointFeature.firstResult();
@@ -67,6 +68,7 @@ assert(aPointFeatureData is not None)
 aPointFeatureData.real("x").setValue(0.)
 aPointFeatureData.real("y").setValue(0.)
 aPointFeatureData.real("z").setValue(100.)
+aPointFeatureData.string("creation_method").setValue("by_xyz")
 aPointFeature.execute()
 aSession.finishOperation()
 aPoint2Result = aPointFeature.firstResult();
diff --git a/src/ConstructionPlugin/Test/TestPoint.py b/src/ConstructionPlugin/Test/TestPoint.py
deleted file mode 100644 (file)
index 4241bc5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-## Copyright (C) 2014-2017  CEA/DEN, EDF R&D
-##
-## This library is free software; you can redistribute it and/or
-## modify it under the terms of the GNU Lesser General Public
-## License as published by the Free Software Foundation; either
-## version 2.1 of the License, or (at your option) any later version.
-##
-## This library is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## Lesser General Public License for more details.
-##
-## You should have received a copy of the GNU Lesser General Public
-## License along with this library; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##
-## See http:##www.salome-platform.org/ or
-## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
-##
-
-"""
-Test case for Construction Point feature. Written on High API.
-"""
-from ModelAPI import *
-from GeomAPI import *
-
-from salome.shaper import model
-
-# Get session
-aSession = ModelAPI_Session.get()
-
-# Create a part
-aDocument = aSession.activeDocument()
-aSession.startOperation()
-model.addPart(aDocument)
-aDocument = aSession.activeDocument()
-aSession.finishOperation()
-
-# Create a point by coordinates
-aSession.startOperation()
-aPoint = model.addPoint(aDocument, 50, 50, 50)
-aSession.finishOperation()
-assert (len(aPoint.results()) > 0)
-
-# # Create a sketch with lines
-# aSession.startOperation()
-# anOrigin = GeomAPI_Pnt(0, 0, 0)
-# aDirX = GeomAPI_Dir(1, 0, 0)
-# aNorm = GeomAPI_Dir(0, 0, 1)
-# aSketch = model.addSketch(aDocument, GeomAPI_Ax3(anOrigin, aDirX, aNorm))
-# aSketchLine1 = aSketch.addLine(0, 0, 100, 100)
-# aSketchLine2 = aSketch.addLine(0, 100, 100, 0)
-# aSession.finishOperation()
-#
-# # Create a point on line
-# aSession.startOperation()
-# aPoint = model.addPoint(aDocument, aSketchLine1.result()[0], 25, True, False)
-# aSession.finishOperation()
-# assert (len(aPoint.result()) > 0)
-#
-# # Create plane
-# aSession.startOperation()
-# aPlane = model.addPlane(aDocument, 1, 1, 1, 1)
-# aSession.finishOperation()
-#
-# # Create a point by projection
-# aSession.startOperation()
-# aPoint = model.addPoint(aDocument, aPoint.result()[0], aPlane.result()[0])
-# aSession.finishOperation()
-# assert (len(aPoint.result()) > 0)
-#
-# # Create a point by lines intersection
-# aSession.startOperation()
-# aPoint = model.addPoint(aDocument, aSketchLine1.result()[0], aSketchLine2.result()[0])
-# aSession.finishOperation()
-# assert (len(aPoint.result()) > 0)
-#
-# # Create a point by line and plane intersection
-# aSession.startOperation()
-# aPoint = model.addPoint(aDocument, aSketchLine1.result()[0], aPlane.result()[0])
-# aSession.finishOperation()
-# assert (len(aPoint.result()) > 0)
-
-assert(model.checkPythonDump())
index 33ff527c403295e1e67de21f1b9e6cd0d1996983..5579700911197b14bae4f48e8523ca90a2243d49 100644 (file)
@@ -31,6 +31,7 @@ assert(aFeatureData is not None)
 aFeatureData.real("x").setValue(0.)
 aFeatureData.real("y").setValue(0.)
 aFeatureData.real("z").setValue(0.)
+aFeatureData.string("creation_method").setValue("by_xyz")
 aFeatureName = aFeature.name()
 aFeature.execute()
 aSession.finishOperation()
diff --git a/src/ConstructionPlugin/Test/TestPoint_LineAndPlane.py b/src/ConstructionPlugin/Test/TestPoint_LineAndPlane.py
new file mode 100644 (file)
index 0000000..635ab81
--- /dev/null
@@ -0,0 +1,55 @@
+## Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+Test case for Construction Point feature as intersection of line and plane.
+"""
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchPoint_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 60)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+model.do()
+Sketch_2 = model.addSketch(partSet, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_2.addLine(60, 100, 0, 20)
+SketchArc_1 = Sketch_2.addArc(0, 0, -65.89631323066888, 61.2998850129882, -90, 0, False)
+model.do()
+
+# point by sketch face and a line
+Point_1 = model.addPoint(partSet, model.selection("EDGE", "Sketch_2/Edge-SketchLine_1"), model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"))
+model.do()
+# check the point position
+rightPosition = GeomAPI_Vertex(-15, 0, 0)
+assert(rightPosition.isEqual(Point_1.results()[0].resultSubShapePair()[0].shape()))
+
+# point by sketch face and an arc, intersection outside of the face, offset is defined
+Point_2 = model.addPoint(partSet, model.selection("EDGE", "Sketch_2/Edge-SketchArc_1"), model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), 10, True)
+# check the point position
+rightPosition = GeomAPI_Vertex(-89.442719099991606, 0, -10)
+assert(rightPosition.isEqual(Point_2.results()[0].resultSubShapePair()[0].shape()))
+
+
+model.end()
+assert(model.checkPythonDump())
diff --git a/src/ConstructionPlugin/Test/TestPoint_XYZ.py b/src/ConstructionPlugin/Test/TestPoint_XYZ.py
new file mode 100644 (file)
index 0000000..df73e5f
--- /dev/null
@@ -0,0 +1,45 @@
+## Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+Test case for Construction Point feature by coordinates.
+"""
+from ModelAPI import *
+from GeomAPI import *
+
+from salome.shaper import model
+
+# Get session
+aSession = ModelAPI_Session.get()
+
+# Create a part
+aDocument = aSession.activeDocument()
+aSession.startOperation()
+model.addPart(aDocument)
+aDocument = aSession.activeDocument()
+aSession.finishOperation()
+
+# Create a point by coordinates
+aSession.startOperation()
+aPoint = model.addPoint(aDocument, 50, 50, 50)
+aSession.finishOperation()
+assert (len(aPoint.results()) > 0)
+
+assert(model.checkPythonDump())
index 42368daf2b48b2c4519ebafa3b4279f7b6baadb8..20f2f3cb9a553f37184ac9ddb5199261f3d5c868 100644 (file)
@@ -20,11 +20,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
 -->
 
 <source>
-  <doublevalue id="x" label="X " tooltip="X coordinate" default="0"/>
-  <doublevalue id="y" label="Y " tooltip="Y coordinate" default="0"/>
-  <doublevalue id="z" label="Z " tooltip="Z coordinate" default="0"/>
-
-  <!--<toolbox id="creation_method">
+  <toolbox id="creation_method">
     <box id="by_xyz"
          title="By X, Y, Z"
          tooltip="Point at a given distance from the origin."
@@ -45,6 +41,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
                    icon="icons/Construction/z_size.png"
                    default="0"/>
     </box>
+<!--
     <box id="by_distance_on_edge"
          title="By distance on edge"
          tooltip="Point on an edge, at a given distance of one of its end."
@@ -111,6 +108,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
         <validator id="ConstructionPlugin_ValidatorPointLines" parameters="first_line"/>
       </shape_selector>
     </box>
+-->
     <box id="by_line_and_plane_intersection"
          title="By line and plane intersection"
          tooltip="Point by intersection of line and plane."
@@ -120,8 +118,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
                       tooltip="Line for intersection."
                       icon="icons/Construction/edge.png"
                       shape_types="edge">
-        <validator id="GeomValidators_ShapeType" parameters="line"/>
-        <validator id="ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel" parameters="intersection_plane"/>
+        <validator id="ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel" parameters="intersection_plane"/>
       </shape_selector>
       <shape_selector id="intersection_plane"
                       label="Plane"
@@ -129,9 +126,13 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
                       icon="icons/Construction/face.png"
                       shape_types="face">
         <validator id="GeomValidators_Face" parameters="plane"/>
-        <validator id="ConstructionPlugin_ValidatorPointLineAndPlaneNotParallel" parameters="intersection_line"/>
+        <validator id="ConstructionPlugin_ValidatorPointEdgeAndPlaneNotParallel" parameters="intersection_line"/>
       </shape_selector>
+      <optionalbox id="use_offset" title="Offset from the plane">
+        <doublevalue id="offset" label="Distance " tooltip="Distance from the plane" min="0" default="0"/>
+        <boolvalue id="reverse_offset" label="Reverse" tooltip="Reverse offset value" default="false"/>
+      </optionalbox>
     </box>
 
-  </toolbox>-->
+  </toolbox>
 </source>
index 8e191e4fd53c93614ce1faf0e1a2025ce9b259a6..325e5055d15213afea642371172db3df3879a03a 100644 (file)
@@ -56,6 +56,8 @@ SET(PROJECT_HEADERS
     GeomAPI_Trsf.h
     GeomAPI_Angle2d.h
     GeomAPI_Wire.h
+    GeomAPI_Ellipse.h
+    GeomAPI_Ellipse2d.h
 )
 
 SET(PROJECT_SOURCES
@@ -90,6 +92,8 @@ SET(PROJECT_SOURCES
     GeomAPI_Trsf.cpp
     GeomAPI_Angle2d.cpp
     GeomAPI_Wire.cpp
+    GeomAPI_Ellipse.cpp
+    GeomAPI_Ellipse2d.cpp
 )
 
 SET(PROJECT_LIBRARIES
index e7658e88ef24d74ecfe2d5d4d4163e154efb2fa7..39cd19c3f42e94cd0796d1b3558ff64844f47c86 100644 (file)
@@ -70,4 +70,7 @@ public:
   std::shared_ptr<GeomAPI_Dir> dir() const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Ax2> GeomAx2Ptr;
+
 #endif
index 6e743363c3bcb13816b901238501675be0f22d36..3da31148a9aeeee0be0122fb20e52478d2ac705b 100644 (file)
@@ -94,4 +94,7 @@ public:
 };
 
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Ax3> GeomAx3Ptr;
+
 #endif
\ No newline at end of file
index 63743cc7d06caaa327758599ccf7f7953ad6f019..87662f275a42cdc2e18a4510c50b4bb8ed2621d9 100644 (file)
@@ -56,6 +56,16 @@ 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)>();
+  Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve);
+  if (aCirc.IsNull())
+    throw Standard_ConstructionError("GeomAPI_Circ: Curve is not a circle");
+  setImpl(new gp_Circ(aCirc->Circ()));
+}
+
 //=================================================================================================
 const std::shared_ptr<GeomAPI_Pnt> GeomAPI_Circ::center() const
 {
index 218efd9ff474505ba80fd023090c5e36e1b68801..4fe0c82407f4a8d2e4dcd52e005dff5551a1238f 100644 (file)
@@ -22,6 +22,7 @@
 #define GeomAPI_Circ_H_
 
 #include <GeomAPI_Interface.h>
+#include <GeomAPI_Curve.h>
 #include <memory>
 
 class GeomAPI_Ax2;
@@ -37,7 +38,8 @@ class GeomAPI_Circ : public GeomAPI_Interface
 {
  public:
 
-  /** \brief Constructs a circle of radius Radius, where theAx2 locates the circle and defines its orientation in 3D space such that:\n
+  /** \brief Constructs a circle of radius Radius, where theAx2 locates
+   *  the circle and defines its orientation in 3D space such that:\n
    *  - the center of the circle is the origin of theAx2;\n
    *  - the origin, "X Direction" and "Y Direction" of theAx2 define the plane of the circle;\n
    *  - theAx2 is the local coordinate system of the circle.\n
@@ -50,6 +52,9 @@ class GeomAPI_Circ : public GeomAPI_Interface
   GEOMAPI_EXPORT GeomAPI_Circ(const std::shared_ptr<GeomAPI_Pnt>& theCenter,
                const std::shared_ptr<GeomAPI_Dir>& theDir, double theRadius);
 
+  /// Creation of circle defined by a curve
+  GEOMAPI_EXPORT GeomAPI_Circ(const GeomCurvePtr& theCurve);
+
   /// Return center of the circle
   GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt> center() const;
 
@@ -77,5 +82,8 @@ class GeomAPI_Circ : public GeomAPI_Interface
                                       double& theParameter) const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Circ> GeomCirclePtr;
+
 #endif
 
index 2d942dd7cf5da18decc27817e35ab4dc41a00d9e..70bafd8299240d441fea44ac9f4d8de6a0a73b2c 100644 (file)
@@ -72,4 +72,7 @@ private:
   double myEnd;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Curve> GeomCurvePtr;
+
 #endif
index 9462aabed1abbacf6376df973ee043066165b0ae..7e2a0bda7f0580b04afb36d4f7be963839fdabc0 100644 (file)
@@ -78,5 +78,8 @@ class GeomAPI_Dir : public GeomAPI_Interface
 
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Dir> GeomDirPtr;
+
 #endif
 
index b0ee1e009d191a3c239acbd4cc1fcbdf282aff37..5e72160c5af8b0ce65abf43ac988ae4c9c455325 100644 (file)
@@ -24,6 +24,8 @@
 #include<GeomAPI_Circ.h>
 #include<GeomAPI_Dir.h>
 #include<GeomAPI_Lin.h>
+#include<GeomAPI_Ax2.h>
+#include<GeomAPI_Ellipse.h>
 
 #include <BRepAdaptor_Curve.hxx>
 
 #include <Geom_Curve.hxx>
 #include <Geom_Line.hxx>
 #include <Geom_Circle.hxx>
+#include <Geom_Ellipse.hxx>
 #include <GeomAdaptor_Curve.hxx>
 #include <gp_Ax1.hxx>
 #include <gp_Pln.hxx>
+#include <gp_Elips.hxx>
 
 #include <GCPnts_AbscissaPoint.hxx>
 
@@ -63,6 +67,8 @@ bool GeomAPI_Edge::isLine() const
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
   double aFirst, aLast;
   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+  if (aCurve.IsNull()) // degenerative edge
+    return false;
   if (aCurve->IsKind(STANDARD_TYPE(Geom_Line)))
     return true;
   return false;
@@ -73,6 +79,8 @@ bool GeomAPI_Edge::isCircle() const
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
   double aFirst, aLast;
   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+  if (aCurve.IsNull()) // degenerative edge
+    return false;
   if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle)))
   {
     // Check the difference of first and last parameters to be equal to the curve period
@@ -87,6 +95,8 @@ bool GeomAPI_Edge::isArc() const
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
   double aFirst, aLast;
   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+  if (aCurve.IsNull()) // degenerative edge
+    return false;
   if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle)))
   {
     // Check the difference of first and last parameters is not equal the curve period
@@ -96,6 +106,18 @@ bool GeomAPI_Edge::isArc() const
   return false;
 }
 
+bool GeomAPI_Edge::isEllipse() const
+{
+  const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
+  double aFirst, aLast;
+  Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+  if (aCurve.IsNull()) // degenerative edge
+    return false;
+  if (aCurve->IsKind(STANDARD_TYPE(Geom_Ellipse)))
+    return true;
+  return false;
+}
+
 std::shared_ptr<GeomAPI_Pnt> GeomAPI_Edge::firstPoint()
 {
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
@@ -116,14 +138,14 @@ std::shared_ptr<GeomAPI_Pnt> GeomAPI_Edge::lastPoint()
   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aPoint.X(), aPoint.Y(), aPoint.Z()));
 }
 
-std::shared_ptr<GeomAPI_Circ> GeomAPI_Edge::circle()
+std::shared_ptr<GeomAPI_Circ> GeomAPI_Edge::circle() const
 {
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
   double aFirst, aLast;
   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
-  if (aCurve) {
+  if (!aCurve.IsNull()) {
     Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve);
-    if (aCirc) {
+    if (!aCirc.IsNull()) {
       gp_Pnt aLoc = aCirc->Location();
       std::shared_ptr<GeomAPI_Pnt> aCenter(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
       gp_Dir anAxis = aCirc->Axis().Direction();
@@ -134,7 +156,24 @@ std::shared_ptr<GeomAPI_Circ> GeomAPI_Edge::circle()
   return std::shared_ptr<GeomAPI_Circ>(); // not circle
 }
 
-std::shared_ptr<GeomAPI_Lin> GeomAPI_Edge::line()
+std::shared_ptr<GeomAPI_Ellipse> GeomAPI_Edge::ellipse() const
+{
+  const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
+  double aFirst, aLast;
+  Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+  if (!aCurve.IsNull()) {
+    Handle(Geom_Ellipse) aElips = Handle(Geom_Ellipse)::DownCast(aCurve);
+    if (!aElips.IsNull()) {
+      gp_Elips aGpElips = aElips->Elips();
+      std::shared_ptr<GeomAPI_Ellipse> aEllipse(new GeomAPI_Ellipse());
+      aEllipse->setImpl(new gp_Elips(aGpElips));
+      return aEllipse;
+    }
+  }
+  return std::shared_ptr<GeomAPI_Ellipse>(); // not elipse
+}
+
+std::shared_ptr<GeomAPI_Lin> GeomAPI_Edge::line() const
 {
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
   double aFirst, aLast;
index f4fd1add6163b04950a9f57e8be1c3339bfff4e7..ce0f7b559d18e0f1b9d830af6e6d3d5d94879970 100644 (file)
@@ -27,6 +27,7 @@ class GeomAPI_Pln;
 class GeomAPI_Pnt;
 class GeomAPI_Circ;
 class GeomAPI_Lin;
+class GeomAPI_Ellipse;
 
 /**\class GeomAPI_Edge
 * \ingroup DataModel
@@ -56,6 +57,10 @@ public:
   GEOMAPI_EXPORT
   bool isArc() const;
 
+  /// Verifies that the edge is an arc of circle
+  GEOMAPI_EXPORT
+  bool isEllipse() const;
+
   /// Returns the first vertex coordinates of the edge
   GEOMAPI_EXPORT
   std::shared_ptr<GeomAPI_Pnt> firstPoint();
@@ -66,11 +71,15 @@ public:
 
   /// Returns a circle if edge is based on the circle curve
   GEOMAPI_EXPORT
-  std::shared_ptr<GeomAPI_Circ> circle();
+  std::shared_ptr<GeomAPI_Circ> circle() const;
+
+  /// Returns an ellipse if edge is based on the ellipse curve
+  GEOMAPI_EXPORT
+  std::shared_ptr<GeomAPI_Ellipse> ellipse() const;
 
   /// Returns a line if edge is based on the linear curve
   GEOMAPI_EXPORT
-  std::shared_ptr<GeomAPI_Lin> line();
+  std::shared_ptr<GeomAPI_Lin> line() const;
 
   /// Returns true if the current edge is geometrically equal to the given edge
   GEOMAPI_EXPORT
@@ -97,5 +106,8 @@ public:
   bool isDegenerated() const;
 };
 
+//! Pointer on attribute object
+typedef std::shared_ptr<GeomAPI_Edge> GeomEdgePtr;
+
 #endif
 
diff --git a/src/GeomAPI/GeomAPI_Ellipse.cpp b/src/GeomAPI/GeomAPI_Ellipse.cpp
new file mode 100644 (file)
index 0000000..9c0926a
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        GeomAPI_Ellipse.cpp
+// Created:     25 April 2017
+// Author:      Vitaly Smetannikov
+
+#include "GeomAPI_Ellipse.h"
+#include "GeomAPI_Ax2.h"
+#include "GeomAPI_Pnt.h"
+
+#include <gp_Elips.hxx>
+
+#define MY_ELIPS implPtr<gp_Elips>()
+
+GeomAPI_Ellipse::GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
+                                 double theMajorRadius, double theMinorRadius)
+: GeomAPI_Interface(new gp_Elips(theAx2->impl<gp_Ax2>(), theMajorRadius, theMinorRadius))
+{
+}
+
+std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::center() const
+{
+  const gp_Pnt& aCenter = MY_ELIPS->Location();
+  return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aCenter.X(), aCenter.Y(), aCenter.Z()));
+}
+
+GeomPointPtr GeomAPI_Ellipse::firstFocus() const
+{
+  const gp_Pnt& aFirst = MY_ELIPS->Focus1();
+  return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aFirst.X(), aFirst.Y(), aFirst.Z()));
+}
+
+GeomPointPtr GeomAPI_Ellipse::secondFocus() const
+{
+  const gp_Pnt& aSecond = MY_ELIPS->Focus2();
+  return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aSecond.X(), aSecond.Y(), aSecond.Z()));
+}
+
+double GeomAPI_Ellipse::minorRadius() const
+{
+  return MY_ELIPS->MinorRadius();
+}
+
+double GeomAPI_Ellipse::majorRadius() const
+{
+  return MY_ELIPS->MajorRadius();
+}
diff --git a/src/GeomAPI/GeomAPI_Ellipse.h b/src/GeomAPI/GeomAPI_Ellipse.h
new file mode 100644 (file)
index 0000000..02536b2
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        GeomAPI_Ellipse.h
+// Created:     25 April 2017
+// Author:      Vitaly Smetannikov
+
+#ifndef GeomAPI_Ellipse_H_
+#define GeomAPI_Ellipse_H_
+
+#include <GeomAPI_Interface.h>
+#include <memory>
+
+class GeomAPI_Pnt;
+class GeomAPI_Ax2;
+
+
+/**\class GeomAPI_Ellipse
+ * \ingroup DataModel
+ * \brief Ellipse in 3D
+ */
+class GeomAPI_Ellipse : public GeomAPI_Interface
+{
+public:
+
+  /// \brief Constructs an epty ellipse
+  GEOMAPI_EXPORT GeomAPI_Ellipse() : GeomAPI_Interface() {}
+
+  /** \brief Constructs an ellipse with major and minor radiuses,
+   *  where theAx2 locates the ellipse and defines its orientation in 3D space such that:\n
+   *  - the center of the circle is the origin of theAx2;\n
+   *  - the origin, "X Direction" and "Y Direction" of theAx2 define the plane of the circle;\n
+   *  - theAx2 is the local coordinate system of the circle.\n
+   *    Note: It is possible to create a circle where Radius is equal to 0.0. raised if Radius < 0.
+   */
+  GEOMAPI_EXPORT GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
+                                 double theMajorRadius, double theMinorRadius);
+
+  /// Returns center of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> center() const;
+
+  /// Returns first focus of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> firstFocus() const;
+
+  /// Returns second focus of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> secondFocus() const;
+
+  /// Returns minor radius of the ellipse
+  GEOMAPI_EXPORT double minorRadius() const;
+
+  /// Returns major radius of the ellipse
+  GEOMAPI_EXPORT double majorRadius() const;
+
+};
+
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Ellipse> GeomEllipsePtr;
+
+#endif
diff --git a/src/GeomAPI/GeomAPI_Ellipse2d.cpp b/src/GeomAPI/GeomAPI_Ellipse2d.cpp
new file mode 100644 (file)
index 0000000..d789f71
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        GeomAPI_Ellipse2d.cpp
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <gp_Ax22d.hxx>
+#include <gp_Elips2d.hxx>
+#include <Precision.hxx>
+
+#define MY_ELLIPSE implPtr<gp_Elips2d>()
+
+static gp_Elips2d* newEllipse(const gp_Pnt2d& theCenter,
+                              const gp_Dir2d& theXAxis,
+                              const double theMajorRadius,
+                              const double theMinorRadius)
+{
+  if (theMajorRadius < theMinorRadius - Precision::Confusion()) {
+    return newEllipse(theCenter, gp_Dir2d(-theXAxis.Y(), theXAxis.X()),
+                      theMinorRadius, theMajorRadius);
+  }
+
+  gp_Ax22d anAxis(theCenter, theXAxis);
+  return new gp_Elips2d(anAxis, theMajorRadius, theMinorRadius);
+}
+
+static gp_Elips2d* newEllipse(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                              const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
+                              const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
+{
+  const gp_Pnt2d& aCenter = theCenter->impl<gp_Pnt2d>();
+  const gp_Pnt2d& anAxisPnt = theAxisPoint->impl<gp_Pnt2d>();
+  const gp_Pnt2d& aPassedPnt = thePassingPoint->impl<gp_Pnt2d>();
+
+  gp_Dir2d aXAxis(anAxisPnt.XY() - aCenter.XY());
+  double aMajorRadius = anAxisPnt.Distance(aCenter);
+
+  gp_XY aPassedDir = aPassedPnt.XY() - aCenter.XY();
+
+  double X = aPassedDir.Dot(aXAxis.XY()) / aMajorRadius;
+  if (Abs(X) > 1.0 - Precision::Confusion())
+    return 0; // ellipse cannot be created for such parameters
+
+  double Y = aPassedDir.CrossMagnitude(aXAxis.XY());
+  double aMinorRadius = Y / Sqrt(1. - X * X);
+
+  return newEllipse(aCenter, aXAxis, aMajorRadius, aMinorRadius);
+}
+
+
+GeomAPI_Ellipse2d::GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                     const std::shared_ptr<GeomAPI_Dir2d>& theXAxis,
+                                     const double theMajorRadius,
+                                     const double theMinorRadius)
+  : GeomAPI_Interface(newEllipse(theCenter->impl<gp_Pnt2d>(), theXAxis->impl<gp_Dir2d>(),
+                                 theMajorRadius, theMinorRadius))
+{
+}
+
+GeomAPI_Ellipse2d::GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
+  : GeomAPI_Interface(newEllipse(theCenter, theAxisPoint, thePassingPoint))
+{
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::center() const
+{
+  const gp_Pnt2d& aCenter = MY_ELLIPSE->Location();
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::firstFocus() const
+{
+  const gp_Pnt2d& aFirst = MY_ELLIPSE->Focus1();
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aFirst.X(), aFirst.Y()));
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::secondFocus() const
+{
+  const gp_Pnt2d& aSecond = MY_ELLIPSE->Focus2();
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aSecond.X(), aSecond.Y()));
+}
+
+double GeomAPI_Ellipse2d::minorRadius() const
+{
+  return MY_ELLIPSE->MinorRadius();
+}
+
+double GeomAPI_Ellipse2d::majorRadius() const
+{
+  return MY_ELLIPSE->MajorRadius();
+}
diff --git a/src/GeomAPI/GeomAPI_Ellipse2d.h b/src/GeomAPI/GeomAPI_Ellipse2d.h
new file mode 100644 (file)
index 0000000..ef8840d
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        GeomAPI_Ellipse2d.h
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef GeomAPI_Ellipse2d_H_
+#define GeomAPI_Ellipse2d_H_
+
+#include <GeomAPI_Interface.h>
+
+class GeomAPI_Pnt2d;
+class GeomAPI_Dir2d;
+
+/**\class GeomAPI_Ellipse2d
+ * \ingroup DataModel
+ * \brief Ellipse in 2D
+ */
+class GeomAPI_Ellipse2d : public GeomAPI_Interface
+{
+public:
+  /// \brief Constructs ellipse by center, X-axis and given radii
+  GEOMAPI_EXPORT GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                   const std::shared_ptr<GeomAPI_Dir2d>& theXAxis,
+                                   const double theMajorRadius,
+                                   const double theMinorRadius);
+
+  /// \brief Constructs ellipse by center and two points lying on the ellipse:
+  ///        first of them defines an axis of the ellipse
+  ///        and another is just placed on the ellipse.
+  GEOMAPI_EXPORT GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                   const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
+                                   const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint);
+
+  /// Returns center of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt2d> center() const;
+
+  /// Returns first focus of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt2d> firstFocus() const;
+
+  /// Returns second focus of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt2d> secondFocus() const;
+
+  /// Returns minor radius of the ellipse
+  GEOMAPI_EXPORT double minorRadius() const;
+
+  /// Returns major radius of the ellipse
+  GEOMAPI_EXPORT double majorRadius() const;
+};
+
+#endif
index bff2d17e4994aa328516a277786ba5ea251c9595..e8c91e2e4d17495481cf7226066ba496a026030f 100644 (file)
@@ -84,5 +84,8 @@ class GeomAPI_Lin : public GeomAPI_Interface
   bool isCoplanar(const std::shared_ptr<GeomAPI_Lin> theLin) const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Lin> GeomLinePtr;
+
 #endif
 
index f7950f6f1d8599237bfd883beb8ff33a7db5e51c..60e417c7c5df4d79f6c29ab2f9ecb2c8533f2c86 100644 (file)
@@ -81,18 +81,6 @@ bool GeomAPI_Pln::isCoincident(const std::shared_ptr<GeomAPI_Pln> thePlane,
     aMyPln.Axis().IsParallel(anOtherPln.Axis(), theTolerance));
 }
 
-bool GeomAPI_Pln::isParallel(const std::shared_ptr<GeomAPI_Lin> theLine)
-{
-  std::shared_ptr<GeomAPI_XYZ> aLineDir = theLine->direction()->xyz();
-  std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
-
-  std::shared_ptr<GeomAPI_XYZ> aNormal = direction()->xyz();
-  std::shared_ptr<GeomAPI_XYZ> aLocation = location()->xyz();
-
-  double aDot = aNormal->dot(aLineDir);
-  return Abs(aDot) < Precision::SquareConfusion();
-}
-
 std::shared_ptr<GeomAPI_Pnt>
   GeomAPI_Pln::intersect(const std::shared_ptr<GeomAPI_Lin>& theLine) const
 {
index 4a22b226aac326987c620a4d70cbaf89c80380f0..863a72f617edfe1329eacf23220c0222a08bb000 100644 (file)
@@ -70,10 +70,6 @@ class GeomAPI_Pln : public GeomAPI_Interface
   GEOMAPI_EXPORT
   bool isCoincident(const std::shared_ptr<GeomAPI_Pln> thePlane, const double theTolerance = 1.e-7);
 
-  /// Returns true if plane is parallel to theLine.
-  GEOMAPI_EXPORT
-  bool isParallel(const std::shared_ptr<GeomAPI_Lin> theLine);
-
   /// Returns intersection point or empty if no intersections
   GEOMAPI_EXPORT
   std::shared_ptr<GeomAPI_Pnt> intersect(const std::shared_ptr<GeomAPI_Lin>& theLine) const;
@@ -95,5 +91,8 @@ class GeomAPI_Pln : public GeomAPI_Interface
   std::shared_ptr<GeomAPI_Lin> intersect(const std::shared_ptr<GeomAPI_Pln> thePlane) const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Pln> GeomPlanePtr;
+
 #endif
 
index 3af09c1275ed7e7480adab7d5d78390239c5992d..333a2350acf1dfe8c710e469fd0a1015c80a6dde 100644 (file)
@@ -91,4 +91,7 @@ class GeomAPI_Pnt : public GeomAPI_Interface
   void translate(const std::shared_ptr<GeomAPI_Dir>& theDir, double theDist);
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Pnt> GeomPointPtr;
+
 #endif
index ef633be17ccb9d0836ab3da0d72fc0c34d379535..ac6365a717d3fcdba76937ef82c96c8fc9e21976 100644 (file)
@@ -76,5 +76,8 @@ class GeomAPI_Pnt2d : public GeomAPI_Interface
   bool isEqual(const std::shared_ptr<GeomAPI_Pnt2d>& theOther) const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Pnt2d> GeomPnt2dPtr;
+
 #endif
 
index fd1d6adeb9fc13d4430149af8e9b0ef1b65b8a29..c1df335558bd9f4f7680e158f68a43984bd27619 100644 (file)
@@ -490,3 +490,13 @@ bool GeomAPI_Shape::isIntersect(const GeomShapePtr theShape) const
 
   return false;
 }
+
+void GeomAPI_Shape::translate(const std::shared_ptr<GeomAPI_Dir> theDir, const double theOffset)
+{
+  gp_Dir aDir = theDir->impl<gp_Dir>();
+  gp_Vec aTrsfVec(aDir.XYZ() * theOffset);
+  gp_Trsf aTranslation;
+  aTranslation.SetTranslation(aTrsfVec);
+  TopoDS_Shape aResult = MY_SHAPE->Moved(aTranslation);
+  setImpl(new TopoDS_Shape(aResult));
+}
index c7345461bd6a3bebfaea24509edfbb77ebc3c133..4e148978cd162140c5b9316ebd6ef0e5d89c9c6a 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef GeomAPI_Shape_H_
 #define GeomAPI_Shape_H_
 
+#include "GeomAPI_Dir.h"
+
 #include <GeomAPI_Interface.h>
 #include <memory>
 #include <list>
@@ -142,6 +144,10 @@ public:
   /// Returns true if min distance between shapes < tolerance.
   GEOMAPI_EXPORT
   bool isIntersect(const std::shared_ptr<GeomAPI_Shape> theShape) const;
+
+  // Translates the shape along the direction for the given offset
+  GEOMAPI_EXPORT
+  void translate(const std::shared_ptr<GeomAPI_Dir> theDir, const double theOffset);
 };
 
 //! Pointer on list of shapes
index 62160593b935e3133bf0bb59d7cf44c2f0df4160..cee8fd66b36bc45a441ed254c957750c0a48d9fa 100644 (file)
@@ -52,5 +52,8 @@ public:
   bool isEqual(const std::shared_ptr<GeomAPI_Shape> theVert) const;
 };
 
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Vertex> GeomVertexPtr;
+
 #endif
 
index 163d4643a33d14bf63e8848bed9cc2f03666d94f..ed0914e1b2810876513980be43ece8de05342e6b 100644 (file)
@@ -222,3 +222,23 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::lineCircleArc(
   }
   return aRes;
 }
+
+std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipse(
+    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 gp_Pnt& aCenter = theCenter->impl<gp_Pnt>();
+  const gp_Dir& aNormal = theNormal->impl<gp_Dir>();
+  const gp_Dir& aMajorAxis = theMajorAxis->impl<gp_Dir>();
+
+  gp_Elips anEllipse(gp_Ax2(aCenter, aNormal, aMajorAxis), theMajorRadius, theMinorRadius);
+
+  BRepBuilderAPI_MakeEdge anEdgeBuilder(anEllipse);
+  std::shared_ptr<GeomAPI_Edge> aRes(new GeomAPI_Edge);
+  TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+  aRes->setImpl(new TopoDS_Shape(anEdge));
+  return aRes;
+}
index e063e2b29d217d490044c7b56b68318d970108f7..22c248d97bfd412b237fe6ee8416c7a55ca7fad4 100644 (file)
@@ -72,6 +72,13 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder
                                                        std::shared_ptr<GeomAPI_Pnt> theStartPoint,
                                                        std::shared_ptr<GeomAPI_Pnt> theEndPoint,
                                                        std::shared_ptr<GeomAPI_Dir> theNormal);
+
+  /// Creates elliptic edge
+  static std::shared_ptr<GeomAPI_Edge> ellipse(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);
 };
 
 #endif
index 197569345369b4f7940438fd77cb795223639e05..7fcdc7a0e9ecbddcc8eae633ddc8f3498cecf3f7 100644 (file)
@@ -43,6 +43,7 @@
 #include <BRepGProp.hxx>
 #include <BRepTools.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
+#include <BRepClass_FaceClassifier.hxx>
 #include <Geom2d_Curve.hxx>
 #include <Geom2d_Curve.hxx>
 #include <BRepLib_CheckCurveOnSurface.hxx>
@@ -50,6 +51,7 @@
 #include <Geom_Plane.hxx>
 #include <GeomLib_IsPlanarSurface.hxx>
 #include <GeomLib_Tool.hxx>
+#include <GeomAPI_ExtremaCurveSurface.hxx>
 #include <gp_Pln.hxx>
 #include <GProp_GProps.hxx>
 #include <IntAna_IntConicQuad.hxx>
@@ -67,6 +69,7 @@
 #include <TopExp_Explorer.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 
+
 #include <BOPAlgo_Builder.hxx>
 #include <BRepBuilderAPI_MakeVertex.hxx>
 #include <TopoDS_Edge.hxx>
@@ -743,6 +746,50 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theE
   return anExt.IsParallel() == Standard_True;
 }
 
+//==================================================================================================
+std::shared_ptr<GeomAPI_Vertex> GeomAlgoAPI_ShapeTools::intersect(
+  const std::shared_ptr<GeomAPI_Edge> theEdge, const std::shared_ptr<GeomAPI_Face> theFace)
+{
+  if(!theEdge.get() || !theFace.get()) {
+    return std::shared_ptr<GeomAPI_Vertex>();
+  }
+
+  TopoDS_Edge anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
+  double aFirstOnCurve, aLastOnCurve;
+  Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirstOnCurve, aLastOnCurve);
+
+  TopoDS_Face aFace  = TopoDS::Face(theFace->impl<TopoDS_Shape>());
+  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
+
+  GeomAPI_ExtremaCurveSurface anExt(aCurve, aSurf);
+  // searching for the best point-intersection
+  int aMaxLevel = 0;
+  gp_Pnt aResult;
+  for(int anIntNum = 1; anIntNum <= anExt.NbExtrema(); anIntNum++) {
+    if (anExt.Distance(anIntNum) > Precision::Confusion())
+      continue;
+    Standard_Real aW, aU, aV;
+    anExt.Parameters(anIntNum, aW, aU, aV);
+    gp_Pnt2d aPointOfSurf(aU, aV);
+    // level of the intersection: if it is inside of edge and/or face the level is higher
+    int aIntLevel = aW > aFirstOnCurve && aW < aLastOnCurve ? 2 : 1;
+    BRepClass_FaceClassifier aFClass(aFace, aPointOfSurf, Precision::Confusion());
+    if (aFClass.State() == TopAbs_IN) // "in" is better than "on"
+      aIntLevel += 2;
+    else if (aFClass.State() == TopAbs_ON)
+      aIntLevel += 1;
+    if (aMaxLevel < aIntLevel) {
+      aMaxLevel = anIntNum;
+      anExt.Points(anIntNum, aResult, aResult);
+    }
+  }
+  if (aMaxLevel > 0) { // intersection found
+    return std::shared_ptr<GeomAPI_Vertex>(
+      new GeomAPI_Vertex(aResult.X(), aResult.Y(), aResult.Z()));
+  }
+  return std::shared_ptr<GeomAPI_Vertex>(); // no intersection found
+}
+
 //==================================================================================================
 void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
                                       const GeomAlgoAPI_ShapeTools::PointToRefsMap& thePointsInfo,
index ba530ebd5567da8b6e8dad1fbe974943f48250b3..2e48c96bbf61ee8cb28585d49976fa56a06370c5 100644 (file)
@@ -133,6 +133,12 @@ public:
   GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
                                             const std::shared_ptr<GeomAPI_Face> theFace);
 
+  // Computes intersection point between the edge curve and a face surface (only one point, with
+  // preferences to point that belongs to edge and face boundaries.
+  /// \returns null if there is no intersection
+  GEOMALGOAPI_EXPORT static std::shared_ptr<GeomAPI_Vertex> intersect(
+    const std::shared_ptr<GeomAPI_Edge> theEdge, const std::shared_ptr<GeomAPI_Face> theFace);
+
   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;
index 0d10a4b15f9e50c6deff99df5c896fc929e13129..5d4781494052ee0537e05832c291c8482f9b5397 100644 (file)
@@ -141,6 +141,7 @@ FeaturePtr InitializationPlugin_Plugin::createPoint(DocumentPtr theDoc, const st
   aPoint->real("x")->setValue(theX);
   aPoint->real("y")->setValue(theY);
   aPoint->real("z")->setValue(theZ);
+  aPoint->string("creation_method")->setValue("by_xyz");
   aPoint->data()->setName(theName);
   // don't show automatically created feature in the features history
   aPoint->setInHistory(aPoint, false);
index f26270a9fcbe8109f7cbe30112e849caf40dfff4..15d910ede504ec9add4d72d034a11497e94fa5f8 100644 (file)
@@ -72,6 +72,13 @@ Standard_GUID kPART_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb27");
 // selection is invalid after recomputation
 Standard_GUID kINVALID_SELECTION("bce47fd7-80fa-4462-9d63-2f58acddd49d");
 
+// identifier of the selection of the center of circle on edge
+Standard_GUID kCIRCLE_CENTER("d0d0e0f1-217a-4b95-8fbb-0c4132f23718");
+// identifier of the selection of the first focus point of ellipse on edge
+Standard_GUID kELLIPSE_CENTER1("f70df04c-3168-4dc9-87a4-f1f840c1275d");
+// identifier of the selection of the second focus point of ellipse on edge
+Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32");
+
 // on this label is stored:
 // TNaming_NamedShape - selected shape
 // TNaming_Naming - topological selection information (for the body)
@@ -89,6 +96,7 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
   } else {
     myTmpContext.reset();
     myTmpSubShape.reset();
+    myTmpCenterType = NOT_CENTER;
   }
 
   const std::shared_ptr<GeomAPI_Shape>& anOldShape = value();
@@ -105,6 +113,9 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
   TDF_Label aSelLab = selectionLabel();
   aSelLab.ForgetAttribute(kSIMPLE_REF_ID);
   aSelLab.ForgetAttribute(kINVALID_SELECTION);
+  aSelLab.ForgetAttribute(kCIRCLE_CENTER);
+  aSelLab.ForgetAttribute(kELLIPSE_CENTER1);
+  aSelLab.ForgetAttribute(kELLIPSE_CENTER2);
 
   bool isDegeneratedEdge = false;
   // do not use the degenerated edge as a shape, a null context and shape is used in the case
@@ -148,6 +159,31 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
   owner()->data()->sendAttributeUpdated(this);
 }
 
+void Model_AttributeSelection::setValueCenter(
+    const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Edge>& theEdge,
+    const CenterType theCenterType, const bool theTemporarily)
+{
+  setValue(theContext, theEdge, theTemporarily);
+  if (theTemporarily) {
+    myTmpCenterType = theCenterType;
+  } else { // store in the data structure
+    TDF_Label aSelLab = selectionLabel();
+    switch(theCenterType) {
+    case CIRCLE_CENTER:
+      TDataStd_UAttribute::Set(aSelLab, kCIRCLE_CENTER);
+      break;
+    case ELLIPSE_FIRST_FOCUS:
+      TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER1);
+      break;
+    case ELLIPSE_SECOND_FOCUS:
+      TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER2);
+      break;
+    }
+    owner()->data()->sendAttributeUpdated(this);
+  }
+}
+
+
 void Model_AttributeSelection::removeTemporaryValues()
 {
   if (myTmpContext.get() || myTmpSubShape.get()) {
@@ -156,10 +192,55 @@ void Model_AttributeSelection::removeTemporaryValues()
   }
 }
 
+// returns the center of the edge: circular or elliptical
+GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::CenterType theType)
+{
+  if (theType != ModelAPI_AttributeSelection::NOT_CENTER && theEdge.get() != NULL) {
+    TopoDS_Shape aShape = theEdge->impl<TopoDS_Shape>();
+    if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_EDGE) {
+      TopoDS_Edge anEdge = TopoDS::Edge(aShape);
+      double aFirst, aLast;
+      Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+      if (!aCurve.IsNull()) {
+        TopoDS_Vertex aVertex;
+        BRep_Builder aBuilder;
+        if (theType == ModelAPI_AttributeSelection::CIRCLE_CENTER) {
+          Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve);
+          if (!aCirc.IsNull()) {
+            aBuilder.MakeVertex(aVertex, aCirc->Location(), Precision::Confusion());
+          }
+        } else { // ellipse
+          Handle(Geom_Ellipse) anEll = Handle(Geom_Ellipse)::DownCast(aCurve);
+          if (!anEll.IsNull()) {
+            aBuilder.MakeVertex(aVertex,
+              theType == ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS ?
+              anEll->Focus1() : anEll->Focus2(), Precision::Confusion());
+          }
+        }
+        if (!aVertex.IsNull()) {
+          std::shared_ptr<GeomAPI_Vertex> aResult(new GeomAPI_Vertex);
+          aResult->setImpl(new TopoDS_Vertex(aVertex));
+          return aResult;
+        }
+      }
+    }
+  }
+  return theEdge; // no vertex, so, return the initial edge
+}
+
 std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
 {
+  CenterType aType = NOT_CENTER;
+  std::shared_ptr<GeomAPI_Shape> aResult = internalValue(aType);
+  return centerByEdge(aResult, aType);
+}
+
+std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::internalValue(CenterType& theType)
+{
+  theType = NOT_CENTER;
   GeomShapePtr aResult;
   if (myTmpContext.get() || myTmpSubShape.get()) {
+    theType = myTmpCenterType;
     ResultConstructionPtr aResulConstruction =
       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myTmpContext);
     if(aResulConstruction.get()) {
@@ -173,6 +254,14 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
   if (aSelLab.IsAttribute(kINVALID_SELECTION))
     return aResult;
 
+  if (aSelLab.IsAttribute(kCIRCLE_CENTER))
+    theType = CIRCLE_CENTER;
+  else if (aSelLab.IsAttribute(kELLIPSE_CENTER1))
+    theType = ELLIPSE_FIRST_FOCUS;
+  else if (aSelLab.IsAttribute(kELLIPSE_CENTER2))
+    theType = ELLIPSE_SECOND_FOCUS;
+
+
   if (myRef.isInitialized()) {
     if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
       ResultPtr aContext = context();
@@ -209,6 +298,7 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
       TopoDS_Shape aSelShape = aSelection->Get();
       aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
       aResult->setImpl(new TopoDS_Shape(aSelShape));
+      return aResult;
     } else { // for simple construction element: just shape of this construction element
       std::shared_ptr<Model_ResultConstruction> aConstr =
         std::dynamic_pointer_cast<Model_ResultConstruction>(context());
@@ -610,21 +700,56 @@ TDF_Label Model_AttributeSelection::selectionLabel()
   return myRef.myRef->Label().FindChild(1);
 }
 
+/// prefixes of the shape names with centers defined
+static std::map<ModelAPI_AttributeSelection::CenterType, std::string> kCENTERS_PREFIX;
+
+/// returns the map that contains all possible prefixes of the center-names
+static std::map<ModelAPI_AttributeSelection::CenterType, std::string>& centersMap()
+{
+  if (kCENTERS_PREFIX.empty()) { // fill map by initial values
+    kCENTERS_PREFIX[ModelAPI_AttributeSelection::CIRCLE_CENTER] = "__cc";
+    kCENTERS_PREFIX[ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS] = "__eff";
+    kCENTERS_PREFIX[ModelAPI_AttributeSelection::ELLIPSE_SECOND_FOCUS] = "__esf";
+  }
+  return kCENTERS_PREFIX;
+}
+
 std::string Model_AttributeSelection::namingName(const std::string& theDefaultName)
 {
   std::string aName("");
   if(!this->isInitialized())
     return !theDefaultName.empty() ? theDefaultName : aName;
 
-  std::shared_ptr<GeomAPI_Shape> aSubSh = value();
+  CenterType aCenterType = NOT_CENTER;
+  std::shared_ptr<GeomAPI_Shape> aSubSh = internalValue(aCenterType);
   ResultPtr aCont = context();
 
   if (!aCont.get()) // in case of selection of removed result
     return "";
 
   Model_SelectionNaming aSelNaming(selectionLabel());
-  return aSelNaming.namingName(
+  std::string aResult = aSelNaming.namingName(
     aCont, aSubSh, theDefaultName, owner()->document() != aCont->document());
+  if (aCenterType != NOT_CENTER) {
+    aResult += centersMap()[aCenterType];
+  }
+  return aResult;
+}
+
+// returns the center type and modifies the shape name if this name is center-name
+static ModelAPI_AttributeSelection::CenterType centerTypeByName(std::string& theShapeName)
+{
+  std::map<ModelAPI_AttributeSelection::CenterType, std::string>::iterator aPrefixIter =
+    centersMap().begin();
+  for(; aPrefixIter != centersMap().end(); aPrefixIter++) {
+    std::size_t aFound = theShapeName.find(aPrefixIter->second);
+    if (aFound != std::string::npos &&
+        aFound == theShapeName.size() - aPrefixIter->second.size()) {
+      theShapeName = theShapeName.substr(0, aFound);
+      return aPrefixIter->first;
+    }
+  }
+  return ModelAPI_AttributeSelection::NOT_CENTER;
 }
 
 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
@@ -633,54 +758,81 @@ void Model_AttributeSelection::selectSubShape(
 {
   if(theSubShapeName.empty() || theType.empty()) return;
 
-  // check this is Part-name: 2 delimiters in the name
-  std::size_t aPartEnd = theSubShapeName.find('/');
-  if (aPartEnd != std::string::npos && aPartEnd != theSubShapeName.rfind('/')) {
-    std::string aPartName = theSubShapeName.substr(0, aPartEnd);
-    ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
-    if (aFound.get()) { // found such part, so asking it for the name
-      ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFound);
-      std::string aNameInPart = theSubShapeName.substr(aPartEnd + 1);
-      int anIndex;
-      std::shared_ptr<GeomAPI_Shape> aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex);
-      if (aSelected.get()) {
-        setValue(aPart, aSelected);
-        TDataStd_Integer::Set(selectionLabel(), anIndex);
-        return;
+  std::string aSubShapeName = theSubShapeName;
+  CenterType aCenterType = theType[0] == 'v' || theType[0] == 'V' ? // only for vertex-type
+    centerTypeByName(aSubShapeName) : NOT_CENTER;
+  std::string aType = aCenterType == NOT_CENTER ? theType : "EDGE"; // search for edge now
+
+  // first iteration is selection by name without center prefix, second - in case of problem,
+  // try with initial name
+  for(int aUseCenter = 1; aUseCenter >= 0; aUseCenter--) {
+    if (aUseCenter == 0 && aCenterType != NOT_CENTER) {
+      aSubShapeName = theSubShapeName;
+      aCenterType = NOT_CENTER;
+      aType = theType;
+    } else if (aUseCenter != 1) continue;
+
+    // check this is Part-name: 2 delimiters in the name
+    std::size_t aPartEnd = aSubShapeName.find('/');
+    if (aPartEnd != std::string::npos && aPartEnd != aSubShapeName.rfind('/')) {
+      std::string aPartName = aSubShapeName.substr(0, aPartEnd);
+      ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
+      if (aFound.get()) { // found such part, so asking it for the name
+        ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFound);
+        std::string aNameInPart = aSubShapeName.substr(aPartEnd + 1);
+        int anIndex;
+        std::shared_ptr<GeomAPI_Shape> aSelected = aPart->shapeInPart(aNameInPart, aType, anIndex);
+        if (aSelected.get()) {
+          if (aCenterType != NOT_CENTER) {
+            if (!aSelected->isEdge())
+              continue;
+            std::shared_ptr<GeomAPI_Edge> aSelectedEdge(new GeomAPI_Edge(aSelected));
+            setValueCenter(aPart, aSelectedEdge, aCenterType);
+          } else
+            setValue(aPart, aSelected);
+          TDataStd_Integer::Set(selectionLabel(), anIndex);
+          return;
+        }
       }
     }
-  }
 
-  Model_SelectionNaming aSelNaming(selectionLabel());
-  std::shared_ptr<Model_Document> aDoc =
-    std::dynamic_pointer_cast<Model_Document>(owner()->document());
-  std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected;
-  ResultPtr aCont;
-  if (aSelNaming.selectSubShape(theType, theSubShapeName, aDoc, aShapeToBeSelected, aCont)) {
-    // try to find the last context to find the up to date shape
-    if (aCont->shape().get() && !aCont->shape()->isNull() &&
-      aCont->groupName() == ModelAPI_ResultBody::group() && aDoc == owner()->document()) {
-      const TopoDS_Shape aConShape = aCont->shape()->impl<TopoDS_Shape>();
-      if (!aConShape.IsNull()) {
-        Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aConShape, selectionLabel());
-        if (!aNS.IsNull()) {
-          aNS = TNaming_Tool::CurrentNamedShape(aNS);
+    Model_SelectionNaming aSelNaming(selectionLabel());
+    std::shared_ptr<Model_Document> aDoc =
+      std::dynamic_pointer_cast<Model_Document>(owner()->document());
+    std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected;
+    ResultPtr aCont;
+    if (aSelNaming.selectSubShape(aType, aSubShapeName, aDoc, aShapeToBeSelected, aCont)) {
+      // try to find the last context to find the up to date shape
+      if (aCont->shape().get() && !aCont->shape()->isNull() &&
+        aCont->groupName() == ModelAPI_ResultBody::group() && aDoc == owner()->document()) {
+        const TopoDS_Shape aConShape = aCont->shape()->impl<TopoDS_Shape>();
+        if (!aConShape.IsNull()) {
+          Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aConShape, selectionLabel());
           if (!aNS.IsNull() && scope().Contains(aNS->Label())) { // scope check is for 2228
-            TDF_Label aLab = aNS->Label();
-            while(aLab.Depth() != 7 && aLab.Depth() > 5)
-              aLab = aLab.Father();
-            ObjectPtr anObj = aDoc->objects()->object(aLab);
-            if (anObj.get()) {
-              ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
-              if (aRes)
-                aCont = aRes;
+            aNS = TNaming_Tool::CurrentNamedShape(aNS);
+            if (!aNS.IsNull()) {
+              TDF_Label aLab = aNS->Label();
+              while(aLab.Depth() != 7 && aLab.Depth() > 5)
+                aLab = aLab.Father();
+              ObjectPtr anObj = aDoc->objects()->object(aLab);
+              if (anObj.get()) {
+                ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
+                if (aRes)
+                  aCont = aRes;
+              }
             }
           }
         }
       }
+      if (aCenterType != NOT_CENTER) {
+        if (!aShapeToBeSelected->isEdge())
+          continue;
+        std::shared_ptr<GeomAPI_Edge> aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected));
+        setValueCenter(aCont, aSelectedEdge, aCenterType);
+      } else
+        setValue(aCont, aShapeToBeSelected);
+      return;
     }
-    setValue(aCont, aShapeToBeSelected);
-    return;
   }
 
   TDF_Label aSelLab = selectionLabel();
index 06d0d3102084d12ec3f791d72f62f95809952bbc..5011bdce420ccde489bded88f141932b5fdaa673 100644 (file)
@@ -43,6 +43,8 @@ class Model_AttributeSelection : public ModelAPI_AttributeSelection
   ResultPtr myTmpContext;
   /// temporarily storages to avoid keeping in the data structure if not needed
   std::shared_ptr<GeomAPI_Shape> myTmpSubShape;
+  /// temporarily storages to avoid keeping in the data structure if not needed
+  CenterType myTmpCenterType;
   /// Reference to the partent attribute, if any (to split selection compounds in issue 1799)
   Model_AttributeSelectionList* myParent;
 public:
@@ -55,6 +57,13 @@ public:
     const ResultPtr& 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)
+  /// and stores the vertex of the central point (for ellipse the first or the second focus point)
+  MODEL_EXPORT virtual void setValueCenter(
+    const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Edge>& theEdge,
+    const CenterType theCenterType,
+    const bool theTemporarily = false);
+
   /// Reset temporary stored values
   virtual void removeTemporaryValues();
 
@@ -103,6 +112,13 @@ protected:
   /// Objects are created for features automatically
   MODEL_EXPORT Model_AttributeSelection(TDF_Label& theLabel);
 
+  /// Returns the selected subshape, internal method that works without knowledge
+  /// about special selection of circle and ellipse focuses (for that the public value
+  /// method calls this and makes additional processing).
+  /// Returns theType type of the center, or NOT_CENTER if it is not.
+  std::shared_ptr<GeomAPI_Shape> internalValue(CenterType& theType);
+
+
   /// Performs the selection for the body result (TNaming Selection)
 
   /// Performs the selection for the body result (TNaming selection)
index 0e9e5e2e421aa258e85c6cc058839cbb5a08b44d..bdd120bff2a31af03547168b7d880cc1b6ef6bc4 100644 (file)
@@ -112,6 +112,7 @@ SET(PROJECT_SOURCES
 
 SET(PROJECT_LIBRARIES
     Config
+    GeomAPI
 )
 SET(CMAKE_SWIG_FLAGS -threads -Wall)
 ADD_DEFINITIONS(-DMODELAPI_EXPORTS)
index 74802c858a77361e7bc691fa5a97e08701da7549..44eace64ffbba7793492591b684aef5ba9d4193e 100644 (file)
@@ -24,6 +24,8 @@
 #include "ModelAPI_Attribute.h"
 #include <ModelAPI_Result.h>
 
+class GeomAPI_Edge;
+
 /**\class ModelAPI_AttributeSelection
  * \ingroup DataModel
  * \brief Attribute that contains reference to the sub-shape of some result, the selected shape.
 class ModelAPI_AttributeSelection : public ModelAPI_Attribute
 {
  public:
+   /// Type of the center of the circular of elliptical edge
+   enum CenterType {
+     NOT_CENTER, ///< this is not a center
+     CIRCLE_CENTER, ///< center of the circle
+     ELLIPSE_FIRST_FOCUS, ///< first focus point of the ellipse
+     ELLIPSE_SECOND_FOCUS, ///< second focus point of the ellipse
+   };
+
   /// Defines the result and its selected sub-shape
   /// \param theContext object where the sub-shape was selected
   /// \param theSubShape selected sub-shape (if null, the whole context is selected)
@@ -41,6 +51,13 @@ class ModelAPI_AttributeSelection : public ModelAPI_Attribute
     const ResultPtr& 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)
+  /// and stores the vertex of the central point (for ellipse the first or the second focus point)
+  virtual void setValueCenter(
+    const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Edge>& theEdge,
+    const CenterType theCenterType,
+    const bool theTemporarily = false) = 0;
+
   /// Reset temporary stored values
   virtual void removeTemporaryValues() = 0;
 
index c660afca2965748dd5c759be5b64ae5ba3e4ed73..0a425d8c2eb5e67a4e558c2c9759ce6667633009 100644 (file)
 #include <ModelAPI.h>
 #include <ModelAPI_Events.h>
 
+#include <GeomAPI_Pnt2d.h>
+
+//#define DEBUG_OBJECT_MOVED_MESSAGE
+#ifdef DEBUG_OBJECT_MOVED_MESSAGE
+#include <iostream>
+#endif
+
 ModelAPI_ObjectUpdatedMessage::ModelAPI_ObjectUpdatedMessage(const Events_ID theID,
                                                              const void* theSender)
     : Events_MessageGroup(theID, theSender)
@@ -338,3 +345,64 @@ const std::set<ObjectPtr>& ModelAPI_SolverFailedMessage::objects() const
 {
   return myObjects;
 }
+
+
+// =====   ModelAPI_ObjectMovedMessage   =====
+ModelAPI_ObjectMovedMessage::ModelAPI_ObjectMovedMessage(const void* theSender)
+  : Events_Message(Events_Loop::eventByName(EVENT_OBJECT_MOVED), theSender)
+{
+}
+
+void ModelAPI_ObjectMovedMessage::setMovedObject(const ObjectPtr& theMovedObject)
+{
+  myMovedObject = theMovedObject;
+  myMovedAttribute = AttributePtr();
+}
+
+void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute)
+{
+  myMovedAttribute = theMovedAttribute;
+  myMovedObject = ObjectPtr();
+}
+
+void ModelAPI_ObjectMovedMessage::setOriginalPosition(double theX, double theY)
+{
+  myOriginalPosition = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(theX, theY));
+#ifdef DEBUG_OBJECT_MOVED_MESSAGE
+  std::cout << "setOriginalPosition: " << myOriginalPosition->x() << ", "
+                                       << myOriginalPosition->y() << std::endl;
+#endif
+}
+
+void ModelAPI_ObjectMovedMessage::setOriginalPosition(
+    const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+  myOriginalPosition = thePoint;
+#ifdef DEBUG_OBJECT_MOVED_MESSAGE
+  std::cout << "setOriginalPosition: " << myOriginalPosition->x() << ", "
+                                       << myOriginalPosition->y() << std::endl;
+#endif
+}
+
+void ModelAPI_ObjectMovedMessage::setCurrentPosition(double theX, double theY)
+{
+  myCurrentPosition = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(theX, theY));
+#ifdef DEBUG_OBJECT_MOVED_MESSAGE
+  std::cout << "setCurrentPosition: " << myCurrentPosition->x() << ", " << myCurrentPosition->y()
+            << ", myCurrentPosition - myOriginalPosition: "
+            << myCurrentPosition->x() - myOriginalPosition->x() << ", "
+            << myCurrentPosition->y() - myOriginalPosition->y() << std::endl;
+#endif
+}
+
+void ModelAPI_ObjectMovedMessage::setCurrentPosition(
+    const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+  myCurrentPosition = thePoint;
+#ifdef DEBUG_OBJECT_MOVED_MESSAGE
+  std::cout << "setCurrentPosition: " << myCurrentPosition->x() << ", " << myCurrentPosition->y()
+            << ", myCurrentPosition - myOriginalPosition: "
+            << myCurrentPosition->x() - myOriginalPosition->x() << ", "
+            << myCurrentPosition->y() - myOriginalPosition->y() << std::endl;
+#endif
+}
index 1d69e38a961c276967a8ebedb1c5b2e745eb2477..a7718d1de11721eaa0106e359d2666d62bc4b776 100644 (file)
@@ -36,6 +36,7 @@
 
 class ModelAPI_Document;
 class ModelAPI_ResultParameter;
+class GeomAPI_Pnt2d;
 
 /// Event ID that feature is created (comes with ModelAPI_ObjectUpdatedMessage)
 static const char * EVENT_OBJECT_CREATED = "ObjectCreated";
@@ -467,4 +468,46 @@ private:
   int myDOF;
 };
 
+/// Message sent when feature or attrubute has been moved.
+/// Stores the moving object/attribute, original and new positions of mouse.
+class ModelAPI_ObjectMovedMessage : public Events_Message
+{
+  ObjectPtr myMovedObject;
+  AttributePtr myMovedAttribute;
+
+  std::shared_ptr<GeomAPI_Pnt2d> myOriginalPosition;
+  std::shared_ptr<GeomAPI_Pnt2d> myCurrentPosition;
+
+public:
+  MODELAPI_EXPORT ModelAPI_ObjectMovedMessage(const void* theSender = 0);
+
+  /// Set object which is being moved (if the message already contains attribute it will be cleared)
+  MODELAPI_EXPORT void setMovedObject(const ObjectPtr& theMovedObject);
+  /// Set attribute which is being moved (if the message already contains object it will be cleared)
+  MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute);
+
+  /// Return moved object
+  ObjectPtr movedObject() const
+  { return myMovedObject; }
+  /// Return moved attribute
+  AttributePtr movedAttribute() const
+  { return myMovedAttribute; }
+
+  /// Set original mouse position
+  MODELAPI_EXPORT void setOriginalPosition(double theX, double theY);
+  /// Set original mouse position
+  MODELAPI_EXPORT void setOriginalPosition(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+  /// Return original mouse position
+  const std::shared_ptr<GeomAPI_Pnt2d>& originalPosition() const
+  { return myOriginalPosition; }
+
+  /// Set current mouse position
+  MODELAPI_EXPORT void setCurrentPosition(double theX, double theY);
+  /// Set current mouse position
+  MODELAPI_EXPORT void setCurrentPosition(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+  /// Return current mouse position
+  const std::shared_ptr<GeomAPI_Pnt2d>& currentPosition() const
+  { return myCurrentPosition; }
+};
+
 #endif
index 34aa535eb849f5a4b54ee200908efdcda0b50cb4..5f748b665f9164a2869d6491cfef6a7db078956d 100644 (file)
@@ -32,6 +32,7 @@ aFeature = aDoc.addFeature("Point")
 aFeature.real("x").setValue(1.)
 aFeature.real("y").setValue(-1.)
 aFeature.real("z").setValue(0.)
+aFeature.string("creation_method").setValue("by_xyz")
 aFeatureName = aFeature.name()
 # "2" is because Origin is the first point
 assert(aFeatureName == "Point_2")
index 5b09cc980fab7b581f1dc1a2198e3b87829d075f..7010d848143a09e50c63e061a6426e09b2fa5984 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_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
     if (temp_attribute) {
     } else {
       $1 = 0;
     }
+  } else if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+    if (temp_selection) {
+      $1 = 1;
+    } else {
+      $1 = 0;
+    }
   } else {
     $1 = 0;
   }
index ad32819b320aa9528358a2228f7daf5366328466..d018517e23f8262bff3c073c0f4e05bc7dd673e0 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_Events.h>
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Result.h>
 #include "ModelHighAPI_Interface.h"
@@ -81,3 +82,13 @@ bool ModelHighAPI_RefAttr::isEmpty() const
 {
   return !(myAttribute && myObject);
 }
+
+//--------------------------------------------------------------------------------------
+void ModelHighAPI_RefAttr::fillMessage(
+    const std::shared_ptr<ModelAPI_ObjectMovedMessage>& theMessage) const
+{
+  switch (myVariantType) {
+  case VT_ATTRIBUTE: theMessage->setMovedAttribute(myAttribute); return;
+  case VT_OBJECT: theMessage->setMovedObject(myObject); return;
+  }
+}
index 7c1bbd6e817f5f481de0ee07f7ca563d0e602ffd..feb9edfdc6124f809975c2bcafa78666e8bc51bb 100644 (file)
@@ -31,6 +31,7 @@ class ModelAPI_Attribute;
 class ModelAPI_AttributeRefAttr;
 class ModelAPI_AttributeRefAttrList;
 class ModelAPI_Object;
+class ModelAPI_ObjectMovedMessage;
 class ModelHighAPI_Interface;
 //--------------------------------------------------------------------------------------
 /**\class ModelHighAPI_RefAttr
@@ -68,6 +69,10 @@ public:
   MODELHIGHAPI_EXPORT
   bool isEmpty() const;
 
+  /// Fill moved message by the attribute or object
+  MODELHIGHAPI_EXPORT
+  void fillMessage(const std::shared_ptr<ModelAPI_ObjectMovedMessage>& theMessage) const;
+
 private:
   enum VariantType { VT_ATTRIBUTE, VT_OBJECT } myVariantType;
   std::shared_ptr<ModelAPI_Attribute> myAttribute;
index e70fcbb8137fecfcc11e867a21897812bb7ca5b2..a9c27367fe427b41fd6a0b0bcc29de33cfaebb79 100644 (file)
@@ -57,7 +57,8 @@ ModuleBase_WidgetEditor::~ModuleBase_WidgetEditor()
 {
 }
 
-bool ModuleBase_WidgetEditor::editedValue(double& outValue, QString& outText)
+bool ModuleBase_WidgetEditor::editedValue(double theSpinMinValue, double theSpinMaxValue,
+                                          double& outValue, QString& outText)
 {
   bool isValueAccepted = false;
 
@@ -67,8 +68,8 @@ bool ModuleBase_WidgetEditor::editedValue(double& outValue, QString& outText)
   aLay->setContentsMargins(2, 2, 2, 2);
 
   ModuleBase_ParamSpinBox* anEditor = new ModuleBase_ParamSpinBox(myEditorDialog);
-  anEditor->setMinimum(0);
-  anEditor->setMaximum(DBL_MAX);
+  anEditor->setMinimum(theSpinMinValue);
+  anEditor->setMaximum(theSpinMaxValue);
   if (outText.isEmpty())
     anEditor->setValue(outValue);
   else
@@ -123,7 +124,7 @@ bool ModuleBase_WidgetEditor::showPopupEditor(const bool theSendSignals)
   if (mySpinBox->hasVariable())
     aText = mySpinBox->text();
 
-  isValueAccepted = editedValue(aValue, aText);
+  isValueAccepted = editedValue(mySpinBox->minimum(), mySpinBox->maximum(), aValue, aText);
   if (isValueAccepted) {
     if (aText.isEmpty()) {
       if (mySpinBox->hasVariable()) {
index 84fb045d6f2589f10a56a49325e7e3681266d0f6..c8177d56a5bd09032f130746a97d52d136ca6e17 100644 (file)
@@ -73,10 +73,13 @@ Q_OBJECT
 
 private:
   /// Show editor
+  /// \param theSpinMinValue a minimal value of popup menu spin box
+  /// \param theSpinMaxValue a maximum value of popup menu spin box
   /// \param theOutValue a result value
   /// \param theOutText a result text
   /// \return true if the editor value is accepted
-  bool editedValue(double& theOutValue, QString& theOutText);
+  bool editedValue(double theSpinMinValue, double theSpinMaxValue,
+                   double& theOutValue, QString& theOutText);
 
  private:
    ///< the current widget feature
index b04c3171684c106de5865e2d6be2b853e735bf8b..37575cf725c28525a1f7541c0224ba880c0130a6 100644 (file)
@@ -56,6 +56,8 @@ SET(PROJECT_HEADERS
     PartSet_WidgetShapeSelector.h
     PartSet_WidgetSketchCreator.h
     PartSet_WidgetSketchLabel.h
+    PartSet_CenterPrs.h
+    PartSet_ExternalPointsMgr.h
 )
 
 SET(PROJECT_MOC_HEADERS
@@ -74,6 +76,7 @@ SET(PROJECT_MOC_HEADERS
     PartSet_WidgetShapeSelector.h
     PartSet_WidgetSketchCreator.h
     PartSet_WidgetSketchLabel.h
+    PartSet_ExternalPointsMgr.h
 )
 
 SET(PROJECT_SOURCES
@@ -101,6 +104,8 @@ SET(PROJECT_SOURCES
     PartSet_WidgetShapeSelector.cpp
     PartSet_WidgetSketchCreator.cpp
     PartSet_WidgetSketchLabel.cpp
+    PartSet_CenterPrs.cpp
+    PartSet_ExternalPointsMgr.cpp
 )
 
 SET(PROJECT_RESOURCES
diff --git a/src/PartSet/PartSet_CenterPrs.cpp b/src/PartSet/PartSet_CenterPrs.cpp
new file mode 100644 (file)
index 0000000..065c797
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        PartSet_CenterPrs.cpp
+// Created:     25 April 2017
+// Author:      Vitaly SMETANNIKOV
+
+#include "PartSet_CenterPrs.h"
+
+#include <Geom_CartesianPoint.hxx>
+
+
+IMPLEMENT_STANDARD_RTTIEXT(PartSet_CenterPrs, AIS_Point)
+
+PartSet_CenterPrs::PartSet_CenterPrs(const ObjectPtr& theObject,
+                                     const GeomEdgePtr& theEdge,
+                                     const gp_Pnt& theCenter,
+                                     ModelAPI_AttributeSelection::CenterType theType)
+  : AIS_Point(new Geom_CartesianPoint(theCenter)),
+  myObject(theObject),
+  myEdge(theEdge),
+  myCenterType(theType)
+{
+}
\ No newline at end of file
diff --git a/src/PartSet/PartSet_CenterPrs.h b/src/PartSet/PartSet_CenterPrs.h
new file mode 100644 (file)
index 0000000..86e54b2
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        PartSet_CenterPrs.h
+// Created:     25 April 2017
+// Author:      Vitaly SMETANNIKOV
+
+#ifndef PartSet_CenterPrs_H
+#define PartSet_CenterPrs_H
+
+#include <ModelAPI_Object.h>
+#include <ModelAPI_AttributeSelection.h>
+#include <GeomAPI_Edge.h>
+
+#include <AIS_Point.hxx>
+#include <Standard_DefineHandle.hxx>
+#include <gp_Pnt.hxx>
+
+DEFINE_STANDARD_HANDLE(PartSet_CenterPrs, AIS_Point)
+
+/**
+* \ingroup GUI
+* A presentation class for displaying of centers of external curcular objects in a sketch
+*/
+class PartSet_CenterPrs: public AIS_Point
+{
+public:
+  /// Constructor
+  /// \param theObject an object with circular edge
+  /// \param theEdge a circular edge
+  /// \param theCenter a center point of the circular edge
+  /// \param theType a type of the center
+  Standard_EXPORT PartSet_CenterPrs(const ObjectPtr& theObject,
+                                    const GeomEdgePtr& theEdge,
+                                    const gp_Pnt& theCenter,
+                                    ModelAPI_AttributeSelection::CenterType theType);
+
+  /// Returns an Object which contains the circular edge
+  ObjectPtr object() const { return myObject; }
+
+  /// Returns a circular edge shape
+  GeomEdgePtr edge() const { return myEdge; }
+
+  /// Returns type of the center
+  ModelAPI_AttributeSelection::CenterType centerType() const { return myCenterType; }
+
+  DEFINE_STANDARD_RTTIEXT(PartSet_CenterPrs, AIS_Point)
+
+private:
+  ObjectPtr myObject;
+  GeomEdgePtr myEdge;
+  ModelAPI_AttributeSelection::CenterType myCenterType;
+};
+
+#endif
diff --git a/src/PartSet/PartSet_ExternalPointsMgr.cpp b/src/PartSet/PartSet_ExternalPointsMgr.cpp
new file mode 100644 (file)
index 0000000..0f9babd
--- /dev/null
@@ -0,0 +1,229 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        PartSet_ExternalPointsMgr.cpp
+// Created:     26 April 2017
+// Author:      Vitaly SMETANNIKOV
+
+#include "PartSet_ExternalPointsMgr.h"
+#include "PartSet_CenterPrs.h"
+#include "PartSet_Tools.h"
+
+#include <ModelAPI_Tools.h>
+
+#include <ModuleBase_IWorkshop.h>
+#include <ModuleBase_ViewerPrs.h>
+
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <XGUI_Tools.h>
+#include <XGUI_Displayer.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_SelectionMgr.h>
+
+PartSet_ExternalPointsMgr::PartSet_ExternalPointsMgr(ModuleBase_IWorkshop* theWorkshop,
+                                                     const CompositeFeaturePtr& theSketch)
+  : QObject(theWorkshop), myWorkshop(theWorkshop), mySketch(theSketch)
+{
+  XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+  connect(aDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
+                      SLOT(onDisplayObject(ObjectPtr, AISObjectPtr)));
+
+  connect(aDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
+                      SLOT(onEraseObject(ObjectPtr, AISObjectPtr)));
+
+  updateCenterPresentations();
+}
+
+
+PartSet_ExternalPointsMgr::~PartSet_ExternalPointsMgr()
+{
+  if (myPresentations.isEmpty())
+    return;
+  XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+  if (!aWorkshop)
+    return;
+
+  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+  QMapIterator<ObjectPtr, ListOfAIS> aIt(myPresentations);
+  while (aIt.hasNext()) {
+    aIt.next();
+    ListOfAIS aAISList = aIt.value();
+    foreach (AISObjectPtr aAIS, aAISList) {
+      aDisplayer->eraseAIS(aAIS, false);
+    }
+  }
+}
+
+
+//******************************************************
+QList<std::shared_ptr<ModuleBase_ViewerPrs>> PartSet_ExternalPointsMgr::findCircularEdgesInPlane()
+{
+  QList<std::shared_ptr<ModuleBase_ViewerPrs>> aResult;
+  XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+  QObjectPtrList aDispObjects = aDisplayer->displayedObjects();
+
+  std::shared_ptr<GeomAPI_Pln> aPlane = plane();
+  foreach(ObjectPtr aObj, aDispObjects) {
+    if (myPresentations.contains(aObj))
+      continue;
+
+    // Do not process objects of the current sketch
+    if (isSketchObject(aObj))
+      continue;
+
+    ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+    if (aResObj.get()) {
+      GeomShapePtr aShape = aResObj->shape();
+      if (aShape.get()) {
+        GeomAPI_ShapeExplorer aExplorer(aShape, GeomAPI_Shape::EDGE);
+        for(; aExplorer.more(); aExplorer.next()) {
+          GeomShapePtr aEdgeShape = aExplorer.current();
+          GeomAPI_Edge anEdge(aEdgeShape);
+          if ((anEdge.isCircle() || anEdge.isArc() || anEdge.isEllipse()) &&
+               anEdge.isInPlane(aPlane)) {
+            bool isContains = false;
+            // Check that edge is not already used.
+            // It is possible that the same edge will be taken from different faces
+            foreach(std::shared_ptr<ModuleBase_ViewerPrs> aPrs, aResult) {
+              GeomAPI_Edge aUsedEdge(aPrs->shape());
+              if (aUsedEdge.isEqual(aEdgeShape)) {
+                isContains = true;
+                break;
+              }
+            }
+            if (!isContains) {
+              std::shared_ptr<ModuleBase_ViewerPrs>
+                aPrs(new ModuleBase_ViewerPrs(aResObj, aEdgeShape));
+              aResult.append(aPrs);
+            }
+          }
+        }
+      }
+    }
+  }
+  return aResult;
+}
+
+
+void PartSet_ExternalPointsMgr::updateCenterPresentations()
+{
+  XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+  // Return if there is no plane defined
+  if (!plane().get()) {
+    connect(aWorkshop->selector(), SIGNAL(selectionChanged()),
+                                   SLOT(onSelectionChanged()));
+    return;
+  }
+  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+
+  QList<std::shared_ptr<ModuleBase_ViewerPrs>> aEdgesPrs = findCircularEdgesInPlane();
+  foreach(std::shared_ptr<ModuleBase_ViewerPrs> aPrs, aEdgesPrs) {
+    GeomEdgePtr aEdge(new GeomAPI_Edge(aPrs->shape()));
+    ListOfAIS aList;
+    if (aEdge->isArc() || aEdge->isCircle()) {
+      GeomCirclePtr aCircle = aEdge->circle();
+      GeomPointPtr aCenter = aCircle->center();
+      Handle(PartSet_CenterPrs) aCentPrs =
+        new PartSet_CenterPrs(aPrs->object(), aEdge, aCenter->impl<gp_Pnt>(),
+                              ModelAPI_AttributeSelection::CIRCLE_CENTER);
+
+      AISObjectPtr anAIS(new GeomAPI_AISObject());
+      anAIS->setImpl(new Handle(AIS_InteractiveObject)(aCentPrs));
+      aList.append(anAIS);
+    } else if (aEdge->isEllipse()) {
+      GeomEllipsePtr aEllipse = aEdge->ellipse();
+      GeomPointPtr aF1 = aEllipse->firstFocus();
+      GeomPointPtr aF2 = aEllipse->secondFocus();
+      Handle(PartSet_CenterPrs) aF1Prs =
+        new PartSet_CenterPrs(aPrs->object(), aEdge, aF1->impl<gp_Pnt>(),
+                              ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS);
+      Handle(PartSet_CenterPrs) aF2Prs =
+        new PartSet_CenterPrs(aPrs->object(), aEdge, aF2->impl<gp_Pnt>(),
+                              ModelAPI_AttributeSelection::ELLIPSE_SECOND_FOCUS);
+
+      AISObjectPtr anAIS1(new GeomAPI_AISObject());
+      anAIS1->setImpl(new Handle(AIS_InteractiveObject)(aF1Prs));
+      aList.append(anAIS1);
+
+      AISObjectPtr anAIS2(new GeomAPI_AISObject());
+      anAIS2->setImpl(new Handle(AIS_InteractiveObject)(aF2Prs));
+      aList.append(anAIS2);
+    }
+    if (myPresentations.contains(aPrs->object()))
+      myPresentations[aPrs->object()].append(aList);
+    else
+      myPresentations[aPrs->object()] = aList;
+    foreach(AISObjectPtr anAIS, aList) {
+      aDisplayer->displayAIS(anAIS, false);
+      aDisplayer->activateAIS(anAIS->impl<Handle(AIS_InteractiveObject)>(), TopAbs_VERTEX, false);
+    }
+  }
+}
+
+std::shared_ptr<GeomAPI_Pln> PartSet_ExternalPointsMgr::plane() const
+{
+  return PartSet_Tools::sketchPlane(mySketch);
+}
+
+void PartSet_ExternalPointsMgr::onDisplayObject(ObjectPtr theObj, AISObjectPtr theAIS)
+{
+  updateCenterPresentations();
+}
+
+void PartSet_ExternalPointsMgr::onEraseObject(ObjectPtr theObj, AISObjectPtr theAIS)
+{
+  if (myPresentations.contains(theObj)) {
+    XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+    XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+    ListOfAIS aList = myPresentations[theObj];
+    foreach(AISObjectPtr aAIS, aList) {
+      aDisplayer->eraseAIS(aAIS, false);
+    }
+    myPresentations.remove(theObj);
+    aDisplayer->updateViewer();
+  }
+}
+
+
+bool PartSet_ExternalPointsMgr::isSketchObject(const ObjectPtr& theRes) const
+{
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theRes);
+  if (!aFeature.get())
+    return false;
+  CompositeFeaturePtr aComp = ModelAPI_Tools::compositeOwner(aFeature);
+  return aComp == mySketch;
+}
+
+void PartSet_ExternalPointsMgr::onSelectionChanged()
+{
+  if (plane().get()) {
+    XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+    disconnect(aWorkshop->selector(), SIGNAL(selectionChanged()),
+               this, SLOT(onSelectionChanged()));
+    updateCenterPresentations();
+  }
+}
diff --git a/src/PartSet/PartSet_ExternalPointsMgr.h b/src/PartSet/PartSet_ExternalPointsMgr.h
new file mode 100644 (file)
index 0000000..4f13f09
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        PartSet_ExternalPointsMgr.h
+// Created:     26 April 2017
+// Author:      Vitaly SMETANNIKOV
+
+#ifndef PartSet_ExternalPointsMgr_H
+#define PartSet_ExternalPointsMgr_H
+
+
+#include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_Result.h>
+#include <GeomAPI_Pln.h>
+#include <GeomAPI_AISObject.h>
+
+#include <QObject>
+#include <QMap>
+
+class ModuleBase_ViewerPrs;
+class ModuleBase_IWorkshop;
+
+
+/**
+* \ingroup Modules
+* A class to manage display of presentations of center points of circular
+* edges outside of a current sketcher
+*/
+class PartSet_ExternalPointsMgr: public QObject
+{
+  Q_OBJECT
+public:
+  PartSet_ExternalPointsMgr(ModuleBase_IWorkshop* theWorkshop,
+                            const CompositeFeaturePtr& theSketch);
+
+  virtual ~PartSet_ExternalPointsMgr();
+
+public slots:
+  /**
+  * A slot which processes display of object
+  * \param theObj the displayed object
+  * \param theAIS its presentation
+  */
+  void onDisplayObject(ObjectPtr theObj, AISObjectPtr theAIS);
+
+  /**
+  * A slot which processes erase of object
+  * \param theObj the displayed object
+  * \param theAIS its presentation
+  */
+  void onEraseObject(ObjectPtr theObj, AISObjectPtr theAIS);
+
+  // Called on selection changed
+  void onSelectionChanged();
+
+private:
+  /**
+  * Returns list of presentations which have displayed shapes with circular edges
+  * (circles, arcs) which are in pane of of the given sketch
+  * \param theSketch - the sketch
+  */
+  QList<std::shared_ptr<ModuleBase_ViewerPrs>> findCircularEdgesInPlane();
+
+  /// Creates presentations of centers
+  void updateCenterPresentations();
+
+  /// Returns plane of the current sketch
+  GeomPlanePtr plane() const;
+
+  /**
+  * Checks that the given object is an object of the current sketch
+  * \param theRes an object to check
+  * \return True if the given object is a sub-object of the current sketch
+  */
+  bool isSketchObject(const ObjectPtr& theRes) const;
+
+private:
+  /// Workshop
+  ModuleBase_IWorkshop* myWorkshop;
+
+  /// Current sketch
+  CompositeFeaturePtr mySketch;
+
+  /// Type for list of created AIS objects
+  typedef QList<AISObjectPtr> ListOfAIS;
+
+  /// Map of created AIS objects
+  QMap<ObjectPtr, ListOfAIS> myPresentations;
+};
+
+#endif
\ No newline at end of file
index 3cc5c73ab56937be16e516537be005bb4d13fa83..5dc11364e32d6cd5496a910e7d54dbd0ecd92df3 100755 (executable)
@@ -1264,7 +1264,7 @@ void PartSet_Module::processEvent(const std::shared_ptr<Events_Message>& theMess
       aTreeView->setExpanded(myActivePartIndex, false);
 
     XGUI_DataModel* aDataModel = aWorkshop->objectBrowser()->dataModel();
-    myActivePartIndex = aDataModel->documentRootIndex(aActiveDoc);
+    myActivePartIndex = aDataModel->documentRootIndex(aActiveDoc, 0);
     bool needUpdate = false;
     if (myActivePartIndex.isValid()) {
       needUpdate = aTreeView->isExpanded(myActivePartIndex);
@@ -1336,7 +1336,7 @@ void PartSet_Module::onTreeViewDoubleClick(const QModelIndex& theIndex)
     //aMgr->setActiveDocument(aMgr->moduleDocument());
     return;
   }
-  if (theIndex.column() != 0) // Use only first column
+  if (theIndex.column() != 1) // Use only first column
     return;
 
   XGUI_Workshop* aWorkshop = getWorkshop();
index 9a1ed0282509f107d55a4ace45d3120211f3b4f6..eab2a165ce2f8de27adcd3d4ac2f3b665b6fb99d 100755 (executable)
@@ -26,6 +26,7 @@
 #include "PartSet_WidgetSketchLabel.h"
 #include "PartSet_WidgetEditor.h"
 #include "PartSet_ResultSketchPrs.h"
+#include "PartSet_ExternalPointsMgr.h"
 
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_Displayer.h>
@@ -152,7 +153,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)
+    myIsPopupMenuActive(false), myExternalPointsMgr(0)
 {
   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
@@ -536,8 +537,11 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
     Point aMousePnt;
     get2dPoint(theWnd, theEvent, aMousePnt);
-    double dX =  aMousePnt.myCurX - myCurrentPoint.myCurX;
-    double dY =  aMousePnt.myCurY - myCurrentPoint.myCurY;
+
+    std::shared_ptr<GeomAPI_Pnt2d> anOriginalPosition = std::shared_ptr<GeomAPI_Pnt2d>(
+                            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));
 
     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
@@ -572,9 +576,15 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
             if (aPoint.get() != NULL) {
               bool isImmutable = aPoint->setImmutable(true);
-              aPoint->move(dX, dY);
+
+              std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
+                       <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+              aMessage->setMovedAttribute(aPoint);
+              aMessage->setOriginalPosition(anOriginalPosition);
+              aMessage->setCurrentPosition(aCurrentPosition);
+              Events_Loop::loop()->send(aMessage);
+
               isModified = true;
-              ModelAPI_EventCreator::get()->sendUpdated(aFeature, aMoveEvent);
               aPoint->setImmutable(isImmutable);
             }
           }
@@ -584,9 +594,13 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
         if (aSketchFeature) {
-          aSketchFeature->move(dX, dY);
+          std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
+                    <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+          aMessage->setMovedObject(aFeature);
+          aMessage->setOriginalPosition(anOriginalPosition);
+          aMessage->setCurrentPosition(aCurrentPosition);
+          Events_Loop::loop()->send(aMessage);
           isModified = true;
-          ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, aMoveEvent);
         }
       }
     }
@@ -594,8 +608,8 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     // were changed here
     if (isModified) {
       aCurrentOperation->onValuesChanged();
+      Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
     }
-    Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations
 
     // 5. it is necessary to save current selection in order to restore it after the features moving
@@ -999,6 +1013,8 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   // plane filter
   if (aPln.get())
     aConnector->activateModuleSelectionModes();
+
+  myExternalPointsMgr = new PartSet_ExternalPointsMgr(myModule->workshop(), myCurrentSketch);
 }
 
 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
@@ -1008,6 +1024,11 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
   myIsConstraintsShown[PartSet_Tools::Expressions] = false;
 
+  if (myExternalPointsMgr) {
+    delete myExternalPointsMgr;
+    myExternalPointsMgr = 0;
+  }
+
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
 
   DataPtr aData = myCurrentSketch->data();
index 5396144b3aa48a213182cb80a5fdb159532556a0..92c74ef8c5dbaa65bd410f1e4a94b118c7ce13c6 100644 (file)
@@ -50,6 +50,7 @@ class ModuleBase_ModelWidget;
 class ModuleBase_Operation;
 class XGUI_OperationMgr;
 class XGUI_Workshop;
+class PartSet_ExternalPointsMgr;
 
 class AIS_InteractiveObject;
 
@@ -432,6 +433,8 @@ private:
   bool myPreviousUpdateViewerEnabled;
 
   QMap<PartSet_Tools::ConstraintVisibleState, bool> myIsConstraintsShown;
+
+  PartSet_ExternalPointsMgr* myExternalPointsMgr;
 };
 
 
index 2b5315a8fbcd79168330f5626f9eb962a44b3028..2a5f0f08d0ee6ed45326ecb64c9e6f68b10cfce3 100755 (executable)
@@ -905,3 +905,29 @@ bool PartSet_Tools::isAuxiliarySketchEntity(const ObjectPtr& theObject)
 
   return isAuxiliaryFeature;
 }
+
+
+ResultPtr PartSet_Tools::createFixedByExternalCenter(
+    const ObjectPtr& theObject,
+    const std::shared_ptr<GeomAPI_Edge>& theEdge,
+    ModelAPI_AttributeSelection::CenterType theType,
+    const CompositeFeaturePtr& theSketch,
+    bool theTemporary)
+{
+  FeaturePtr aMyFeature = theSketch->addFeature(SketchPlugin_Point::ID());
+
+  if (aMyFeature) {
+    DataPtr aData = aMyFeature->data();
+    AttributeSelectionPtr anAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
+        (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
+
+    ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+    if (anAttr.get() && aRes.get()) {
+      anAttr->setValueCenter(aRes, theEdge, theType, theTemporary);
+      aMyFeature->execute();
+      return aMyFeature->lastResult();
+    }
+  }
+  return ResultPtr();
+}
index 69b9838d4ff2a3fa6108534ad91531fa44098832..b7c0a22c921efec6e030b73f6af513d872cd62cb 100755 (executable)
@@ -31,6 +31,7 @@
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_Object.h>
 #include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeSelection.h>
 
 #include <Events_Message.h>
 
@@ -279,6 +280,13 @@ public:
    * \return boolean result
    */
   static bool isAuxiliarySketchEntity(const ObjectPtr& theObject);
+
+  static ResultPtr createFixedByExternalCenter(const ObjectPtr& theObject,
+                                               const std::shared_ptr<GeomAPI_Edge>& theEdge,
+                                               ModelAPI_AttributeSelection::CenterType theType,
+                                               const CompositeFeaturePtr& theSketch,
+                                               bool theTemporary = false);
+
 };
 
 #endif
index 36b897e5f2f8d003ffb802a1bb6135ba99fdc4dd..3d9d933e95e927ce3457820dfc1b48c90fe9e886 100644 (file)
@@ -23,6 +23,7 @@
 #include <PartSet_Module.h>
 #include <PartSet_SketcherReentrantMgr.h>
 #include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_CenterPrs.h>
 
 #include <XGUI_Tools.h>
 #include <XGUI_Workshop.h>
@@ -76,6 +77,7 @@
 #include <TopoDS.hxx>
 #include <TopoDS_Vertex.hxx>
 #include <BRep_Tool.hxx>
+#include <Geom_Point.hxx>
 
 #include <cfloat>
 #include <climits>
@@ -356,10 +358,23 @@ bool PartSet_WidgetPoint2D::storeValueCustom()
   //                myYSpin->hasVariable() ? myYSpin->text().toStdString() : "");
   //aPoint->setValue(!myXSpin->hasVariable() ? myXSpin->value() : aPoint->x(),
   //                 !myYSpin->hasVariable() ? myYSpin->value() : aPoint->y());
-  aPoint->setValue(myXSpin->value(), myYSpin->value());
 
-  // after movement the solver will call the update event: optimization
-  moveObject(myFeature);
+  if (myFeature->isMacro()) {
+    // Moving points of macro-features has been processed directly (without solver)
+    aPoint->setValue(myXSpin->value(), myYSpin->value());
+    moveObject(myFeature);
+  } else {
+    if (!aPoint->isInitialized())
+      aPoint->setValue(0., 0.);
+
+    std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
+        new ModelAPI_ObjectMovedMessage(this));
+    aMessage->setMovedAttribute(aPoint);
+    aMessage->setOriginalPosition(aPoint->pnt());
+    aMessage->setCurrentPosition(myXSpin->value(), myYSpin->value());
+    Events_Loop::loop()->send(aMessage);
+  }
+
   aPoint->setImmutable(isImmutable);
   that->blockSignals(isBlocked);
 
@@ -693,7 +708,36 @@ void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMo
       }
     }
   }
-  // End of Bug dependent fragment
+  // The selection could be a center of an external circular object
+  else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
+    Handle(PartSet_CenterPrs) aAIS =
+        Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
+    if (!aAIS.IsNull()) {
+      gp_Pnt aPntComp = aAIS->Component()->Pnt();
+      GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
+      TopoDS_Shape aShape = aVertPtr->impl<TopoDS_Shape>();
+
+      ResultPtr aFixedObject =
+          PartSet_Tools::findFixedObjectByExternal(aShape, aAIS->object(), mySketch);
+      if (!aFixedObject.get())
+        aFixedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
+                                                                  aAIS->centerType(), mySketch);
+      if (aFixedObject.get())
+        setConstraintToObject(aFixedObject);
+      // fignal updated should be flushed in order to visualize possible created
+      // external objects e.g. selection of trihedron axis when input end arc point
+      updateObject(feature());
+
+      double aX, aY;
+      if (getPoint2d(aView, aShape, aX, aY)) {
+        // do not create a constraint to the point, which already used by the feature
+        // if the feature contains the point, focus is not switched
+        setPoint(aX, aY);
+      }
+      emit vertexSelected(); // it stops the reentrant operation
+      emit focusOutWidget(this);
+    }
+  }
   else {
     // A case when point is taken from mouse event
     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
index 190b7e2a348435f0117c5fa28f9a050a2baa797b..aa209656b328a61230ef0ff4e5efe3eacce1a881 100644 (file)
@@ -48,6 +48,8 @@
 #include <GeomDataAPI_Dir.h>
 #include <GeomAPI_XYZ.h>
 #include <GeomAPI_Face.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <SketchPlugin_Sketch.h>
 #include <SketcherPrs_Tools.h>
@@ -586,7 +588,7 @@ std::shared_ptr<GeomAPI_Dir>
   std::shared_ptr<GeomAPI_Pnt> anOrigPnt(new GeomAPI_Pnt(aCoords));
   // X axis is preferable to be dirX on the sketch
   const double tol = Precision::Confusion();
-  bool isX = fabs(anA - 1.0) < tol && fabs(aB) < tol && fabs(aC) < tol;
+  bool isX = fabs(fabs(anA) - 1.0) < tol && fabs(aB) < tol && fabs(aC) < tol;
   std::shared_ptr<GeomAPI_Dir> aTempDir(
       isX ? new GeomAPI_Dir(0, 1, 0) : new GeomAPI_Dir(1, 0, 0));
   std::shared_ptr<GeomAPI_Dir> aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir)));
@@ -619,3 +621,47 @@ void PartSet_WidgetSketchLabel::onSetPlaneView()
       aModule->onViewTransformed();
   }
 }
+
+
+//******************************************************
+QList<std::shared_ptr<ModuleBase_ViewerPrs>> PartSet_WidgetSketchLabel::findCircularEdgesInPlane()
+{
+  QList<std::shared_ptr<ModuleBase_ViewerPrs>> aResult;
+  XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+  QObjectPtrList aDispObjects = aDisplayer->displayedObjects();
+
+  std::shared_ptr<GeomAPI_Pln> aPlane = plane();
+  foreach(ObjectPtr aObj, aDispObjects) {
+    ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+    if (aResObj.get()) {
+      GeomShapePtr aShape = aResObj->shape();
+      if (aShape.get()) {
+        GeomAPI_ShapeExplorer aExplorer(aShape, GeomAPI_Shape::EDGE);
+        for(; aExplorer.more(); aExplorer.next()) {
+          GeomShapePtr aEdgeShape = aExplorer.current();
+          GeomAPI_Edge anEdge(aEdgeShape);
+          if ((anEdge.isCircle() || anEdge.isArc() || anEdge.isEllipse()) &&
+               anEdge.isInPlane(aPlane)) {
+            bool isContains = false;
+            // Check that edge is not used.
+            // It is possible that the same edge will be taken from different faces
+            foreach(std::shared_ptr<ModuleBase_ViewerPrs> aPrs, aResult) {
+              GeomAPI_Edge aUsedEdge(aPrs->shape());
+              if (aUsedEdge.isEqual(aEdgeShape)) {
+                isContains = true;
+                break;
+              }
+            }
+            if (!isContains) {
+              std::shared_ptr<ModuleBase_ViewerPrs>
+                aPrs(new ModuleBase_ViewerPrs(aResObj, aEdgeShape));
+              aResult.append(aPrs);
+            }
+          }
+        }
+      }
+    }
+  }
+  return aResult;
+}
index 515c0377ab415a749f118ff542f1a810c361ca48..5cc4a10cf76049ac3b633341362dcc22228c420c 100644 (file)
@@ -192,6 +192,13 @@ protected:
   /// \param thePlane a plane
   std::shared_ptr<GeomAPI_Dir> setSketchPlane(std::shared_ptr<GeomAPI_Pln> thePlane);
 
+  /**
+  * Returns list of presentations which have displayed shapes with circular edges
+  * (circles, arcs) which are in pane of of the given sketch
+  * \param theSketch - the sketch
+  */
+  QList<std::shared_ptr<ModuleBase_ViewerPrs>> findCircularEdgesInPlane();
+
 private:
   /// class to show/hide preview planes
   PartSet_PreviewPlanes* myPreviewPlanes;
index b015b4278170b469d81fa7d734d14f4812bb448f..8c0319a1ecab2b26d8bd563a03aface7855dc7c8 100644 (file)
@@ -3,3 +3,4 @@
 
 from SketchAPI import addSketch
 from tools import *
+from tests import *
diff --git a/src/PythonAPI/model/sketcher/tests.py b/src/PythonAPI/model/sketcher/tests.py
new file mode 100644 (file)
index 0000000..ea69081
--- /dev/null
@@ -0,0 +1,93 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from ModelAPI import *
+from GeomDataAPI import *
+import ModelHighAPI
+import math
+from salome.shaper.model.sketcher import tools
+
+TOLERANCE = 1.e-7
+
+def assertPoint(thePoint, theCoords):
+    """ Verifies coordinates of the point
+    """
+    aPoint = tools.toList(thePoint)
+    assert aPoint[0] == theCoords[0] and aPoint[1] == theCoords[1], "Wrong '{}' point {}, expected {}".format(thePoint.id(), aPoint, theCoords)
+
+
+def assertLine(theLine, theStart, theEnd):
+    """ Verifies coordinates of line extremities
+    """
+    aLine = tools.toSketchFeature(theLine)
+
+    aStartPnt = geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+    aEndPnt = geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+    if len(theStart):
+        assertPoint(aStartPnt, theStart)
+    if len(theEnd):
+        assertPoint(aEndPnt, theEnd)
+
+
+def assertCircle(theCircle, theCenter, theRadius):
+    """ Verifies attributes of circle
+    """
+    aCircle = tools.toSketchFeature(theCircle)
+
+    aCenter = geomDataAPI_Point2D(aCircle.attribute("circle_center"))
+    if len(theCenter):
+        assertPoint(aCenter, theCenter)
+
+    aRadius = aCircle.real("circle_radius")
+    assert aRadius.value() == theRadius, "Wrong circle radius {}, expected {}".format(aRadius.value(), theRadius)
+
+
+def assertArc(theArc, theCenter, theStart, theEnd):
+    """ Verifies coordinates of arc points and the consistency of the arc.
+        Some of points may be empty lists.
+    """
+    anArc = tools.toSketchFeature(theArc)
+
+    aCenterPnt = geomDataAPI_Point2D(anArc.attribute("center_point"))
+    aStartPnt = geomDataAPI_Point2D(anArc.attribute("start_point"))
+    aEndPnt = geomDataAPI_Point2D(anArc.attribute("end_point"))
+    if len(theCenter):
+        assertPoint(aCenterPnt, theCenter)
+    if len(theStart):
+        assertPoint(aStartPnt, theStart)
+    if len(theEnd):
+        assertPoint(aEndPnt, theEnd)
+
+    assertArcValidity(anArc)
+
+
+def assertArcValidity(theArc):
+    """ Tests whether the arc is correctly defined
+    """
+    anArc = tools.toSketchFeature(theArc)
+
+    aCenterPnt = geomDataAPI_Point2D(anArc.attribute("center_point"))
+    aStartPnt = geomDataAPI_Point2D(anArc.attribute("start_point"))
+    aEndPnt = geomDataAPI_Point2D(anArc.attribute("end_point"))
+    aRadius = anArc.real("radius")
+    aDistCS = tools.distancePointPoint(aCenterPnt, aStartPnt)
+    aDistCE = tools.distancePointPoint(aCenterPnt, aEndPnt)
+    assert math.fabs(aDistCS - aDistCE) < TOLERANCE, "Wrong arc: center-start distance {}, center-end distance {}".format(aDistCS, aDistCE)
+    assert math.fabs(aRadius.value() - aDistCS) < TOLERANCE, "Wrong arc: radius is {}, expected {}".format(aRadius.value(), aDistCS)
index de3032f54d16bae221e821bfa78cb0d68c397e36..5c1903a062196d3e71b4565a7f993cd9e097b01b 100644 (file)
@@ -77,6 +77,20 @@ def distancePointPoint(thePoint1, thePoint2):
         aGeomPnt2 = thePoint2.pnt()
     return aGeomPnt1.distance(aGeomPnt2)
 
+def signedDistancePointLine(thePoint, theLine):
+    aPoint = toList(thePoint)
+    aLine = toSketchFeature(theLine)
+
+    aLineStart = geomDataAPI_Point2D(aLine.attribute("StartPoint")).pnt().xy()
+    aLineEnd = geomDataAPI_Point2D(aLine.attribute("EndPoint")).pnt().xy()
+    aLineDir = aLineEnd.decreased(aLineStart)
+    aLineLen = aLineEnd.distance(aLineStart)
+    aCross = (aPoint[0] - aLineStart.x()) * aLineDir.y() - (aPoint[1] - aLineStart.y()) * aLineDir.x()
+    return aCross / aLineLen
+
+def distancePointLine(thePoint, theLine):
+    return math.fabs(signedDistancePointLine(thePoint, theLine))
+
 def lastSubFeature(theSketch, theKind):
     """
     obtains last feature of given kind from the sketch
index b777eaddeecc77df2e07e95d17b28ae53f8305b6..c5a75fef3a135a6dacc4f8feaee90d7a74007f61 100644 (file)
@@ -28,6 +28,8 @@
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
@@ -82,6 +84,14 @@ static const std::string& constraintTypeToSetter(const std::string& theType)
     static const std::string DISTANCE_SETTER("setDistance");
     return DISTANCE_SETTER;
   }
+  if (theType == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+    static const std::string DISTANCE_SETTER("setHorizontalDistance");
+    return DISTANCE_SETTER;
+  }
+  if (theType == SketchPlugin_ConstraintDistanceVertical::ID()) {
+    static const std::string DISTANCE_SETTER("setVerticalDistance");
+    return DISTANCE_SETTER;
+  }
   if (theType == SketchPlugin_ConstraintEqual::ID()) {
     static const std::string EQUAL_SETTER("setEqual");
     return EQUAL_SETTER;
@@ -182,5 +192,10 @@ void SketchAPI_Constraint::dump(ModelHighAPI_Dumper& theDumper) const
   if (aValueAttr && aValueAttr->isInitialized())
     theDumper << ", " << aValueAttr;
 
+  if (aBase->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+    AttributeBooleanPtr isSigned = aBase->boolean(SketchPlugin_ConstraintDistance::SIGNED());
+    theDumper << ", " << isSigned->value();
+  }
+
   theDumper << ")" << std::endl;
 }
index 51628de970f564cb26fe6b3c148a90fde9d352ea..38e84be98560cfff64879f6bfe0364dd52d64037 100644 (file)
@@ -78,6 +78,12 @@ void SketchAPI_Projection::setByExternalName(const std::string& theExternalName)
   execute(true);
 }
 
+void SketchAPI_Projection::setIncludeToResult(bool theKeepResult)
+{
+  fillAttribute(theKeepResult, includeToResult());
+  execute(true);
+}
+
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_SketchEntity> SketchAPI_Projection::createdFeature() const
 {
@@ -106,7 +112,9 @@ void SketchAPI_Projection::dump(ModelHighAPI_Dumper& theDumper) const
   const std::string& aSketchName = theDumper.parentName(aBase);
 
   AttributeSelectionPtr anExternal = externalFeature();
-  theDumper << aBase << " = " << aSketchName << ".addProjection(" << anExternal << ")" << std::endl;
+  AttributeBooleanPtr isIncludeToRes = includeToResult();
+  theDumper << aBase << " = " << aSketchName << ".addProjection("
+            << anExternal << ", " << isIncludeToRes << ")" << std::endl;
   // dump "auxiliary" flag if necessary
   SketchAPI_SketchEntity::dump(theDumper);
 
index e1b1570535b5bb28441715f35dc991a79c338033..e3926fc36ea541514bcfa010658a78999493f1b8 100644 (file)
@@ -52,13 +52,15 @@ public:
   SKETCHAPI_EXPORT
   virtual ~SketchAPI_Projection();
 
-  INTERFACE_3(SketchPlugin_Projection::ID(),
+  INTERFACE_4(SketchPlugin_Projection::ID(),
               externalFeature, SketchPlugin_Projection::EXTERNAL_FEATURE_ID(),
               ModelAPI_AttributeSelection, /** External feature */,
               projectedFeature, SketchPlugin_Projection::PROJECTED_FEATURE_ID(),
               ModelAPI_AttributeRefAttr, /** Projected feature */,
               external, SketchPlugin_Projection::EXTERNAL_ID(),
-              ModelAPI_AttributeSelection, /** External */
+              ModelAPI_AttributeSelection, /** External */,
+              includeToResult, SketchPlugin_Projection::INCLUDE_INTO_RESULT(),
+              ModelAPI_AttributeBoolean, /** Include into result */
   )
 
   /// Set external feature
@@ -69,6 +71,10 @@ public:
   SKETCHAPI_EXPORT
   void setByExternalName(const std::string & theExternalName);
 
+  /// Set flag to include projection to result or not
+  SKETCHAPI_EXPORT
+  void setIncludeToResult(bool theKeepResult);
+
   /// Returns created feature
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_SketchEntity> createdFeature() const;
index 6fa94f420bf68679c530d5bb735b3d8d46c4a886..135285e6a0b3cc78b71deb244eaaf721ee27156c 100644 (file)
@@ -78,3 +78,13 @@ void SketchAPI_Rectangle::setByPoints(
 }
 
 //--------------------------------------------------------------------------------------
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Rectangle::lines() const
+{
+  std::list<FeaturePtr> aFeatures;
+  std::list<ObjectPtr> aList = linesList()->list();
+  std::list<ObjectPtr>::const_iterator anIt = aList.begin();
+  for (; anIt != aList.end(); ++anIt)
+    aFeatures.push_back(ModelAPI_Feature::feature(*anIt));
+  return SketchAPI_SketchEntity::wrap(aFeatures);
+}
index fb63cec63ddcbe897365a72e58fedf133e1e3eda..b9fe8fced01cea8cf62f0b39a67c34861c4cf269 100644 (file)
@@ -65,6 +65,9 @@ public:
   SKETCHAPI_EXPORT
   void setByPoints(const std::shared_ptr<GeomAPI_Pnt2d> & theStartPoint,
                    const std::shared_ptr<GeomAPI_Pnt2d> & theEndPoint);
+
+  /// List of lines composing rectangle
+  SKETCHAPI_EXPORT std::list<std::shared_ptr<SketchAPI_SketchEntity> > lines() const;
 };
 
 //! Pointer on Rectangle object
index b3b26c0d0dce7468c026f8837b7d5bf6bb5c61e7..5f36a0872b89739ee9b13bbe9dfe7da691049ed7 100644 (file)
@@ -25,6 +25,8 @@
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_Fillet.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
@@ -41,6 +43,7 @@
 #include <SketchPlugin_ConstraintVertical.h>
 #include <SketcherPrs_Tools.h>
 //--------------------------------------------------------------------------------------
+#include <ModelAPI_Events.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelHighAPI_Double.h>
 #include "SketchAPI_Rotation.h"
 #include "SketchAPI_Translation.h"
 //--------------------------------------------------------------------------------------
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+#include <cmath>
+//--------------------------------------------------------------------------------------
 SketchAPI_Sketch::SketchAPI_Sketch(
     const std::shared_ptr<ModelAPI_Feature> & theFeature)
 : ModelHighAPI_Interface(theFeature)
@@ -451,19 +458,25 @@ std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const std::string & theE
 
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
-    const ModelHighAPI_Selection & theExternalFeature)
+    const ModelHighAPI_Selection & theExternalFeature,
+    bool theKeepResult)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Projection::ID());
-  return ProjectionPtr(new SketchAPI_Projection(aFeature, theExternalFeature));
+  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalFeature));
+  aProjection->setIncludeToResult(theKeepResult);
+  return aProjection;
 }
 
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
-    const std::string & theExternalName)
+    const std::string & theExternalName,
+    bool theKeepResult)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Projection::ID());
-  return ProjectionPtr(new SketchAPI_Projection(aFeature, theExternalName));
+  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalName));
+  aProjection->setIncludeToResult(theKeepResult);
+  return aProjection;
 }
 
 //--------------------------------------------------------------------------------------
@@ -620,13 +633,59 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setCollinear(
 std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setDistance(
     const ModelHighAPI_RefAttr & thePoint,
     const ModelHighAPI_RefAttr & thePointOrLine,
-    const ModelHighAPI_Double & theValue)
+    const ModelHighAPI_Double & theValue,
+    bool isSigned)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
       compositeFeature()->addFeature(SketchPlugin_ConstraintDistance::ID());
   fillAttribute(thePoint, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(thePointOrLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
   fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  fillAttribute(isSigned, aFeature->boolean(SketchPlugin_ConstraintDistance::SIGNED()));
+  aFeature->execute();
+  return InterfacePtr(new ModelHighAPI_Interface(aFeature));
+}
+
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setSignedDistance(
+    const ModelHighAPI_RefAttr & thePoint,
+    const ModelHighAPI_RefAttr & thePointOrLine,
+    const ModelHighAPI_Double & theValue)
+{
+  return setDistance(thePoint, thePointOrLine, theValue, true);
+}
+
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setUnsignedDistance(
+    const ModelHighAPI_RefAttr & thePoint,
+    const ModelHighAPI_RefAttr & thePointOrLine,
+    const ModelHighAPI_Double & theValue)
+{
+  return setDistance(thePoint, thePointOrLine, theValue, false);
+}
+
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setHorizontalDistance(
+    const ModelHighAPI_RefAttr & thePoint1,
+    const ModelHighAPI_RefAttr & thePoint2,
+    const ModelHighAPI_Double & theValue)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceHorizontal::ID());
+  fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
+  fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
+  fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  aFeature->execute();
+  return InterfacePtr(new ModelHighAPI_Interface(aFeature));
+}
+
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setVerticalDistance(
+    const ModelHighAPI_RefAttr & thePoint1,
+    const ModelHighAPI_RefAttr & thePoint2,
+    const ModelHighAPI_Double & theValue)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+      compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceVertical::ID());
+  fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
+  fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
+  fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
@@ -775,6 +834,127 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setVertical(
 
 //--------------------------------------------------------------------------------------
 
+static std::shared_ptr<GeomAPI_Pnt2d> pointCoordinates(const AttributePtr& thePoint)
+{
+  AttributePoint2DPtr aPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint);
+  if (aPnt)
+    return aPnt->pnt();
+  return std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnLine(const FeaturePtr& theFeature)
+{
+  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::START_ID()));
+  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::END_ID()));
+
+  if (!aStartAttr || !aEndAttr)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  std::shared_ptr<GeomAPI_XY> aStartPoint = aStartAttr->pnt()->xy();
+  std::shared_ptr<GeomAPI_XY> aEndPoint = aEndAttr->pnt()->xy();
+  return std::shared_ptr<GeomAPI_Pnt2d>(
+      new GeomAPI_Pnt2d(aStartPoint->added(aEndPoint)->multiplied(0.5)));
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> pointOnCircle(const FeaturePtr& theFeature)
+{
+  AttributePoint2DPtr aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Circle::CENTER_ID()));
+  AttributeDoublePtr aRadius = theFeature->real(SketchPlugin_Circle::RADIUS_ID());
+
+  if (!aCenter || !aRadius)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  return std::shared_ptr<GeomAPI_Pnt2d>(
+      new GeomAPI_Pnt2d(aCenter->x() + aRadius->value(), aCenter->y()));
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnArc(const FeaturePtr& theFeature)
+{
+  static const double PI = 3.141592653589793238463;
+
+  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
+  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::START_ID()));
+  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::END_ID()));
+
+  if (!aCenterAttr || !aStartAttr || !aEndAttr)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
+      aStartAttr->x() - aCenterAttr->x(), aStartAttr->y() - aCenterAttr->y()));
+  std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
+      aEndAttr->x() - aCenterAttr->x(), aEndAttr->y() - aCenterAttr->y()));
+
+  double anAngle = aStartDir->angle(aEndDir);
+  bool isReversed = theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
+  if (isReversed && anAngle > 0.)
+    anAngle -= 2.0 * PI;
+  else if (!isReversed && anAngle <= 0.)
+    anAngle += 2.0 * PI;
+
+  double cosA = cos(anAngle);
+  double sinA = sin(anAngle);
+
+  // rotate start dir to find middle point on arc
+  double aRadius = aStartAttr->pnt()->distance(aCenterAttr->pnt());
+  double x = aCenterAttr->x() + aRadius * (aStartDir->x() * cosA - aStartDir->y() * sinA);
+  double y = aCenterAttr->y() + aRadius * (aStartDir->x() * sinA + aStartDir->y() * cosA);
+
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
+{
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  if (aFeature) {
+    const std::string& aFeatureKind = aFeature->getKind();
+    if (aFeatureKind == SketchPlugin_Point::ID())
+      return pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID()));
+    else if (aFeatureKind == SketchPlugin_Line::ID())
+      return middlePointOnLine(aFeature);
+    else if (aFeatureKind == SketchPlugin_Circle::ID())
+      return pointOnCircle(aFeature);
+    else if (aFeatureKind == SketchPlugin_Arc::ID())
+      return middlePointOnArc(aFeature);
+  }
+  // do not move other types of features
+  return std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
+void SketchAPI_Sketch::move(const ModelHighAPI_RefAttr& theMovedEntity,
+                            const std::shared_ptr<GeomAPI_Pnt2d>& theTargetPoint)
+{
+  std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(new ModelAPI_ObjectMovedMessage);
+  theMovedEntity.fillMessage(aMessage);
+
+  std::shared_ptr<GeomAPI_Pnt2d> anOriginalPosition;
+  if (aMessage->movedAttribute())
+    anOriginalPosition = pointCoordinates(aMessage->movedAttribute());
+  else
+    anOriginalPosition = middlePoint(aMessage->movedObject());
+
+  if (!anOriginalPosition)
+    return; // something has gone wrong, do not process movement
+
+  aMessage->setOriginalPosition(anOriginalPosition);
+  aMessage->setCurrentPosition(theTargetPoint);
+  Events_Loop::loop()->send(aMessage);
+}
+
+void SketchAPI_Sketch::move(const ModelHighAPI_RefAttr& theMovedEntity,
+                            double theTargetX, double theTargetY)
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aTargetPoint(new GeomAPI_Pnt2d(theTargetX, theTargetY));
+  move(theMovedEntity, aTargetPoint);
+}
+
+//--------------------------------------------------------------------------------------
+
 std::shared_ptr<GeomAPI_Pnt2d> SketchAPI_Sketch::to2D(const std::shared_ptr<GeomAPI_Pnt>& thePoint)
 {
   FeaturePtr aBase = feature();
index b62e9c3af6edb2d679861497bac4d0baf31e2a1d..3e531012dcfc64b7721e9d80aaa0c3d20335797e 100644 (file)
@@ -251,11 +251,13 @@ public:
   /// Add projection
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_Projection> addProjection(
-      const ModelHighAPI_Selection & theExternalFeature);
+      const ModelHighAPI_Selection & theExternalFeature,
+      bool theKeepResult = false);
 
   /// Add projection
   SKETCHAPI_EXPORT
-  std::shared_ptr<SketchAPI_Projection> addProjection(const std::string & theExternalName);
+  std::shared_ptr<SketchAPI_Projection> addProjection(const std::string & theExternalName,
+                                                      bool theKeepResult = false);
 
   /// Add mirror
   SKETCHAPI_EXPORT
@@ -329,10 +331,39 @@ public:
   /// Set distance
   SKETCHAPI_EXPORT
   std::shared_ptr<ModelHighAPI_Interface> setDistance(
+      const ModelHighAPI_RefAttr & thePoint,
+      const ModelHighAPI_RefAttr & thePointOrLine,
+      const ModelHighAPI_Double & theValue,
+      bool isSigned = false);
+
+  /// Set signed distance
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setSignedDistance(
+      const ModelHighAPI_RefAttr & thePoint,
+      const ModelHighAPI_RefAttr & thePointOrLine,
+      const ModelHighAPI_Double & theValue);
+
+  /// Set unsigned distance
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setUnsignedDistance(
       const ModelHighAPI_RefAttr & thePoint,
       const ModelHighAPI_RefAttr & thePointOrLine,
       const ModelHighAPI_Double & theValue);
 
+  /// Set horizontal distance
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setHorizontalDistance(
+      const ModelHighAPI_RefAttr & thePoint1,
+      const ModelHighAPI_RefAttr & thePoint2,
+      const ModelHighAPI_Double & theValue);
+
+  /// Set vertical distance
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setVerticalDistance(
+      const ModelHighAPI_RefAttr & thePoint1,
+      const ModelHighAPI_RefAttr & thePoint2,
+      const ModelHighAPI_Double & theValue);
+
   /// Set equal
   SKETCHAPI_EXPORT
   std::shared_ptr<ModelHighAPI_Interface> setEqual(
@@ -407,6 +438,16 @@ public:
       const std::shared_ptr<ModelHighAPI_Interface> & theConstraint,
       const ModelHighAPI_Double & theValue);
 
+  /// Move point or sketch feature
+  SKETCHAPI_EXPORT
+  void move(const ModelHighAPI_RefAttr& theMovedEntity,
+            const std::shared_ptr<GeomAPI_Pnt2d>& theTargetPoint);
+
+  /// Move point or sketch feature
+  SKETCHAPI_EXPORT
+  void move(const ModelHighAPI_RefAttr& theMovedEntity,
+            double theTargetX, double theTargetY);
+
   SKETCHAPI_EXPORT
   std::shared_ptr<GeomAPI_Pnt2d> to2D(const std::shared_ptr<GeomAPI_Pnt>& thePoint);
 
index ba06dbe55faa650a1fec3ded65150e0f93f9d63d..7c89b5e5c2f6270098d37e92824cdda19841089f 100644 (file)
@@ -31,6 +31,8 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintCoincidence.h
     SketchPlugin_ConstraintCollinear.h
     SketchPlugin_ConstraintDistance.h
+    SketchPlugin_ConstraintDistanceHorizontal.h
+    SketchPlugin_ConstraintDistanceVertical.h
     SketchPlugin_ConstraintEqual.h
     SketchPlugin_Fillet.h
     SketchPlugin_ConstraintHorizontal.h
@@ -43,6 +45,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintRigid.h
     SketchPlugin_ConstraintTangent.h
     SketchPlugin_ConstraintVertical.h
+    SketchPlugin_Ellipse.h
     SketchPlugin_ExternalValidator.h
     SketchPlugin_Feature.h
     SketchPlugin_IntersectionPoint.h
@@ -50,6 +53,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_MacroArc.h
     SketchPlugin_MacroArcReentrantMessage.h
     SketchPlugin_MacroCircle.h
+    SketchPlugin_MacroEllipse.h
     SketchPlugin_MultiRotation.h
     SketchPlugin_MultiTranslation.h
     SketchPlugin_Plugin.h
@@ -72,6 +76,8 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintCoincidence.cpp
     SketchPlugin_ConstraintCollinear.cpp
     SketchPlugin_ConstraintDistance.cpp
+    SketchPlugin_ConstraintDistanceHorizontal.cpp
+    SketchPlugin_ConstraintDistanceVertical.cpp
     SketchPlugin_ConstraintEqual.cpp
     SketchPlugin_Fillet.cpp
     SketchPlugin_ConstraintHorizontal.cpp
@@ -84,12 +90,14 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintRigid.cpp
     SketchPlugin_ConstraintTangent.cpp
     SketchPlugin_ConstraintVertical.cpp
+    SketchPlugin_Ellipse.cpp
     SketchPlugin_ExternalValidator.cpp
     SketchPlugin_Feature.cpp
     SketchPlugin_IntersectionPoint.cpp
     SketchPlugin_Line.cpp
     SketchPlugin_MacroArc.cpp
     SketchPlugin_MacroCircle.cpp
+    SketchPlugin_MacroEllipse.cpp
     SketchPlugin_MultiRotation.cpp
     SketchPlugin_MultiTranslation.cpp
     SketchPlugin_Plugin.cpp
@@ -155,11 +163,15 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestConstraintCollinear.py
                TestConstraintLength.py
                TestConstraintDistance.py
+               TestConstraintDistanceHorizontal.py
+               TestConstraintDistanceVertical.py
+               TestConstraintDistanceBehavior.py
                TestConstraintParallel.py
                TestConstraintPerpendicular.py
                TestConstraintRadius.py
                TestConstraintFixed.py
                TestConstraintHorizontal.py
+               TestConstraintHorizontalValidator.py
                TestConstraintVertical.py
                TestConstraintEqual.py
                TestConstraintTangent.py
@@ -172,6 +184,7 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestFilletInteracting.py
                TestRectangle.py
                TestProjection.py
+               TestProjectionIntoResult.py
                TestSplit.py
                TestHighload.py
                TestSnowflake.py
@@ -201,4 +214,21 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestTrimLine02.py
                Test2229.py
                Test2239.py
+               TestDistanceSignedVsUnsigned01.py
+               TestDistanceSignedVsUnsigned02.py
+               TestDistanceSignedVsUnsigned03.py
+               TestDistanceSignedVsUnsigned04.py
+               TestDistanceSignedVsUnsigned05.py
+               TestSignedDistancePointPoint.py
+               TestSignedDistancePointLine.py
 )
+
+if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
+  ADD_UNIT_TESTS(
+               TestMovePoint.py
+               TestMoveLine.py
+               TestMoveCircle.py
+               TestMoveArc.py
+               TestMovementComplex.py
+  )
+endif()
\ No newline at end of file
index 6c5f2e884b6c4dde43be996800c57226b22e3fbf..d8b03f5a83381c3e92f53e2afc36030ab3597a3d 100644 (file)
@@ -135,36 +135,6 @@ void SketchPlugin_Arc::execute()
   setResult(aResult, 1);
 }
 
-void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if(!aData->isValid()) {
-    return;
-  }
-
-  bool aWasBlocked = aData->blockSendAttributeUpdated(true);
-
-  std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      attribute(CENTER_ID()));
-  if(aCenter->isInitialized()) {
-    aCenter->move(theDeltaX, theDeltaY);
-  }
-
-  std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      attribute(START_ID()));
-  if(aStart->isInitialized()) {
-    aStart->move(theDeltaX, theDeltaY);
-  }
-
-  std::shared_ptr<GeomDataAPI_Point2D> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      attribute(END_ID()));
-  if(anEnd->isInitialized()) {
-    anEnd->move(theDeltaX, theDeltaY);
-  }
-
-  aData->blockSendAttributeUpdated(aWasBlocked);
-}
-
 bool SketchPlugin_Arc::isFixed()
 {
   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
index 38c565b738768625993aa115ad26558fa40e4c30..b9dd9ed8fd5732615f64ea0bd45a2189842df60c 100644 (file)
@@ -103,11 +103,6 @@ class SketchPlugin_Arc: public SketchPlugin_SketchEntity
   /// Creates an arc-shape
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Updates the "reversed" flag
   /// \param isReversed  whether the arc will be reversed
   void setReversed(bool isReversed);
index 77ea5d998ae950b3faf19c56c965cd61c4333519..0975e57e43db79f00e2bde9e7f1bc3a8b6fda85b 100644 (file)
@@ -96,20 +96,6 @@ void SketchPlugin_Circle::execute()
   setResult(aResult, 1);
 }
 
-void SketchPlugin_Circle::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if(!aData->isValid()) {
-    return;
-  }
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aData->attribute(CENTER_ID()));
-  if(aPoint->isInitialized()) {
-    aPoint->move(theDeltaX, theDeltaY);
-  }
-}
-
 bool SketchPlugin_Circle::isFixed() {
   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
 }
index 6bc4050d86571c0e615d456af1803b4e608e1033..ea95823d87b5bc83dd45c96287f887ee588ae560 100644 (file)
@@ -69,11 +69,6 @@ class SketchPlugin_Circle: public SketchPlugin_SketchEntity
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Use plugin manager for features creation
   SketchPlugin_Circle();
 
index 3d2440b154b49fdec541e78000417988201c493d..14815ed666a854c70bbe50069b957b1d1dd37f5e 100644 (file)
@@ -269,20 +269,6 @@ void SketchPlugin_ConstraintAngle::updateConstraintValueByAngleValue()
   aValueAttr->setValue(anAngle);
 }
 
-void SketchPlugin_ConstraintAngle::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if (!aData->isValid())
-    return;
-
-  myFlyoutUpdate = true;
-  std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
-      GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
-  aFlyoutAttr->setValue(aFlyoutAttr->x() + theDeltaX, aFlyoutAttr->y() + theDeltaY);
-  myFlyoutUpdate = false;
-}
-
-
 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
 {
   if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
index ce7e5f79542c1eeb5a81b5e41e4153b167cb1de2..ba00fbc9d76449eb5753dd92b1f666efe9b67cbd 100644 (file)
@@ -97,11 +97,6 @@ class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Calculate current value of the angle
   double calculateAngle();
 
index 19037692fd9c58d12bb39f393dfb920488f4ceb4..0a499442b65045fc305851e9c365bc92a1156475 100644 (file)
@@ -29,9 +29,3 @@ const void SketchPlugin_ConstraintBase::addSub(const FeaturePtr& theFeature)
 {
 
 }
-
-void SketchPlugin_ConstraintBase::move(const double theDeltaX, const double theDeltaY)
-{
-
-}
-
index a30139b0226832da415452142a6f3a707df6c3f0..9c65757d6355809ed4a8a0c34fa11731b2302bc9 100644 (file)
@@ -64,10 +64,6 @@ class SketchPlugin_ConstraintBase : public SketchPlugin_Constraint, public GeomA
    *  \param theFeature sub-feature
    */
   SKETCHPLUGIN_EXPORT virtual const void addSub(const FeaturePtr& theFeature);
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
 
       /// Customize presentation of the feature
   virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
index ef3a7a5687197860d02fe3244e45c29ab4835508..e36287b4c35f2f8f4212f8c37cadc03256e9b8f5 100644 (file)
@@ -41,8 +41,8 @@ AISObjectPtr SketchPlugin_ConstraintCollinear::getAISObject(AISObjectPtr thePrev
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::collinearConstraint(this, sketch()->coordinatePlane(),
-                                                                thePrevious);
+  AISObjectPtr anAIS = SketcherPrs_Factory::collinearConstraint(
+      this, sketch(), sketch()->coordinatePlane(), thePrevious);
   return anAIS;
 }
 
index 4d299b6b01d848532fdda463e70a51b18271ccd6..9566988fd570640bb00298148e6a39e9d2756479 100644 (file)
@@ -54,6 +54,7 @@ void SketchPlugin_ConstraintDistance::initAttributes()
   data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(SIGNED(), ModelAPI_AttributeBoolean::typeId());
 }
 
 void SketchPlugin_ConstraintDistance::colorConfigInfo(std::string& theSection, std::string& theName,
@@ -91,60 +92,6 @@ AISObjectPtr SketchPlugin_ConstraintDistance::getAISObject(AISObjectPtr thePrevi
   return anAIS;
 }
 
-//*************************************************************************************
-void SketchPlugin_ConstraintDistance::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if (!aData->isValid())
-    return;
-
-  // Recalculate a shift of flyout point in terms of local coordinates
-  std::shared_ptr<GeomAPI_XY> aDir(new GeomAPI_XY(theDeltaX, theDeltaY));
-  std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
-  std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
-      data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
-  std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
-      data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
-
-  std::shared_ptr<GeomAPI_XY> aStartPnt;
-  std::shared_ptr<GeomAPI_XY> aEndPnt;
-  if (aPointA && aPointB) {
-    aStartPnt = aPointA->pnt()->xy();
-    aEndPnt = aPointB->pnt()->xy();
-  } else if (aPointA) {
-    FeaturePtr aLine = SketcherPrs_Tools::getFeatureLine(data(),
-        SketchPlugin_Constraint::ENTITY_B());
-    if (!aLine)
-      return;
-    std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointA->pnt();
-    aStartPnt = aPoint->xy();
-    aEndPnt = SketcherPrs_Tools::getProjectionPoint(aLine, aPoint)->xy();
-  } else if (aPointB) {
-    FeaturePtr aLine = SketcherPrs_Tools::getFeatureLine(data(),
-        SketchPlugin_Constraint::ENTITY_A());
-    if (!aLine)
-      return;
-    std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointB->pnt();
-    aStartPnt = SketcherPrs_Tools::getProjectionPoint(aLine, aPoint)->xy();
-    aEndPnt = aPoint->xy();
-  } else
-    return;
-
-  std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
-  double dX = aDir->dot(aLineDir->xy());
-  double dY = -aDir->cross(aLineDir->xy());
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
-  myFlyoutUpdate = true;
-  if (aPoint->isInitialized()) {
-    aPoint->setValue(aPoint->x() + dX, aPoint->y() + dY);
-  } else {
-    aPoint->setValue(dX, dY);
-  }
-  myFlyoutUpdate = false;
-}
-
 double SketchPlugin_ConstraintDistance::calculateCurrentDistance()
 {
   double aDistance = -1.;
@@ -178,6 +125,32 @@ double SketchPlugin_ConstraintDistance::calculateCurrentDistance()
   return aDistance;
 }
 
+bool SketchPlugin_ConstraintDistance::areAttributesInitialized()
+{
+  std::shared_ptr<ModelAPI_Data> aData = data();
+  std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+  std::shared_ptr<GeomDataAPI_Point2D> aPointA =
+      SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_A(), aPlane);
+  std::shared_ptr<GeomDataAPI_Point2D> aPointB =
+      SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+  if (!aPointA && !aPointB)
+    return false;
+  else if (aPointA || aPointB) {
+    FeaturePtr aLine;
+    if (!aPointA)
+      aLine = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
+    else if (!aPointB)
+      aLine = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
+    else // both points are initialized
+      return true;
+
+    if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
+      return false;
+  }
+  return true;
+}
+
 void SketchPlugin_ConstraintDistance::attributeChanged(const std::string& theID)
 {
   if (theID == SketchPlugin_Constraint::ENTITY_A() ||
@@ -193,7 +166,6 @@ void SketchPlugin_ConstraintDistance::attributeChanged(const std::string& theID)
       }
     }
   } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
-    myFlyoutUpdate = true;
     // Recalculate flyout point in local coordinates of the distance constraint:
     // the X coordinate is a length of projection of the flyout point on the
     //                  line binding two distanced points
@@ -237,6 +209,7 @@ void SketchPlugin_ConstraintDistance::attributeChanged(const std::string& theID)
     if (aEndPnt->distance(aStartPnt) < tolerance)
       return;
 
+    myFlyoutUpdate = true;
     std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aStartPnt);
 
index 8c96dfa2953824610abfb7d840a889686219ff23..e9e4b1501329863f3161ddb006fe920b4b63dedb 100644 (file)
@@ -58,6 +58,13 @@ class SketchPlugin_ConstraintDistance : public SketchPlugin_ConstraintBase
     return MY_KIND;
   }
 
+  /// \brief Shows whether the point-line distance should keep its sign
+  inline static const std::string& SIGNED()
+  {
+    static const std::string MY_SIGNED("SignedDistance");
+    return MY_SIGNED;
+  }
+
   /// \brief Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
@@ -71,11 +78,6 @@ class SketchPlugin_ConstraintDistance : public SketchPlugin_ConstraintBase
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Called on change of any argument-attribute of this object
   /// \param theID identifier of changed attribute
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
@@ -85,9 +87,12 @@ class SketchPlugin_ConstraintDistance : public SketchPlugin_ConstraintBase
 
 protected:
   /// Returns the current distance between the feature attributes
-  double calculateCurrentDistance();
+  virtual double calculateCurrentDistance();
+
+  /// Check the attributes related to distanced points/features are initialized
+  bool areAttributesInitialized();
 
-private:
+protected:
   bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point
 };
 
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.cpp b/src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.cpp
new file mode 100644 (file)
index 0000000..accd996
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:    SketchPlugin_ConstraintDistanceHorizontal.cpp
+// Created: 2 May 2017
+// Author:  Artem ZHIDKOV
+
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+
+#include <SketcherPrs_Tools.h>
+#include <SketcherPrs_Factory.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_AttributeDouble.h>
+
+const double tolerance = 1e-7;
+
+
+SketchPlugin_ConstraintDistanceHorizontal::SketchPlugin_ConstraintDistanceHorizontal()
+  : SketchPlugin_ConstraintDistance()
+{
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceHorizontal::initAttributes()
+{
+  data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceHorizontal::execute()
+{
+  AttributeDoublePtr anAttrValue = real(SketchPlugin_Constraint::VALUE());
+  if (anAttrValue->isInitialized() || !areAttributesInitialized())
+    return;
+
+  double aDistance = calculateCurrentDistance();
+  anAttrValue->setValue(aDistance);
+}
+
+//*************************************************************************************
+AISObjectPtr SketchPlugin_ConstraintDistanceHorizontal::getAISObject(AISObjectPtr thePrevious)
+{
+  if (!sketch())
+    return thePrevious;
+
+  AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
+                                                                      sketch()->coordinatePlane(),
+                                                                      thePrevious);
+  return anAIS;
+}
+
+double SketchPlugin_ConstraintDistanceHorizontal::calculateCurrentDistance()
+{
+  std::shared_ptr<ModelAPI_Data> aData = data();
+  std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+  std::shared_ptr<GeomDataAPI_Point2D> aPointA =
+    SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_A(), aPlane);
+  std::shared_ptr<GeomDataAPI_Point2D> aPointB =
+      SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+  return aPointB->x() - aPointA->x();
+}
+
+void SketchPlugin_ConstraintDistanceHorizontal::attributeChanged(const std::string& theID)
+{
+  if (theID == SketchPlugin_Constraint::ENTITY_A() ||
+      theID == SketchPlugin_Constraint::ENTITY_B())
+  {
+    AttributeDoublePtr aValueAttr = real(SketchPlugin_Constraint::VALUE());
+    if (!aValueAttr->isInitialized() && areAttributesInitialized()) {
+      // only if it is not initialized, try to compute the current value
+      double aDistance = calculateCurrentDistance();
+      aValueAttr->setValue(aDistance);
+    }
+  } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
+    // Recalculate flyout point in local coordinates of the distance constraint:
+    // the X coordinate is a length of projection of the flyout point on the
+    //                  line binding two distanced points
+    //                  or a line of projection of the distanced point onto the distanced segment
+    // the Y coordinate is a distance from the flyout point to the line
+    std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+    std::shared_ptr<GeomAPI_Pnt2d> aFlyoutPnt = aFlyoutAttr->pnt();
+
+    std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+    std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
+        data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
+    std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
+        data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+    std::shared_ptr<GeomAPI_XY> aStartPnt = aPointA->pnt()->xy();
+    std::shared_ptr<GeomAPI_XY> aEndPnt = aPointB->pnt()->xy();
+    if (aEndPnt->distance(aStartPnt) < tolerance)
+      return;
+
+    myFlyoutUpdate = true;
+    std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aEndPnt);
+    double X = aFlyoutDir->x(); // Dot on OX axis
+    double Y = aFlyoutDir->y(); // Cross to OX axis
+    aFlyoutAttr->setValue(X, Y);
+    myFlyoutUpdate = false;
+  }
+}
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.h b/src/SketchPlugin/SketchPlugin_ConstraintDistanceHorizontal.h
new file mode 100644 (file)
index 0000000..e8f6cb8
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:    SketchPlugin_ConstraintDistanceHorizontal.h
+// Created: 2 May 2017
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintDistanceHorizontal_H_
+#define SketchPlugin_ConstraintDistanceHorizontal_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_ConstraintDistance.h>
+
+/** \class SketchPlugin_ConstraintDistanceHorizontal
+ *  \ingroup Plugins
+ *  \brief Feature for creation of a new constraint which defines a horizontal distance between two points.
+ *
+ *  This constraint has three attributes:
+ *  SketchPlugin_Constraint::VALUE(), SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintDistanceHorizontal : public SketchPlugin_ConstraintDistance
+{
+public:
+  /// Distance constraint kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistanceHorizontal");
+    return MY_CONSTRAINT_DISTANCE_ID;
+  }
+
+  /// \brief Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_ConstraintDistanceHorizontal::ID();
+    return MY_KIND;
+  }
+
+  /// \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();
+
+  /// Returns the AIS preview
+  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Called on change of any argument-attribute of this object
+  /// \param theID identifier of changed attribute
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintDistanceHorizontal();
+
+protected:
+  /// Returns the current distance between the feature attributes
+  virtual double calculateCurrentDistance();
+};
+
+#endif
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.cpp b/src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.cpp
new file mode 100644 (file)
index 0000000..e9f645a
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:    SketchPlugin_ConstraintDistanceVertical.cpp
+// Created: 10 May 2017
+// Author:  Artem ZHIDKOV
+
+#include <SketchPlugin_ConstraintDistanceVertical.h>
+
+#include <SketcherPrs_Tools.h>
+#include <SketcherPrs_Factory.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_AttributeDouble.h>
+
+const double tolerance = 1e-7;
+
+
+SketchPlugin_ConstraintDistanceVertical::SketchPlugin_ConstraintDistanceVertical()
+  : SketchPlugin_ConstraintDistance()
+{
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceVertical::initAttributes()
+{
+  data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceVertical::execute()
+{
+  AttributeDoublePtr anAttrValue = real(SketchPlugin_Constraint::VALUE());
+  if (anAttrValue->isInitialized() || !areAttributesInitialized())
+    return;
+
+  double aDistance = calculateCurrentDistance();
+  anAttrValue->setValue(aDistance);
+}
+
+//*************************************************************************************
+AISObjectPtr SketchPlugin_ConstraintDistanceVertical::getAISObject(AISObjectPtr thePrevious)
+{
+  if (!sketch())
+    return thePrevious;
+
+  AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
+                                                                      sketch()->coordinatePlane(),
+                                                                      thePrevious);
+  return anAIS;
+}
+
+double SketchPlugin_ConstraintDistanceVertical::calculateCurrentDistance()
+{
+  std::shared_ptr<ModelAPI_Data> aData = data();
+  std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+  std::shared_ptr<GeomDataAPI_Point2D> aPointA =
+    SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_A(), aPlane);
+  std::shared_ptr<GeomDataAPI_Point2D> aPointB =
+      SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+  return aPointB->y() - aPointA->y();
+}
+
+void SketchPlugin_ConstraintDistanceVertical::attributeChanged(const std::string& theID)
+{
+  if (theID == SketchPlugin_Constraint::ENTITY_A() ||
+      theID == SketchPlugin_Constraint::ENTITY_B())
+  {
+    AttributeDoublePtr aValueAttr = real(SketchPlugin_Constraint::VALUE());
+    if (!aValueAttr->isInitialized() && areAttributesInitialized()) {
+      // only if it is not initialized, try to compute the current value
+      double aDistance = calculateCurrentDistance();
+      aValueAttr->setValue(aDistance);
+    }
+  } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
+    // Recalculate flyout point in local coordinates of the distance constraint:
+    // the X coordinate is a length of projection of the flyout point on the
+    //                  line binding two distanced points
+    //                  or a line of projection of the distanced point onto the distanced segment
+    // the Y coordinate is a distance from the flyout point to the line
+    std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+    std::shared_ptr<GeomAPI_Pnt2d> aFlyoutPnt = aFlyoutAttr->pnt();
+
+    std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+    std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
+        data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
+    std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
+        data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+    std::shared_ptr<GeomAPI_XY> aStartPnt = aPointA->pnt()->xy();
+    std::shared_ptr<GeomAPI_XY> aEndPnt = aPointB->pnt()->xy();
+
+    if (aEndPnt->distance(aStartPnt) < tolerance)
+      return;
+
+    std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aEndPnt);
+    myFlyoutUpdate = true;
+    double X =  aFlyoutDir->y(); // Dot on OY axis
+    double Y = -aFlyoutDir->x(); // Cross to OY axis
+    aFlyoutAttr->setValue(X, Y);
+    myFlyoutUpdate = false;
+  }
+}
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.h b/src/SketchPlugin/SketchPlugin_ConstraintDistanceVertical.h
new file mode 100644 (file)
index 0000000..2cdb36d
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:    SketchPlugin_ConstraintDistanceVertical.h
+// Created: 10 May 2017
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintDistanceVertical_H_
+#define SketchPlugin_ConstraintDistanceVertical_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_ConstraintDistance.h>
+
+/** \class SketchPlugin_ConstraintDistanceVertical
+ *  \ingroup Plugins
+ *  \brief Feature for creation of a new constraint which defines a vertical distance between two points.
+ *
+ *  This constraint has three attributes:
+ *  SketchPlugin_Constraint::VALUE(), SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintDistanceVertical : public SketchPlugin_ConstraintDistance
+{
+public:
+  /// Distance constraint kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistanceVertical");
+    return MY_CONSTRAINT_DISTANCE_ID;
+  }
+
+  /// \brief Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_ConstraintDistanceVertical::ID();
+    return MY_KIND;
+  }
+
+  /// \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();
+
+  /// Returns the AIS preview
+  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Called on change of any argument-attribute of this object
+  /// \param theID identifier of changed attribute
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintDistanceVertical();
+
+protected:
+  /// Returns the current distance between the feature attributes
+  virtual double calculateCurrentDistance();
+};
+
+#endif
index 3605f1af5788437fa6bff1f4dea10e4281b30b56..7be8935aa2d9b52aff0d55ae7691c788e5c16834 100644 (file)
@@ -50,7 +50,8 @@ AISObjectPtr SketchPlugin_ConstraintEqual::getAISObject(AISObjectPtr thePrevious
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::equalConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::equalConstraint(this, sketch(),
+                                                            sketch()->coordinatePlane(),
                                                             thePrevious);
   return anAIS;
 }
index 81612bc20f04e1dde79d94068520e9de35ba40b8..6ebf472e8f8157c0cc1fb38e15d9b9ba1f2f555d 100644 (file)
@@ -50,7 +50,8 @@ AISObjectPtr SketchPlugin_ConstraintHorizontal::getAISObject(AISObjectPtr thePre
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::horisontalConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::horisontalConstraint(this, sketch(),
+                                                                 sketch()->coordinatePlane(),
                                                                  thePrevious);
   return anAIS;
 }
index 36932d4ddee7442002e25a7cc3419c09a320f014..504314fbd293b7a98c91b1b684c681d9b2ed0427 100644 (file)
@@ -165,37 +165,6 @@ AISObjectPtr SketchPlugin_ConstraintLength::getAISObject(AISObjectPtr thePreviou
   return anAIS;
 }
 
-void SketchPlugin_ConstraintLength::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if (!aData->isValid())
-    return;
-
-  AttributeRefAttrPtr aLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      attribute(SketchPlugin_Constraint::ENTITY_A()));
-  if (!aLineAttr || !aLineAttr->isObject())
-    return;
-  FeaturePtr aLine = ModelAPI_Feature::feature(aLineAttr->object());
-  if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
-    return;
-
-  // Recalculate a shift of flyout point in terms of local coordinates
-  std::shared_ptr<GeomAPI_XY> aDir(new GeomAPI_XY(theDeltaX, theDeltaY));
-  std::shared_ptr<GeomAPI_XY> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLine->attribute(SketchPlugin_Line::START_ID()))->pnt()->xy();
-  std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
-  std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
-  double dX = aDir->dot(aLineDir->xy());
-  double dY = -aDir->cross(aLineDir->xy());
-
-  myFlyoutUpdate = true;
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
-  aPoint->setValue(aPoint->x() + dX, aPoint->y() + dY);
-  myFlyoutUpdate = false;
-}
-
 void SketchPlugin_ConstraintLength::attributeChanged(const std::string& theID) {
   if (theID == SketchPlugin_Constraint::ENTITY_A())
   {
@@ -208,7 +177,6 @@ void SketchPlugin_ConstraintLength::attributeChanged(const std::string& theID) {
         aValueAttr->setValue(aLength);
     }
   } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
-    myFlyoutUpdate = true;
     // Recalculate flyout point in local coordinates of the line:
     // the X coordinate is a length of projection of the flyout point on the line
     // the Y coordinate is a distance from the point to the line
@@ -229,6 +197,7 @@ void SketchPlugin_ConstraintLength::attributeChanged(const std::string& theID) {
     std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
         aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
 
+    myFlyoutUpdate = true;
     std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aStartPnt);
     double X = aFlyoutDir->dot(aLineDir->xy());
index 042201613e5df694b13d24f02ebfe0800b9b447a..50e9ebb9b5c10654b0b39d3c11b89a552cd20ad4 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <list>
 
+class GeomAPI_Pnt2d;
 class GeomDataAPI_Point2D;
 
 /** \class SketchPlugin_ConstraintLength
@@ -73,11 +74,6 @@ class SketchPlugin_ConstraintLength : public SketchPlugin_ConstraintBase
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Called on change of any argument-attribute of this object
   /// \param theID identifier of changed attribute
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
index 06d01f8edc09ae904e49d0d35ccc547c30d1e588..620b0691ab8533023c7a11127cf1a8d7fcc8ec27 100644 (file)
@@ -41,7 +41,8 @@ AISObjectPtr SketchPlugin_ConstraintMiddle::getAISObject(AISObjectPtr thePreviou
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::middleConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::middleConstraint(this, sketch(),
+                                                             sketch()->coordinatePlane(),
                                                              thePrevious);
   return anAIS;
 }
index e4c6ed4ed3d2d63d20034317429e28b1cec86beb..ec7be3a799ce2bffabe5a2e6bbea54f9d4434445 100755 (executable)
@@ -209,7 +209,8 @@ AISObjectPtr SketchPlugin_ConstraintMirror::getAISObject(AISObjectPtr thePreviou
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::mirrorConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::mirrorConstraint(this, sketch(),
+                                                             sketch()->coordinatePlane(),
                                                              thePrevious);
   return anAIS;
 }
index 68f041749b9c5f9096621c652d107a4ceb45795d..9ddda85aa439c0873fa1bf99c1e9a23b1e205b8a 100644 (file)
@@ -56,7 +56,8 @@ AISObjectPtr SketchPlugin_ConstraintParallel::getAISObject(AISObjectPtr thePrevi
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::parallelConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::parallelConstraint(this, sketch(),
+                                                               sketch()->coordinatePlane(),
                                                                thePrevious);
   return anAIS;
 }
index f60e3492e791584addf9fb507687bb774f0be39a..258e30dc0b5b6dbeb91652362159c968ac5faef4 100644 (file)
@@ -55,7 +55,7 @@ AISObjectPtr SketchPlugin_ConstraintPerpendicular::getAISObject(AISObjectPtr the
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::perpendicularConstraint(this,
+  AISObjectPtr anAIS = SketcherPrs_Factory::perpendicularConstraint(this, sketch(),
     sketch()->coordinatePlane(), thePrevious);
   return anAIS;
 }
index 41be22e742475117d7a225e9fdbf7347fee0f963..16c7b60326aa4e775d6b084fbcec0d8b34aa1720 100644 (file)
@@ -173,19 +173,6 @@ AISObjectPtr SketchPlugin_ConstraintRadius::getAISObject(AISObjectPtr thePreviou
   return anAIS;
 }
 
-void SketchPlugin_ConstraintRadius::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if (!aData->isValid())
-    return;
-
-  myFlyoutUpdate = true;
-  std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
-      GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
-  aFlyoutAttr->setValue(aFlyoutAttr->x() + theDeltaX, aFlyoutAttr->y() + theDeltaY);
-  myFlyoutUpdate = false;
-}
-
 void SketchPlugin_ConstraintRadius::attributeChanged(const std::string& theID) {
   if (theID == SketchPlugin_Constraint::ENTITY_A()) {
     std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
index d4ad2f5979de525e20f573d1b6df27914401a46c..cdb83eccd522b6ada6ea80c62450dd8bd249b3af 100644 (file)
@@ -67,11 +67,6 @@ class SketchPlugin_ConstraintRadius : public SketchPlugin_ConstraintBase
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Called on change of any argument-attribute of this object
   /// \param theID identifier of changed attribute
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
index 042b2df1aaffedee30438534821bb8d847d0e9ad..67eba8044c0a570e7e5345aea324fed89a17b612 100644 (file)
@@ -47,5 +47,6 @@ AISObjectPtr SketchPlugin_ConstraintRigid::getAISObject(AISObjectPtr thePrevious
 {
   if (!sketch())
     return thePrevious;
-  return SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane(), thePrevious);
+  return SketcherPrs_Factory::rigidConstraint(this, sketch(),
+                                              sketch()->coordinatePlane(), thePrevious);
 }
\ No newline at end of file
index 2dc22943e7bdba2c159562a1031569a1ee1f2f3f..37fa4e0de354499265d75c4340a794105954740e 100644 (file)
@@ -50,7 +50,8 @@ AISObjectPtr SketchPlugin_ConstraintTangent::getAISObject(AISObjectPtr thePrevio
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::tangentConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::tangentConstraint(this, sketch(),
+                                                              sketch()->coordinatePlane(),
                                                               thePrevious);
   return anAIS;
 }
index 8a03d77ef76e1deb29012e60d5a42e8d359cc381..3debcfd378d08e9b225e5081e48f7af479ef2448 100644 (file)
@@ -49,7 +49,8 @@ AISObjectPtr SketchPlugin_ConstraintVertical::getAISObject(AISObjectPtr thePrevi
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::verticalConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::verticalConstraint(this, sketch(),
+                                                               sketch()->coordinatePlane(),
                                                                thePrevious);
   return anAIS;
 }
diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.cpp b/src/SketchPlugin/SketchPlugin_Ellipse.cpp
new file mode 100644 (file)
index 0000000..b7ec057
--- /dev/null
@@ -0,0 +1,136 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto: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_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+static const double tolerance = 1e-7;
+
+
+SketchPlugin_Ellipse::SketchPlugin_Ellipse()
+: SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_Ellipse::initDerivedClassAttributes()
+{
+  data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_Ellipse::execute()
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if(!aSketch) {
+    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()));
+
+  // 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);
+}
+
+bool SketchPlugin_Ellipse::isFixed() {
+  return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_Ellipse::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();
+
+      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(FOCUS_ID()));
+      aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+
+      real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+      real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+    }
+  }
+}
diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.h b/src/SketchPlugin/SketchPlugin_Ellipse.h
new file mode 100644 (file)
index 0000000..fe0873f
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        SketchPlugin_Ellipse.h
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef SketchPlugin_Ellipse_H_
+#define SketchPlugin_Ellipse_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_Ellipse
+ * \ingroup Plugins
+ * \brief Feature for creation of the new ellipse in Sketch.
+ */
+class SketchPlugin_Ellipse: public SketchPlugin_SketchEntity
+{
+ public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchEllipse");
+    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 - focus of the ellipse
+  inline static const std::string& FOCUS_ID()
+  {
+    static const std::string ID("ellipse_focus");
+    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;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_Ellipse::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_Ellipse();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+};
+
+#endif
index a780d5e10efc223bf7f27575b36c679e4a63b911..a9823830700559907394b85759940a911e842a53 100644 (file)
@@ -65,11 +65,6 @@ class SketchPlugin_Feature : public ModelAPI_Feature
     return true;
   }
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) = 0;
-
   /// Construction result is allways recomuted on the fly
   SKETCHPLUGIN_EXPORT virtual bool isPersistentResult() {return false;}
 
index a7ff0b68e92136d1148de98f62cb457aadb869e8..a391b22e6a31f49d5c9a9a373575db2833dd75bd 100644 (file)
@@ -52,10 +52,6 @@ void SketchPlugin_IntersectionPoint::execute()
   }
 }
 
-void SketchPlugin_IntersectionPoint::move(double theDeltaX, double theDeltaY)
-{
-}
-
 void SketchPlugin_IntersectionPoint::attributeChanged(const std::string& theID)
 {
   if (theID == EXTERNAL_LINE_ID()) {
index b93e262a3294c1a504261708a7425260a54ddb70..a25f1be363dbcfe3c63bcac0c01cefa31b66e2b0 100644 (file)
@@ -57,11 +57,6 @@ public:
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Called on change of any argument-attribute of this object: for external point
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
 
index 0e2d723d1a0a2281cbbcb96003d515bcb8a5e28c..23cbe266674cfd4cc376d113f1d9807341e8a32b 100644 (file)
@@ -92,21 +92,6 @@ void SketchPlugin_Line::execute()
   }
 }
 
-void SketchPlugin_Line::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if (!aData->isValid())
-    return;
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-    (aData->attribute(START_ID()));
-  aPoint1->move(theDeltaX, theDeltaY);
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-    (aData->attribute(END_ID()));
-  aPoint2->move(theDeltaX, theDeltaY);
-}
-
 std::string SketchPlugin_Line::processEvent(const std::shared_ptr<Events_Message>& theMessage)
 {
   std::string aFilledAttributeName;
index 31e38a28a6993aa4b6697bf36033cd609958bc9c..d51c6608f79225a3944b8d74e107f113627a32b7 100644 (file)
@@ -76,11 +76,6 @@ class SketchPlugin_Line : public SketchPlugin_SketchEntity,
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Apply information of the message to current object. It fills start attribute of
   /// the currrent feature by last attribute of the message feature, build coincidence
   /// if message has selected object
index 023c1f76fcaa0d7102afbf9539b625a5123d53c2..20b42c4629c0cf01ae8dbcbd7bf2fba0aa1b23e9 100644 (file)
@@ -200,13 +200,6 @@ class SketchPlugin_MacroArc: public SketchPlugin_SketchEntity,
   /// Creates an arc-shape
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY)
-  {
-  };
-
   /// Reimplemented from ModelAPI_Feature::isMacro().
   SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
 
index 9208dfdb1fe4eae8cf69c0e2d3b709c300a94834..621439c445fd7a2904945bdf613fe80dabd87b12 100644 (file)
@@ -170,12 +170,6 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity,
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY)
-  {};
-
   /// Reimplemented from ModelAPI_Feature::isMacro().
   /// \returns true
   SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
new file mode 100644 (file)
index 0000000..37ea7aa
--- /dev/null
@@ -0,0 +1,262 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        SketchPlugin_MacroEllipse.cpp
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#include <SketchPlugin_MacroEllipse.h>
+
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Events.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Vertex.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+
+SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse()
+: SketchPlugin_SketchEntity(),
+  myMajorRadius(0.0),
+  myMinorRadius(0.0)
+{
+}
+
+void SketchPlugin_MacroEllipse::initAttributes()
+{
+  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());
+  data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(PASSED_POINT_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());
+
+  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(), PASSED_POINT_REF_ID());
+}
+
+void SketchPlugin_MacroEllipse::execute()
+{
+  FeaturePtr anEllipse = createEllipseFeature();
+  constraintsForEllipse(anEllipse);
+
+  // message to init reentrant operation
+  static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
+  ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+  aMessage->setCreatedFeature(anEllipse);
+  Events_Loop::loop()->send(aMessage);
+}
+
+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);
+
+    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>(
+        new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
+  }
+
+  if (!anEllipse || anEllipse->implPtr<void>() == 0)
+    return;
+
+  myCenter = anEllipse->center();
+  myFocus = anEllipse->firstFocus();
+  myMajorRadius = anEllipse->majorRadius();
+  myMinorRadius = anEllipse->minorRadius();
+
+  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);
+}
+
+std::string SketchPlugin_MacroEllipse::processEvent(
+                                              const std::shared_ptr<Events_Message>& theMessage)
+{
+  std::string aFilledAttributeName;
+
+  ReentrantMessagePtr aReentrantMessage =
+        std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+  if (aReentrantMessage) {
+    FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+    ObjectPtr anObject = aReentrantMessage->selectedObject();
+    AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+    std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+    if (aClickedPoint && (anObject || anAttribute)) {
+      aFilledAttributeName = CENTER_POINT_ID();
+      std::string aReferenceAttributeName = CENTER_POINT_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_POINT_ID())
+            anAttribute = aCreatedFeature->attribute(SketchPlugin_Ellipse::CENTER_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);
+      }
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  }
+  return aFilledAttributeName;
+}
+
+void SketchPlugin_MacroEllipse::constraintsForEllipse(FeaturePtr theEllipseFeature)
+{
+  // Create constraints.
+  SketchPlugin_Tools::createConstraint(
+      this, CENTER_POINT_REF_ID(),
+      theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+      ObjectPtr(), false);
+  SketchPlugin_Tools::createConstraint(
+      this, MAJOR_AXIS_POINT_REF_ID(), AttributePtr(),
+      theEllipseFeature->lastResult(), true);
+  SketchPlugin_Tools::createConstraint(
+      this, PASSED_POINT_REF_ID(), AttributePtr(),
+      theEllipseFeature->lastResult(), true);
+}
+
+FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
+{
+  FeaturePtr aEllipseFeature = sketch()->addFeature(SketchPlugin_Ellipse::ID());
+
+  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()));
+  aCenterAttr->setValue(myCenter->x(), myCenter->y());
+
+  AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_Ellipse::FOCUS_ID()));
+  aFocusAttr->setValue(myFocus->x(), myFocus->y());
+
+  aEllipseFeature->real(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
+  aEllipseFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(myMinorRadius);
+
+  aEllipseFeature->boolean(SketchPlugin_Ellipse::AUXILIARY_ID())->setValue(
+      boolean(AUXILIARY_ID())->value());
+
+  aEllipseFeature->execute();
+  return aEllipseFeature;
+}
+
+AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch || !myCenter || myMajorRadius == 0)
+    return AISObjectPtr();
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      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(),
+      aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
+
+  std::shared_ptr<GeomAPI_Shape> anEllipseShape =
+      GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, myMajorRadius, myMinorRadius);
+  GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
+  if (!anEllipseShape.get() || !aCenterPointShape.get())
+    return AISObjectPtr();
+
+  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
+  aShapes.push_back(anEllipseShape);
+  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;
+}
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.h b/src/SketchPlugin/SketchPlugin_MacroEllipse.h
new file mode 100644 (file)
index 0000000..0af9ee7
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:        SketchPlugin_MacroEllipse.h
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef SketchPlugin_MacroEllipse_H_
+#define SketchPlugin_MacroEllipse_H_
+
+#include <ModelAPI_IReentrant.h>
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+#include <GeomAPI_IPresentable.h>
+
+////class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+
+/**\class SketchPlugin_MacroEllipse
+ * \ingroup Plugins
+ * \brief Feature for creation of the new ellipse in Sketch.
+ */
+class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity,
+                                 public GeomAPI_IPresentable,
+                                 public ModelAPI_IReentrant
+{
+ public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchMacroEllipse");
+    return ID;
+  }
+
+  /// 2D point - center of the ellipse.
+  inline static const std::string& CENTER_POINT_ID()
+  {
+    static const std::string ID("center_point");
+    return ID;
+  }
+
+  /// Reference for center point selection.
+  inline static const std::string& CENTER_POINT_REF_ID()
+  {
+    static const std::string ID("center_point_ref");
+    return ID;
+  }
+
+  /// 2D point - major axis point of the ellipse.
+  inline static const std::string& MAJOR_AXIS_POINT_ID()
+  {
+    static const std::string ID("major_axis_point");
+    return ID;
+  }
+
+  /// Reference for major axis point selection.
+  inline static const std::string& MAJOR_AXIS_POINT_REF_ID()
+  {
+    static const std::string ID("major_axis_point_ref");
+    return ID;
+  }
+
+  /// 2D point - passed point of the ellipse
+  inline static const std::string& PASSED_POINT_ID()
+  {
+    static const std::string ID("passed_point");
+    return ID;
+  }
+
+  /// Reference for passed point selection.
+  inline static const std::string& PASSED_POINT_REF_ID()
+  {
+    static const std::string ID("passed_point_ref");
+    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;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_MacroEllipse::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_MacroEllipse();
+
+private:
+  void constraintsForEllipse(FeaturePtr theEllipseFeature);
+
+  FeaturePtr createEllipseFeature();
+
+private:
+  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+  std::shared_ptr<GeomAPI_Pnt2d> myFocus;
+  double                         myMajorRadius;
+  double                         myMinorRadius;
+};
+
+#endif
index 8743a3c3629531d1d5a1c23f2a9dfda56dac5ab4..3fd19dc330fb75afab595294c0da47b59bb78326 100755 (executable)
@@ -226,7 +226,8 @@ AISObjectPtr SketchPlugin_MultiRotation::getAISObject(AISObjectPtr thePrevious)
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::rotateConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::rotateConstraint(this, sketch(),
+                                                             sketch()->coordinatePlane(),
                                                              thePrevious);
   return anAIS;
 }
index 5fc05fc1e63fb607aa484a9d4ebf45eb2f0ad25f..b927739d1c65c12dc7d52c21d2b7eb48996fabce 100755 (executable)
@@ -212,7 +212,8 @@ AISObjectPtr SketchPlugin_MultiTranslation::getAISObject(AISObjectPtr thePreviou
   if (!sketch())
     return thePrevious;
 
-  AISObjectPtr anAIS = SketcherPrs_Factory::translateConstraint(this, sketch()->coordinatePlane(),
+  AISObjectPtr anAIS = SketcherPrs_Factory::translateConstraint(this, sketch(),
+                                                                sketch()->coordinatePlane(),
                                                                 thePrevious);
   return anAIS;
 }
index 515cc685deb68622074d8105d937b7e6526623eb..0a1c026780f159025a7b7ca0653c3a74ebde224a 100644 (file)
@@ -30,6 +30,8 @@
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_Fillet.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
@@ -50,6 +52,8 @@
 #include <SketchPlugin_Split.h>
 #include <SketchPlugin_Validators.h>
 #include <SketchPlugin_ExternalValidator.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_MacroEllipse.h>
 
 #include <Events_Loop.h>
 #include <GeomDataAPI_Dir.h>
@@ -126,6 +130,7 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_ArcEndPointValidator);
   aFactory->registerValidator("SketchPlugin_ArcEndPointIntersectionValidator",
                               new SketchPlugin_ArcEndPointIntersectionValidator);
+  aFactory->registerValidator("SketchPlugin_HasNoConstraint", new SketchPlugin_HasNoConstraint);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
@@ -187,6 +192,10 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_ConstraintCollinear);
   } else if (theFeatureID == SketchPlugin_ConstraintDistance::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintDistance);
+  } else if (theFeatureID == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+    return FeaturePtr(new SketchPlugin_ConstraintDistanceHorizontal);
+  } else if (theFeatureID == SketchPlugin_ConstraintDistanceVertical::ID()) {
+    return FeaturePtr(new SketchPlugin_ConstraintDistanceVertical);
   } else if (theFeatureID == SketchPlugin_ConstraintLength::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintLength);
   } else if (theFeatureID == SketchPlugin_ConstraintParallel::ID()) {
@@ -225,6 +234,10 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_MacroArc);
   } else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
     return FeaturePtr(new SketchPlugin_MacroCircle);
+  } else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
+    return FeaturePtr(new SketchPlugin_Ellipse);
+  } else if (theFeatureID == SketchPlugin_MacroEllipse::ID()) {
+    return FeaturePtr(new SketchPlugin_MacroEllipse);
   }
   // feature of such kind is not found
   return FeaturePtr();
@@ -267,6 +280,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCoincidence::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCollinear::ID(), aHasSketchPlane);
@@ -290,6 +304,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_ConstraintDistanceHorizontal::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane);
       // SketchRectangle is a python feature, so its ID is passed just as a string
       aMsg->setState("SketchRectangle", aHasSketchPlane);
     }
index 766d33936db8b080f3011176af3566c3bfbc397e..252ecf18118b57f82eda9f600e73a45ba5b1639c 100644 (file)
@@ -62,17 +62,6 @@ void SketchPlugin_Point::execute()
   }
 }
 
-void SketchPlugin_Point::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if (!aData->isValid())
-    return;
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aData->attribute(SketchPlugin_Point::COORD_ID()));
-  aPoint1->move(theDeltaX, theDeltaY);
-}
-
 bool SketchPlugin_Point::isFixed() {
   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
 }
index 7e7a4c6736de8b1195691acbd0628806444721d1..ae23556e3cc846c29f74b342b090f691a365983b 100644 (file)
@@ -58,11 +58,6 @@ class SketchPlugin_Point : public SketchPlugin_SketchEntity
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Called on change of any argument-attribute of this object: for external point
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
 
index ef83cce1d2db49d8a2b7fc0c3302de40b4908eaa..9b8f4e4b874acc77a19a4614d6862f72879f340e 100644 (file)
@@ -23,6 +23,7 @@
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
 #include <SketchPlugin_Sketch.h>
 #include <SketchPlugin_ConstraintRigid.h>
 
@@ -39,6 +40,7 @@
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Vertex.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomDataAPI_Point2D.h>
 
@@ -61,6 +63,8 @@ void SketchPlugin_Projection::initDerivedClassAttributes()
   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
 
+  data()->addAttribute(INCLUDE_INTO_RESULT(), ModelAPI_AttributeBoolean::typeId());
+
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
 }
 
@@ -86,11 +90,6 @@ void SketchPlugin_Projection::execute()
   computeProjection(EXTERNAL_FEATURE_ID());
 }
 
-void SketchPlugin_Projection::move(double theDeltaX, double theDeltaY)
-{
-  // feature cannot be moved
-}
-
 void SketchPlugin_Projection::attributeChanged(const std::string& theID)
 {
   if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
@@ -100,19 +99,42 @@ void SketchPlugin_Projection::attributeChanged(const std::string& theID)
   }
 }
 
+static bool isValidProjectionType(FeaturePtr theProjection,
+                                  GeomEdgePtr theEdge,
+                                  GeomVertexPtr theVertex)
+{
+  if (theVertex && theProjection->getKind() == SketchPlugin_Point::ID())
+    return true;
+  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;
+  }
+  return false;
+}
+
 void SketchPlugin_Projection::computeProjection(const std::string& theID)
 {
   AttributeSelectionPtr aExtFeature =
       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_FEATURE_ID()));
 
-  std::shared_ptr<GeomAPI_Edge> anEdge;
-  if (aExtFeature && aExtFeature->value() && aExtFeature->value()->isEdge()) {
-    anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aExtFeature->value()));
-  } else if (aExtFeature->context() && aExtFeature->context()->shape() &&
-             aExtFeature->context()->shape()->isEdge()) {
-    anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aExtFeature->context()->shape()));
+  GeomShapePtr aShape;
+  GeomEdgePtr anEdge;
+  GeomVertexPtr aVertex;
+  if (aExtFeature)
+    aShape = aExtFeature->value();
+  if (!aShape && aExtFeature->context())
+    aShape = aExtFeature->context()->shape();
+  if (aShape) {
+    if (aShape->isEdge())
+      anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
+    else if (aShape->isVertex())
+      aVertex = GeomVertexPtr(new GeomAPI_Vertex(aShape));
   }
-  if (!anEdge.get())
+  if (!anEdge && !aVertex)
     return;
 
   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
@@ -122,18 +144,15 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
 
   // if the type of feature differs with already selected, remove it and create once again
   bool hasPrevProj = aProjection.get() != 0;
-  if (hasPrevProj) {
-    if ((anEdge->isLine() && aProjection->getKind() != SketchPlugin_Line::ID()) ||
-        (anEdge->isCircle() && aProjection->getKind() != SketchPlugin_Circle::ID()) ||
-        (anEdge->isArc() && aProjection->getKind() != SketchPlugin_Arc::ID())) {
-      DocumentPtr aDoc = sketch()->document();
-
-      std::set<FeaturePtr> aFeaturesToBeRemoved;
-      aFeaturesToBeRemoved.insert(aProjection);
-      ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
-      aProjection = FeaturePtr();
-      aRefAttr->setObject(aProjection);
-    }
+  if (hasPrevProj && !isValidProjectionType(aProjection, anEdge, aVertex)) {
+    DocumentPtr aDoc = sketch()->document();
+
+    std::set<FeaturePtr> aFeaturesToBeRemoved;
+    aFeaturesToBeRemoved.insert(aProjection);
+    ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
+    aProjection = FeaturePtr();
+    aRefAttr->setObject(aProjection);
+    hasPrevProj = false;
   }
 
   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
@@ -145,7 +164,18 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
   }
 
-  if (anEdge->isLine()) {
+  if (aVertex) {
+    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());
+
+    // update coordinates of projection
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
+  }
+  else if (anEdge->isLine()) {
     std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
     std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
 
@@ -192,9 +222,13 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
     std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
 
+    bool isInversed = aCircle->normal()->dot(aSketchPlane->direction()) < 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>(
@@ -208,6 +242,9 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
     aStartPnt->setValue(aFirstInSketch);
     aEndPnt->setValue(aLastInSketch);
     aCenterPnt->setValue(aCenterInSketch);
+    aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
+
+    aProjection->data()->blockSendAttributeUpdated(aWasBlocked, false);
   }
 
   aProjection->boolean(COPY_ID())->setValue(true);
index daffb87519eb1c175b9cd0edbbcc4aeac3131191..26b4b960e0a91bbbf82098b5bfe8752ccf92bbce 100644 (file)
@@ -55,6 +55,12 @@ public:
     return MY_PROJ_FEATURE_ID;
   }
 
+  static const std::string& INCLUDE_INTO_RESULT()
+  {
+    static std::string MY_INCLUDE("IncludeToResult");
+    return MY_INCLUDE;
+  }
+
   /// Returns true because projected feature is always external
   virtual bool isFixed()
   { return true; }
@@ -69,11 +75,6 @@ public:
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
-
   /// Called on change of any argument-attribute of this object: for external point
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
 
index 6f5dc20a49b1c5c5a15b965a22f9f052e286da6a..b0660a958229009b031b28166fe51419621a8db7 100755 (executable)
@@ -43,6 +43,7 @@
 
 #include <SketchPlugin_Sketch.h>
 #include <SketchPlugin_Feature.h>
+#include <SketchPlugin_Projection.h>
 #include <SketchPlugin_SketchEntity.h>
 #include <SketchPlugin_Tools.h>
 
@@ -102,10 +103,14 @@ void SketchPlugin_Sketch::execute()
     if (aFeature) {
       if (!aFeature->sketch()) // on load document the back references are missed
         aFeature->setSketch(this);
-      // do not include the external edges into the result
+      // do not include into the result the external edges with disabled flag "Include into result"
       if (aFeature->data()->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID())) {
-        if (aFeature->data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->context())
-          continue;
+        if (aFeature->data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->context()) {
+          AttributeBooleanPtr aKeepResult =
+              aFeature->boolean(SketchPlugin_Projection::INCLUDE_INTO_RESULT());
+          if (!aKeepResult || !aKeepResult->value())
+            continue;
+        }
       }
       // do not include the construction entities in the result
       if (aFeature->data()->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())) {
index 6b76be658885f82508f481432db62c861d8417fc..3e7328e77cc15623cdfb930d5964e25228331bf6 100644 (file)
@@ -104,13 +104,6 @@ class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICu
   /// Request for initialization of data model of the feature: adding all attributes
   SKETCHPLUGIN_EXPORT virtual void initAttributes();
 
-  /// Moves the feature
-  /// \param theDeltaX the delta for X coordinate is moved
-  /// \param theDeltaY the delta for Y coordinate is moved
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY)
-  {
-  }
-
   /// Converts a 2D sketch space point into point in 3D space
   /// \param theX an X coordinate
   /// \param theY an Y coordinate
index 4a37a3f0a17e807c36bd68868f340e4aa84c41e4..1c9ae40e53441b66a14737ec0cdd42675579968b 100644 (file)
@@ -128,9 +128,6 @@ class SketchPlugin_Split : public SketchPlugin_Feature, public GeomAPI_IPresenta
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
-  /// Moves the feature : Empty
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {};
-
   /// 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);
 
index 9dd5015db7fe1fd40ab35df97daaf0ff6083b045..f03c5d59f5bca6622e92ae62ac4135d9af77d781 100644 (file)
@@ -103,9 +103,6 @@ class SketchPlugin_Trim : public SketchPlugin_Feature, public GeomAPI_IPresentab
   /// Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
-  /// Moves the feature : Empty
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {};
-
   /// 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);
 
index f922ce8eac2b2b0e9be1c51a2e3f6284cfb0cd46..ed22a6420b086cae59f833b975ccedc47b0d3e5a 100755 (executable)
@@ -979,18 +979,33 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
   AttributeSelectionPtr aFeatureAttr =
       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
   std::shared_ptr<GeomAPI_Edge> anEdge;
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
   if (aFeatureAttr.get()) {
     GeomShapePtr aVal = aFeatureAttr->value();
     ResultPtr aRes = aFeatureAttr->context();
-    if(aFeatureAttr->value() && aFeatureAttr->value()->isEdge()) {
+    if(aVal && aVal->isEdge()) {
       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
-    } else if(aFeatureAttr->context() && aFeatureAttr->context()->shape() &&
-              aFeatureAttr->context()->shape()->isEdge()) {
+    } else if(aRes && aRes->shape() && aRes->shape()->isEdge()) {
       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
     }
+
+    // try to convert result to sketch feature
+    if (aRes) {
+      aSketchFeature =
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
+    }
   }
   if (!anEdge) {
-    theError = "The attribute %1 should be an edge";
+    // check a vertex has been selected
+    if (aFeatureAttr->value() && aFeatureAttr->value()->isVertex())
+      return true;
+    else {
+      ResultPtr aRes = aFeatureAttr->context();
+      if (aRes && aRes->shape() && aRes->shape()->isVertex())
+        return true;
+    }
+
+    theError = "The attribute %1 should be an edge or vertex";
     theError.arg(theAttribute->id());
     return false;
   }
@@ -1011,6 +1026,10 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
     theError = "There is no sketch referring to the current feature";
     return false;
   }
+  if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
+    theError = "Unable to project feature from the same sketch";
+    return false;
+  }
 
   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
@@ -1019,11 +1038,8 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
   if (anEdge->isLine()) {
     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
-    std::shared_ptr<GeomAPI_Pnt> aLineLoc = aLine->location();
-    double aDot = aNormal->dot(aLineDir);
-    double aDist = aLineLoc->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
-    bool aValid = (fabs(aDot) >= tolerance && fabs(aDot) < 1.0 - tolerance) ||
-           (fabs(aDot) < tolerance && fabs(aDist) > tolerance);
+    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.";
     return aValid;
@@ -1031,10 +1047,8 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
   else if (anEdge->isCircle() || anEdge->isArc()) {
     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
-    std::shared_ptr<GeomAPI_Pnt> aCircCenter = aCircle->center();
     double aDot = fabs(aNormal->dot(aCircNormal));
-    double aDist = aCircCenter->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
-    bool aValid = fabs(aDot - 1.0) < tolerance * tolerance && fabs(aDist) > tolerance;
+    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.");
@@ -1508,3 +1522,46 @@ bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
 
   return false;
 }
+
+bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
+                                           const std::list<std::string>& theArguments,
+                                           Events_InfoMessage& theError) const
+{
+  std::set<std::string> aFeatureKinds;
+  for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
+       anArgIt != theArguments.end(); anArgIt++) {
+    aFeatureKinds.insert(*anArgIt);
+  }
+
+  if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
+    theError = "The attribute with the %1 type is not processed";
+    theError.arg(theAttribute->attributeType());
+    return false;
+  }
+
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
+                                                                      (theAttribute);
+  bool isObject = aRefAttr->isObject();
+  if (!isObject) {
+    theError = "It uses an empty object";
+    return false;
+  }
+  ObjectPtr anObject = aRefAttr->object();
+  FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
+  if (!aFeature.get()) {
+    theError = "The feature of the checked attribute is empty";
+    return false;
+  }
+
+  FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
+
+  std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
+  std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
+  for (; anIt != aRefsList.end(); anIt++) {
+    FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
+    if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
+        aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
+      return false; // constraint is found, that means that the check is not valid
+  }
+  return true;
+}
index 398fd16baf5c29f8f1b2f9368b92fc5eca8b52a7..ccfe6432824aaef8313f9d54c8e26a5ef0e1ddea 100644 (file)
@@ -427,4 +427,24 @@ class SketchPlugin_ArcEndPointIntersectionValidator: public ModelAPI_AttributeVa
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_HasNoConstraint
+ * \ingroup Validators
+ * \brief Validator for checking whether the feature has constraint.
+ *
+ * Checks that feature of the attribute does not have constraint with some kinds.
+ * The kinds of constraints should be described in parameters of the validator
+ * Validator processes the ModelAPI_AttributeRefAttr attribute kind
+ */
+class SketchPlugin_HasNoConstraint: 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;
+};
+
 #endif
index 4c60d369677553c70c04aafe06639d44a7c977b5..263e89a76abcf696a01c32113e797255af0c88e6 100644 (file)
@@ -163,12 +163,12 @@ for aDelta in range(0, 20):
   aSession.startOperation()
   anArcStartPoint.setValue(sx, sy+aDelta) # move start point
   aSession.finishOperation()
-  model.assertSketchArc(aSketchArc)
+  model.assertArcValidity(aSketchArc)
 for aDelta in range(20, -1, -1):
   aSession.startOperation()
   anArcStartPoint.setValue(sx, sy+aDelta) # move start point
   aSession.finishOperation()
-  model.assertSketchArc(aSketchArc)
+  model.assertArcValidity(aSketchArc)
 #=========================================================================
 # Test that movement of end point of arc does not break the arc
 #=========================================================================
@@ -180,9 +180,9 @@ for aDelta in range(0, 20):
   aSession.startOperation()
   anArcEndPoint.setValue(sx+aDelta, sy) # move end point
   aSession.finishOperation()
-  model.assertSketchArc(aSketchArc)
+  model.assertArcValidity(aSketchArc)
 for aDelta in range(20, -1, -1):
   aSession.startOperation()
   anArcEndPoint.setValue(sx+aDelta, sy) # move end point
   aSession.finishOperation()
-  model.assertSketchArc(aSketchArc)
+  model.assertArcValidity(aSketchArc)
index 082de9f9ae165153b9df42f80e7e3242e047744f..4ce25cd89b2033a504266abde2c2e3a667d5f91d 100644 (file)
@@ -87,6 +87,7 @@ aFeature = aDocument.addFeature("Point")
 aFeature.real("x").setValue(0.)
 aFeature.real("y").setValue(0.)
 aFeature.real("z").setValue(0.)
+aFeature.string("creation_method").setValue("by_xyz")
 anOriginName = aFeature.name()
 aSession.finishOperation()
 #=========================================================================
index b776b267b3ec22581c21622c3b4c5effdacb0c8b..46ce2e4d1cba0c4bf6125b3f467242c37fda21dd 100644 (file)
@@ -51,23 +51,6 @@ from salome.shaper import model
 __updated__ = "2014-10-28"
 
 
-def distancePointLine(point, line):
-    """
-    subroutine to calculate distance between point and line
-    result of calculated distance is has 10**-5 precision
-    """
-    aStartPoint = geomDataAPI_Point2D(line.attribute("StartPoint"))
-    aEndPoint = geomDataAPI_Point2D(line.attribute("EndPoint"))
-    # orthogonal direction
-    aDirX = -(aEndPoint.y() - aStartPoint.y())
-    aDirY = (aEndPoint.x() - aStartPoint.x())
-    aLen = math.sqrt(aDirX**2 + aDirY**2)
-    aDirX = aDirX / aLen
-    aDirY = aDirY / aLen
-    aVecX = point.x() - aStartPoint.x()
-    aVecY = point.y() - aStartPoint.y()
-    return round(math.fabs(aVecX * aDirX + aVecY * aDirY), 5)
-
 aSession = ModelAPI_Session.get()
 aDocument = aSession.moduleDocument()
 #=========================================================================
@@ -163,7 +146,7 @@ assert (model.dof(aSketchFeature) == 6)
 # Add distance between point and line
 #=========================================================================
 PT_LINE_DIST = 50.
-aDist = distancePointLine(aSketchPointCoords, aSketchLine)
+aDist = model.distancePointLine(aSketchPointCoords, aSketchLine)
 aSession.startOperation()
 aConstraint = aSketchFeature.addFeature("SketchConstraintDistance")
 aDistance = aConstraint.real("ConstraintValue")
@@ -194,7 +177,7 @@ assert (model.dof(aSketchFeature) == 5)
 aSession.startOperation()
 aDistance.setValue(PT_LINE_DIST)
 aSession.finishOperation()
-assert (math.fabs(distancePointLine(aSketchPointCoords, aSketchLine) - PT_LINE_DIST) < 1.e-10)
+assert (math.fabs(model.distancePointLine(aSketchPointCoords, aSketchLine) - PT_LINE_DIST) < 1.e-10)
 assert (model.dof(aSketchFeature) == 5)
 #=========================================================================
 # Set distance between line boundaries
diff --git a/src/SketchPlugin/Test/TestConstraintDistanceBehavior.py b/src/SketchPlugin/Test/TestConstraintDistanceBehavior.py
new file mode 100644 (file)
index 0000000..35ab149
--- /dev/null
@@ -0,0 +1,102 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+DistanceParam = model.addParameter(Part_1_doc, "distance", "10.")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchRectangle_1 = Sketch_1.addRectangle(20., 20., 70., 50.)
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4] = SketchRectangle_1.lines()
+firstPoint = SketchAPI_Line(SketchLine_2).startPoint()
+secondPoint = SketchAPI_Line(SketchLine_3).endPoint()
+model.do()
+
+# =============================================================================
+# Test 1.
+# =============================================================================
+# horizontal distance constraint
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(firstPoint, secondPoint, "distance")
+model.do()
+
+# changing the parameter
+for param in range(-30, 31, 2):
+    DistanceParam.setValue(param)
+    model.do()
+    dist = secondPoint.x() - firstPoint.x()
+    assert math.fabs(dist - param) < TOLERANCE, "Incorrect horizontal distance {}, expected {}".format(dist, param)
+
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchConstraintDistanceHorizontal", 1)
+
+# remove horizontal distance constraint
+Part_1_doc.removeFeature(SketchConstraintDistanceHorizontal_1.feature())
+model.do()
+
+# =============================================================================
+# Test 2.
+# =============================================================================
+# Vertical distance constraint
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(firstPoint, secondPoint, "distance")
+model.do()
+
+# changing the parameter
+for param in range(-30, 31, 2):
+    DistanceParam.setValue(param)
+    model.do()
+    dist = secondPoint.y() - firstPoint.y()
+    assert math.fabs(dist - param) < TOLERANCE, "Incorrect vertical distance {}, expected {}".format(dist, param)
+
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchConstraintDistanceVertical", 1)
+
+# remove verticel distance constraint
+Part_1_doc.removeFeature(SketchConstraintDistanceVertical_1.feature())
+model.do()
+
+# =============================================================================
+# Test 3.
+# =============================================================================
+# distance constraint
+SketchConstraintDistance_1 = Sketch_1.setDistance(firstPoint, secondPoint, "distance")
+model.do()
+
+# changing the parameter
+for param in range(-30, 31, 2):
+    DistanceParam.setValue(param)
+    model.do()
+    if param <= 0:
+        assert SketchConstraintDistance_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
+    else:
+        dist = model.distancePointPoint(firstPoint, secondPoint)
+        assert math.fabs(dist - math.fabs(param)) < TOLERANCE, "Incorrect distance {}, expected {}".format(dist, math.fabs(param))
+
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchConstraintDistance", 1)
+# leave distance constraint alive
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestConstraintDistanceHorizontal.py b/src/SketchPlugin/Test/TestConstraintDistanceHorizontal.py
new file mode 100644 (file)
index 0000000..2427874
--- /dev/null
@@ -0,0 +1,228 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    TestConstraintDistanceHorizontal.py
+    Unit test of SketchPlugin_ConstraintDistanceHorizontal class
+
+    SketchPlugin_ConstraintDistanceHorizontal
+        static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistance");
+        data()->addAttribute(SketchPlugin_Constraint::VALUE(),    ModelAPI_AttributeDouble::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+"""
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2017-05-10"
+
+
+def horizontalDistance(point1, point2):
+    """
+    subroutine to calculate signed distance between two points
+    """
+    return point2.x() - point1.x()
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create two movable and one fixed point
+#=========================================================================
+aSession.startOperation()
+aPoint1 = aSketchFeature.addFeature("SketchPoint")
+aPoint1Coords = geomDataAPI_Point2D(aPoint1.attribute("PointCoordinates"))
+aPoint1Coords.setValue(50., 50.)
+aSession.finishOperation()
+aSession.startOperation()
+aPoint2 = aSketchFeature.addFeature("SketchPoint")
+aPoint2Coords = geomDataAPI_Point2D(aPoint2.attribute("PointCoordinates"))
+aPoint2Coords.setValue(70., 70.)
+aSession.finishOperation()
+aSession.startOperation()
+anOriginResult = modelAPI_Result(aDocument.objectByName("Construction", "Origin"))
+anOriginShape = anOriginResult.shape()
+anExtPoint = aSketchFeature.addFeature("SketchPoint")
+anExtCoords = geomDataAPI_Point2D(anExtPoint.attribute("PointCoordinates"))
+anExtCoords.setValue(0., 0.)
+anExtPoint.selection("External").setValue(anOriginResult, anOriginShape)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 4)
+
+#=========================================================================
+# Create a constraint to keep horizontal distance between movable points
+#=========================================================================
+DISTANCE1 = 25.
+aSession.startOperation()
+aHDist1 = aSketchFeature.addFeature("SketchConstraintDistanceHorizontal")
+aDistance = aHDist1.real("ConstraintValue")
+refattrA = aHDist1.refattr("ConstraintEntityA")
+refattrB = aHDist1.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(aPoint1.lastResult())
+refattrB.setObject(aPoint2.lastResult())
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+# set flyout point then abort operation, after that check the Distance is correct
+aSession.startOperation()
+aFlyoutPoint = geomDataAPI_Point2D(aHDist1.attribute("ConstraintFlyoutValuePnt"))
+aFlyoutPoint.setValue(50.0, 100.0)
+aSession.abortOperation()
+assert (refattrA.isInitialized())
+assert (refattrB.isInitialized())
+assert (aDistance.isInitialized())
+aSession.startOperation()
+aDistance.setValue(DISTANCE1)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+assert (model.dof(aSketchFeature) == 3)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE1 + 20.
+dStep = -5.
+while d >= -30.:
+    aSession.startOperation()
+    DISTANCE1 = d
+    aDistance.setValue(DISTANCE1)
+    aSession.finishOperation()
+    assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    d += dStep
+assert (model.dof(aSketchFeature) == 3)
+
+#=========================================================================
+# Create a constraint to keep horizontal distance between fixed and movable points
+#=========================================================================
+DISTANCE2 = 50.
+aSession.startOperation()
+aHDist2 = aSketchFeature.addFeature("SketchConstraintDistanceHorizontal")
+aDistance = aHDist2.real("ConstraintValue")
+refattrA = aHDist2.refattr("ConstraintEntityA")
+refattrB = aHDist2.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(anExtPoint.lastResult())
+refattrB.setAttr(aPoint1Coords)
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert (model.dof(aSketchFeature) == 2)
+#=========================================================================
+# Change a distance value (check previous constraint is applied too)
+#=========================================================================
+d = DISTANCE2
+dStep = -5.
+while d >= -50.:
+    aSession.startOperation()
+    DISTANCE2 = d
+    aDistance.setValue(DISTANCE2)
+    aSession.finishOperation()
+    assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+    assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+    assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    d += dStep
+assert (model.dof(aSketchFeature) == 2)
+
+#=========================================================================
+# Remove first distance
+#=========================================================================
+aStoredCoords = [aPoint2Coords.x(), aPoint2Coords.y()]
+aSession.startOperation()
+aDocument.removeFeature(aHDist1)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+aSession.startOperation()
+DISTANCE2 = 20.
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert aPoint2Coords.x() == aStoredCoords[0] and aPoint2Coords.y() == aStoredCoords[1]
+
+#=========================================================================
+# Create line and set horizontal distance between line boundaries
+#=========================================================================
+aSession.startOperation()
+aLine = aSketchFeature.addFeature("SketchLine")
+aStartPoint = geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+aEndPoint = geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+aStartPoint.setValue(50., 0.)
+aEndPoint.setValue(100., 20.)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 7)
+
+DISTANCE3 = 50.
+aSession.startOperation()
+aHDist3 = aSketchFeature.addFeature("SketchConstraintDistanceHorizontal")
+aDistance = aHDist3.real("ConstraintValue")
+refattrA = aHDist3.refattr("ConstraintEntityA")
+refattrB = aHDist3.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setAttr(aStartPoint)
+refattrB.setAttr(aEndPoint)
+aDistance.setValue(DISTANCE3)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+assert (model.dof(aSketchFeature) == 6)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE3
+dStep = -5.
+while d >= -50.:
+    aSession.startOperation()
+    DISTANCE3 = d
+    aDistance.setValue(DISTANCE3)
+    aSession.finishOperation()
+    assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+    d += dStep
+assert (model.dof(aSketchFeature) == 6)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestConstraintDistanceVertical.py b/src/SketchPlugin/Test/TestConstraintDistanceVertical.py
new file mode 100644 (file)
index 0000000..8910edc
--- /dev/null
@@ -0,0 +1,228 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    TestConstraintDistanceVertical.py
+    Unit test of SketchPlugin_ConstraintDistanceVertical class
+
+    SketchPlugin_ConstraintDistanceVertical
+        static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistance");
+        data()->addAttribute(SketchPlugin_Constraint::VALUE(),    ModelAPI_AttributeDouble::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+"""
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2017-05-10"
+
+
+def verticalDistance(point1, point2):
+    """
+    subroutine to calculate signed distance between two points
+    """
+    return point2.y() - point1.y()
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create two movable and one fixed point
+#=========================================================================
+aSession.startOperation()
+aPoint1 = aSketchFeature.addFeature("SketchPoint")
+aPoint1Coords = geomDataAPI_Point2D(aPoint1.attribute("PointCoordinates"))
+aPoint1Coords.setValue(50., 50.)
+aSession.finishOperation()
+aSession.startOperation()
+aPoint2 = aSketchFeature.addFeature("SketchPoint")
+aPoint2Coords = geomDataAPI_Point2D(aPoint2.attribute("PointCoordinates"))
+aPoint2Coords.setValue(70., 70.)
+aSession.finishOperation()
+aSession.startOperation()
+anOriginResult = modelAPI_Result(aDocument.objectByName("Construction", "Origin"))
+anOriginShape = anOriginResult.shape()
+anExtPoint = aSketchFeature.addFeature("SketchPoint")
+anExtCoords = geomDataAPI_Point2D(anExtPoint.attribute("PointCoordinates"))
+anExtCoords.setValue(0., 0.)
+anExtPoint.selection("External").setValue(anOriginResult, anOriginShape)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 4)
+
+#=========================================================================
+# Create a constraint to keep vertical distance between movable points
+#=========================================================================
+DISTANCE1 = 25.
+aSession.startOperation()
+aVDist1 = aSketchFeature.addFeature("SketchConstraintDistanceVertical")
+aDistance = aVDist1.real("ConstraintValue")
+refattrA = aVDist1.refattr("ConstraintEntityA")
+refattrB = aVDist1.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(aPoint1.lastResult())
+refattrB.setObject(aPoint2.lastResult())
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+# set flyout point then abort operation, after that check the Distance is correct
+aSession.startOperation()
+aFlyoutPoint = geomDataAPI_Point2D(aVDist1.attribute("ConstraintFlyoutValuePnt"))
+aFlyoutPoint.setValue(50.0, 100.0)
+aSession.abortOperation()
+assert (refattrA.isInitialized())
+assert (refattrB.isInitialized())
+assert (aDistance.isInitialized())
+aSession.startOperation()
+aDistance.setValue(DISTANCE1)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+assert (model.dof(aSketchFeature) == 3)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE1 + 20.
+dStep = -5.
+while d >= -30.:
+    aSession.startOperation()
+    DISTANCE1 = d
+    aDistance.setValue(DISTANCE1)
+    aSession.finishOperation()
+    assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    d += dStep
+assert (model.dof(aSketchFeature) == 3)
+
+#=========================================================================
+# Create a constraint to keep vertical distance between fixed and movable points
+#=========================================================================
+DISTANCE2 = 50.
+aSession.startOperation()
+aVDist2 = aSketchFeature.addFeature("SketchConstraintDistanceVertical")
+aDistance = aVDist2.real("ConstraintValue")
+refattrA = aVDist2.refattr("ConstraintEntityA")
+refattrB = aVDist2.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(anExtPoint.lastResult())
+refattrB.setAttr(aPoint1Coords)
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert (model.dof(aSketchFeature) == 2)
+#=========================================================================
+# Change a distance value (check previous constraint is applied too)
+#=========================================================================
+d = DISTANCE2
+dStep = -5.
+while d >= -50.:
+    aSession.startOperation()
+    DISTANCE2 = d
+    aDistance.setValue(DISTANCE2)
+    aSession.finishOperation()
+    assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+    assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+    assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+    d += dStep
+assert (model.dof(aSketchFeature) == 2)
+
+#=========================================================================
+# Remove first distance
+#=========================================================================
+aStoredCoords = [aPoint2Coords.x(), aPoint2Coords.y()]
+aSession.startOperation()
+aDocument.removeFeature(aVDist1)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+aSession.startOperation()
+DISTANCE2 = 20.
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert aPoint2Coords.x() == aStoredCoords[0] and aPoint2Coords.y() == aStoredCoords[1]
+
+#=========================================================================
+# Create line and set vertical distance between line boundaries
+#=========================================================================
+aSession.startOperation()
+aLine = aSketchFeature.addFeature("SketchLine")
+aStartPoint = geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+aEndPoint = geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+aStartPoint.setValue(50., 0.)
+aEndPoint.setValue(100., 20.)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 7)
+
+DISTANCE3 = 50.
+aSession.startOperation()
+aVDist3 = aSketchFeature.addFeature("SketchConstraintDistanceVertical")
+aDistance = aVDist3.real("ConstraintValue")
+refattrA = aVDist3.refattr("ConstraintEntityA")
+refattrB = aVDist3.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setAttr(aStartPoint)
+refattrB.setAttr(aEndPoint)
+aDistance.setValue(DISTANCE3)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+assert (model.dof(aSketchFeature) == 6)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE3
+dStep = -5.
+while d >= -50.:
+    aSession.startOperation()
+    DISTANCE3 = d
+    aDistance.setValue(DISTANCE3)
+    aSession.finishOperation()
+    assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+    d += dStep
+assert (model.dof(aSketchFeature) == 6)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
index 8b67e708ceec64d8647e3d3cb513b72d49787dca..db20680aa714465bfbadd81d379bedb5e9432668 100644 (file)
@@ -169,6 +169,141 @@ assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLi
 assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y()))
 assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y()))
 assert (model.dof(aSketchFeature) == 6)
+
+#=========================================================================
+# Create circle, fix it and check the circle is not moved
+#=========================================================================
+aCenter = [10., 10.]
+aRadius = 5.
+aSession.startOperation()
+aCircle = aSketchFeature.addFeature("SketchCircle")
+aCircleCenter = geomDataAPI_Point2D(aCircle.attribute("circle_center"))
+aCircleRadius = aCircle.real("circle_radius")
+aCircleCenter.setValue(aCenter[0], aCenter[1])
+aCircleRadius.setValue(aRadius)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 9)
+# fixed constraints
+aSession.startOperation()
+aRigidConstraint = aSketchFeature.addFeature("SketchConstraintRigid")
+aRigidConstraint.refattr("ConstraintEntityA").setObject(aCircle.lastResult())
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 6)
+# move center of circle
+aSession.startOperation()
+aCircleCenter.setValue(aCenter[0] + 1., aCenter[1] - 1.)
+aSession.finishOperation()
+assert (aCircleCenter.x() == aCenter[0] and aCircleCenter.y() == aCenter[1])
+assert (aCircleRadius.value() == aRadius)
+assert (model.dof(aSketchFeature) == 6)
+# change radius of circle
+aSession.startOperation()
+aCircleRadius.setValue(aRadius + 3.)
+aSession.finishOperation()
+assert (aCircleCenter.x() == aCenter[0] and aCircleCenter.y() == aCenter[1])
+assert (aCircleRadius.value() == aRadius)
+assert (model.dof(aSketchFeature) == 6)
+
+#=========================================================================
+# Remove Fixed constraint and check the circle can be moved
+#=========================================================================
+aSession.startOperation()
+aDocument.removeFeature(aRigidConstraint)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 9)
+# move center of circle
+aCenter = [aCenter[0] + 1., aCenter[1] - 1.]
+aSession.startOperation()
+aCircleCenter.setValue(aCenter[0], aCenter[1])
+aSession.finishOperation()
+assert (aCircleCenter.x() == aCenter[0] and aCircleCenter.y() == aCenter[1])
+assert (aCircleRadius.value() == aRadius)
+assert (model.dof(aSketchFeature) == 9)
+# change radius of circle
+aRadius = aRadius + 3.
+aSession.startOperation()
+aCircleRadius.setValue(aRadius)
+aSession.finishOperation()
+assert (aCircleCenter.x() == aCenter[0] and aCircleCenter.y() == aCenter[1])
+assert (aCircleRadius.value() == aRadius)
+assert (model.dof(aSketchFeature) == 9)
+
+#=========================================================================
+# Create arc, fix it and check it is not moved
+#=========================================================================
+aCenter = [10., 10.]
+aStart = [5., 10.]
+aEnd = [10., 15.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchArc")
+anArcCenter = geomDataAPI_Point2D(anArc.attribute("center_point"))
+anArcStart = geomDataAPI_Point2D(anArc.attribute("start_point"))
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point"))
+anArcCenter.setValue(aCenter[0], aCenter[1])
+anArcStart.setValue(aStart[0], aStart[1])
+anArcEnd.setValue(aEnd[0], aEnd[1])
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 14)
+# fixed constraints
+aSession.startOperation()
+aRigidConstraint = aSketchFeature.addFeature("SketchConstraintRigid")
+aRigidConstraint.refattr("ConstraintEntityA").setObject(anArc.lastResult())
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 9)
+# move center of arc
+aSession.startOperation()
+anArcCenter.setValue(aCenter[0] + 1., aCenter[1] - 1.)
+aSession.finishOperation()
+assert (anArcCenter.x() == aCenter[0] and anArcCenter.y() == aCenter[1])
+assert (anArcStart.x() == aStart[0] and anArcStart.y() == aStart[1])
+assert (anArcEnd.x() == aEnd[0] and anArcEnd.y() == aEnd[1])
+assert (model.dof(aSketchFeature) == 9)
+# move start point of arc
+aSession.startOperation()
+anArcStart.setValue(aStart[0] + 1., aStart[1] - 1.)
+aSession.finishOperation()
+assert (anArcCenter.x() == aCenter[0] and anArcCenter.y() == aCenter[1])
+assert (anArcStart.x() == aStart[0] and anArcStart.y() == aStart[1])
+assert (anArcEnd.x() == aEnd[0] and anArcEnd.y() == aEnd[1])
+assert (model.dof(aSketchFeature) == 9)
+# move end point of arc
+aSession.startOperation()
+anArcEnd.setValue(aEnd[0] + 1., aEnd[1] - 1.)
+aSession.finishOperation()
+assert (anArcCenter.x() == aCenter[0] and anArcCenter.y() == aCenter[1])
+assert (anArcStart.x() == aStart[0] and anArcStart.y() == aStart[1])
+assert (anArcEnd.x() == aEnd[0] and anArcEnd.y() == aEnd[1])
+assert (model.dof(aSketchFeature) == 9)
+
+#=========================================================================
+# Remove Fixed constraint and check the arc can be moved
+#=========================================================================
+aSession.startOperation()
+aDocument.removeFeature(aRigidConstraint)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 14)
+# move center of arc
+aCenter = [anArcCenter.x(), anArcCenter.y()]
+aSession.startOperation()
+anArcCenter.setValue(aCenter[0] + 1., aCenter[1] - 1.)
+aSession.finishOperation()
+assert (anArcCenter.x() != aCenter[0] or anArcCenter.y() != aCenter[1])
+assert (model.dof(aSketchFeature) == 14)
+# move start point of arc
+aStart = [anArcStart.x(), anArcStart.y()]
+aSession.startOperation()
+anArcStart.setValue(aStart[0] + 1., aStart[1] - 1.)
+aSession.finishOperation()
+assert (anArcStart.x() != aStart[0] or anArcStart.y() != aStart[1])
+assert (model.dof(aSketchFeature) == 14)
+# move end point of arc
+aEnd = [anArcEnd.x(), anArcEnd.y()]
+aSession.startOperation()
+anArcEnd.setValue(aEnd[0] + 1., aEnd[1] - 1.)
+aSession.finishOperation()
+assert (anArcEnd.x() != aEnd[0] or anArcEnd.y() != aEnd[1])
+assert (model.dof(aSketchFeature) == 14)
+
 #=========================================================================
 # End of test
 #=========================================================================
diff --git a/src/SketchPlugin/Test/TestConstraintHorizontalValidator.py b/src/SketchPlugin/Test/TestConstraintHorizontalValidator.py
new file mode 100644 (file)
index 0000000..103d7db
--- /dev/null
@@ -0,0 +1,70 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    TestConstraintHorizontalValidator.py
+    It tests validation of horizontal and vertical segments in H and V constraints to avoid
+    selection segments that already have one of these constraint"
+"""
+
+#=========================================================================
+# of the test
+#=========================================================================
+from salome.shaper import model
+from ModelAPI import *
+import math
+#=========================================================================
+# Creation of a part
+#=========================================================================
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 20, 40, 80)
+SketchLine_2 = Sketch_1.addLine(40, 80, 60, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+model.do()
+#=========================================================================
+# Checking that sketch and constraints become invalid when to one line
+# two horizontal/vertical constraints are applied in any combination
+#=========================================================================
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Sketch_1.feature()))
+assert(Sketch_1.feature().error() != '')
+#=========================================================================
+# Remove duplicated Vertical constraints
+#=========================================================================
+Part_1_doc.removeFeature(SketchConstraintVertical_1.feature())
+assert(aFactory.validate(Sketch_1.feature()))
+model.do()
+#=========================================================================
+# Checking that after excess constraints are removed or undone,
+# sketch becomes valid.
+#=========================================================================
+assert(aFactory.validate(Sketch_1.feature()))
+assert(Sketch_1.feature().error() == '')
+
+assert(model.checkPythonDump())
index e7e8a5c128a7e16797ce84d47c06308730d984e6..c5aaa01a867056b217a72eb9ba7c0480532b9414 100644 (file)
@@ -71,6 +71,7 @@ aFeature = aDocument.addFeature("Point")
 aFeature.real("x").setValue(0.)
 aFeature.real("y").setValue(0.)
 aFeature.real("z").setValue(0.)
+aFeature.string("creation_method").setValue("by_xyz")
 anOriginName = aFeature.name()
 aSession.finishOperation()
 #=========================================================================
index 09649edfa275b2fc3fc652991af53ced7bc343b1..3f3ac2e7ed9382800fe81551d4df974ab3b58e94 100644 (file)
@@ -40,23 +40,6 @@ from salome.shaper import model
 
 __updated__ = "2015-03-17"
 
-def distancePointLine(point, line):
-    """
-    subroutine to calculate distance between point and line
-    result of calculated distance is has 10**-5 precision
-    """
-    aStartPoint = geomDataAPI_Point2D(line.attribute("StartPoint"))
-    aEndPoint = geomDataAPI_Point2D(line.attribute("EndPoint"))
-    # orthogonal direction
-    aDirX = -(aEndPoint.y() - aStartPoint.y())
-    aDirY = (aEndPoint.x() - aStartPoint.x())
-    aLen = math.sqrt(aDirX**2 + aDirY**2)
-    aDirX = aDirX / aLen
-    aDirY = aDirY / aLen
-    aVecX = point.x() - aStartPoint.x()
-    aVecY = point.y() - aStartPoint.y()
-    return round(math.fabs(aVecX * aDirX + aVecY * aDirY), 5)
-
 def checkArcLineTangency(theArc, theLine):
     """
     subroutine to check that the line is tangent to arc/circle
@@ -68,7 +51,7 @@ def checkArcLineTangency(theArc, theLine):
         aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
         aStartPnt = geomDataAPI_Point2D(theArc.attribute("start_point"))
         aRadius = model.distancePointPoint(aStartPnt, aCenter)
-    aDist = distancePointLine(aCenter, theLine)
+    aDist = model.distancePointLine(aCenter, theLine)
     assert math.fabs(aDist - aRadius) < 2.e-5, "aDist = {0}, aRadius = {1}".format(aDist, aRadius)
 
 def checkArcArcTangency(theArc1, theArc2):
index 097e636b2a1177df781d1eb4dbdbb7abd2672b4f..0e44647749bcb621f235025a4c94a29aa0ccf221 100644 (file)
@@ -52,22 +52,10 @@ def verifyLastArc(theSketch, theCenter, theStart, theEnd):
     subroutine to verify position of last arc in the sketch
     """
     aLastArc = model.lastSubFeature(theSketch, "SketchArc")
-    aCenterPnt = geomDataAPI_Point2D(aLastArc.attribute("center_point"))
-    aStartPnt = geomDataAPI_Point2D(aLastArc.attribute("start_point"))
-    aEndPnt = geomDataAPI_Point2D(aLastArc.attribute("end_point"))
-    if len(theCenter):
-        verifyPointCoordinates(aCenterPnt, theCenter[0], theCenter[1])
-    if len(theStart):
-        verifyPointCoordinates(aStartPnt, theStart[0], theStart[1])
-    if len(theEnd):
-        verifyPointCoordinates(aEndPnt, theEnd[0], theEnd[1])
-    model.assertSketchArc(aLastArc)
-
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.id(), thePoint.x(), thePoint.y(), theX, theY)
+    model.assertArc(aLastArc, theCenter, theStart, theEnd)
 
 def verifyPointOnLine(thePoint, theLine):
-    aDistance = distancePointLine(thePoint, theLine)
+    aDistance = model.distancePointLine(thePoint, theLine)
     assert aDistance < TOLERANCE, "Point is not on Line, distance: {0}".format(aDistance)
 
 def verifyPointOnCircle(thePoint, theCircular):
@@ -82,14 +70,6 @@ def verifyPointOnCircle(thePoint, theCircular):
         return
     assert math.fabs(model.distancePointPoint(aCenterPoint, thePoint) - aRadius) < TOLERANCE
 
-def distancePointLine(thePoint, theLine):
-    aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint")).pnt().xy()
-    aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint")).pnt().xy()
-    aLineDir = aLineEnd.decreased(aLineStart)
-    aLineLen = aLineEnd.distance(aLineStart)
-    aPntDir = thePoint.pnt().xy().decreased(aLineStart)
-    return math.fabs(aPntDir.cross(aLineDir) / aLineLen)
-
 
 aSession = ModelAPI_Session.get()
 aDocument = aSession.moduleDocument()
@@ -243,7 +223,7 @@ aEndRef.setObject(aLine.lastResult())
 aEnd.setValue(aLineStart[0], aLineStart[1])
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 8), "Number of subs {}".format(aSketchFeature.numberOfSubs())
-verifyPointCoordinates(aPointCoord, aPointCoordinates[0], aPointCoordinates[1])
+model.assertPoint(aPointCoord, aPointCoordinates)
 verifyLastArc(aSketchFeature, [aPrevArcStart.x(), aPrevArcStart.y()], aPointCoordinates, [])
 model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3)
 
@@ -279,11 +259,8 @@ aEnd.setValue(aLineEndPoint.pnt())
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 12), "Number of subs {}".format(aSketchFeature.numberOfSubs())
 # check connected features do not change their positions
-verifyPointCoordinates(aPrevArcCenter, aPrevArcCenterXY[0], aPrevArcCenterXY[1])
-verifyPointCoordinates(aPrevArcStart, aPrevArcStartXY[0], aPrevArcStartXY[1])
-verifyPointCoordinates(aPrevArcEnd, aPrevArcEndXY[0], aPrevArcEndXY[1])
-verifyPointCoordinates(aLineStartPoint, aLineStart[0], aLineStart[1])
-verifyPointCoordinates(aLineEndPoint, aLineEnd[0], aLineEnd[1])
+model.assertArc(aPrevArc, aPrevArcCenterXY, aPrevArcStartXY, aPrevArcEndXY)
+model.assertLine(aLine, aLineStart, aLineEnd)
 # verify newly created arc
 anArc = model.lastSubFeature(aSketchFeature, "SketchArc")
 aCenter = geomDataAPI_Point2D(anArc.attribute("center_point"))
index 6f296a03d91c5d046a78265137e49f62bbc9d452..448f9ea3d6fd4ff02638f749a47b0c0c21f73ab2 100644 (file)
@@ -52,19 +52,7 @@ def verifyLastArc(theSketch, theCenter, theStart, theEnd):
     subroutine to verify position of last arc in the sketch
     """
     aLastArc = model.lastSubFeature(theSketch, "SketchArc")
-    aCenterPnt = geomDataAPI_Point2D(aLastArc.attribute("center_point"))
-    aStartPnt = geomDataAPI_Point2D(aLastArc.attribute("start_point"))
-    aEndPnt = geomDataAPI_Point2D(aLastArc.attribute("end_point"))
-    if len(theCenter):
-        verifyPointCoordinates(aCenterPnt, theCenter[0], theCenter[1])
-    if len(theStart):
-        verifyPointCoordinates(aStartPnt, theStart[0], theStart[1])
-    if len(theEnd):
-        verifyPointCoordinates(aEndPnt, theEnd[0], theEnd[1])
-    model.assertSketchArc(aLastArc)
-
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.id(), thePoint.x(), thePoint.y(), theX, theY)
+    model.assertArc(aLastArc, theCenter, theStart, theEnd)
 
 def verifyTangent(theFeature1, theFeature2):
     anArcs = []
@@ -99,19 +87,11 @@ def verifyArcLineTangent(theArc, theLine):
     aStart  = geomDataAPI_Point2D(theArc.attribute("start_point"))
     aRadius = model.distancePointPoint(aStart, aCenter)
 
-    aDistCL = distancePointLine(aCenter, theLine)
+    aDistCL = model.distancePointLine(aCenter, theLine)
     assert math.fabs(aDistCL - aRadius) < TOLERANCE, "Arc and line do not tangent"
 
-def distancePointLine(thePoint, theLine):
-    aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint")).pnt().xy()
-    aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint")).pnt().xy()
-    aLineDir = aLineEnd.decreased(aLineStart)
-    aLineLen = aLineEnd.distance(aLineStart)
-    aPntDir = thePoint.pnt().xy().decreased(aLineStart)
-    return math.fabs(aPntDir.cross(aLineDir) / aLineLen)
-
 def verifyPointOnLine(thePoint, theLine):
-    aDistance = distancePointLine(thePoint, theLine)
+    aDistance = model.distancePointLine(thePoint, theLine)
     assert aDistance < TOLERANCE, "Point is not on Line, distance: {0}".format(aDistance)
 
 
index 0844028d99bce4045ce2a3fac6d98586f6bf7a64..f6240ab205e4a91bc8c30484dc08213dc40abcb5 100644 (file)
@@ -48,13 +48,10 @@ def verifyLastArc(theSketch, theX, theY, theR):
     """
     aLastArc = model.lastSubFeature(theSketch, "SketchArc")
     aCenter = geomDataAPI_Point2D(aLastArc.attribute("center_point"))
-    verifyPointCoordinates(aCenter, theX, theY)
+    model.assertPoint(aCenter, [theX, theY])
     aRadius = aLastArc.real("radius")
     assert aRadius.value() == theR, "Wrong radius {0}, expected {1}".format(aRadius.value(), theR)
 
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.attributeType(), thePoint.x(), thePoint.y(), theX, theY)
-
 def verifyPointOnArc(thePoint, theArc):
     aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
     aDistCP = model.distancePointPoint(aCenter, thePoint)
@@ -78,17 +75,9 @@ def verifyTangentCircular(theDistBetweenCenters, theRadius1, theRadius2):
 def verifyTangentArcLine(theArc, theLine):
     aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
     aRadius = theArc.real("radius").value()
-    aDistCL = distancePointLine(aCenter, theLine)
+    aDistCL = model.distancePointLine(aCenter, theLine)
     assert math.fabs(aDistCL - aRadius) < TOLERANCE, "Circle and line are not tangent"
 
-def distancePointLine(thePoint, theLine):
-    aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint")).pnt().xy()
-    aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint")).pnt().xy()
-    aLineDir = aLineEnd.decreased(aLineStart)
-    aLineLen = aLineEnd.distance(aLineStart)
-    aPntDir = thePoint.pnt().xy().decreased(aLineStart)
-    return math.fabs(aPntDir.cross(aLineDir) / aLineLen)
-
 
 #=========================================================================
 # Start of test
@@ -178,9 +167,9 @@ anArcPnt3.setValue(aLineStart[0], aLineStart[1])
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 7)
 # check the points do not change their positions
-verifyPointCoordinates(aPrevCenter, aPrevCenterXY[0], aPrevCenterXY[1])
-verifyPointCoordinates(aPointCoord, aPointCoodinates[0], aPointCoodinates[1])
-verifyPointCoordinates(aStartPnt, aLineStart[0], aLineStart[1])
+model.assertPoint(aPrevCenter, aPrevCenterXY)
+model.assertPoint(aPointCoord, aPointCoodinates)
+model.assertPoint(aStartPnt, aLineStart)
 # check newly created arc passes through the points
 anArc = model.lastSubFeature(aSketchFeature, "SketchArc")
 verifyPointOnArc(aPrevCenter, anArc)
@@ -209,9 +198,9 @@ anArcPnt3.setValue(20, 25)
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 9)
 # check the points do not change their positions
-verifyPointCoordinates(aPrevCenter, aPrevCenterXY[0], aPrevCenterXY[1])
-verifyPointCoordinates(aPointCoord, aPointCoodinates[0], aPointCoodinates[1])
-verifyPointCoordinates(aStartPnt, aLineStart[0], aLineStart[1])
+model.assertPoint(aPrevCenter, aPrevCenterXY)
+model.assertPoint(aPointCoord, aPointCoodinates)
+model.assertPoint(aStartPnt, aLineStart)
 # check sub-features
 model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3)
 model.testNbSubFeatures(aSketch, "SketchConstraintTangent", 1)
index 88ad0c60ed677acca958c6631e3f3f9dd2cb62a3..851241a02a20a1cac14eceaade0c995cd3a1b65e 100644 (file)
@@ -88,19 +88,7 @@ def verifyLastArc(theSketch, theCenter, theStart, theEnd):
     subroutine to verify position of last arc in the sketch
     """
     aLastArc = model.lastSubFeature(theSketch, "SketchArc")
-    aCenterPnt = geomDataAPI_Point2D(aLastArc.attribute("center_point"))
-    aStartPnt = geomDataAPI_Point2D(aLastArc.attribute("start_point"))
-    aEndPnt = geomDataAPI_Point2D(aLastArc.attribute("end_point"))
-    if len(theCenter):
-        verifyPointCoordinates(aCenterPnt, theCenter[0], theCenter[1])
-    if len(theStart):
-        verifyPointCoordinates(aStartPnt, theStart[0], theStart[1])
-    if len(theEnd):
-        verifyPointCoordinates(aEndPnt, theEnd[0], theEnd[1])
-    model.assertSketchArc(aLastArc)
-
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.id(), thePoint.x(), thePoint.y(), theX, theY)
+    model.assertArc(aLastArc, theCenter, theStart, theEnd)
 
 
 #=========================================================================
index 9be701d66e20aa0a0eb53d957622e7f10a26cf36..6fbb6b34a77c87078acfee9dae969f3244fd27c6 100644 (file)
@@ -47,16 +47,10 @@ def verifyLastCircle(theSketch, theX, theY, theR):
     subroutine to verify position of last circle in the sketch
     """
     aLastCircle = model.lastSubFeature(theSketch, "SketchCircle")
-    aCenter = geomDataAPI_Point2D(aLastCircle.attribute("circle_center"))
-    verifyPointCoordinates(aCenter, theX, theY)
-    aRadius = aLastCircle.real("circle_radius")
-    assert aRadius.value() == theR, "Wrong radius {0}, expected {1}".format(aRadius.value(), theR)
-
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.id(), thePoint.x(), thePoint.y(), theX, theY)
+    model.assertCircle(aLastCircle, [theX, theY], theR)
 
 def verifyPointOnLine(thePoint, theLine):
-    aDistance = distancePointLine(thePoint, theLine)
+    aDistance = model.distancePointLine(thePoint, theLine)
     assert aDistance < TOLERANCE, "Point is not on Line, distance: {0}".format(aDistance)
 
 def verifyTangentCircles(theCircle1, theCircle2):
@@ -69,14 +63,6 @@ def verifyTangentCircles(theCircle1, theCircle2):
     aRDiff = math.fabs(aRadius1 - aRadius2)
     assert math.fabs(aRSum - aDistCC) < TOLERANCE or math.fabs(aRDiff - aDistCC) < TOLERANCE, "Circles do not tangent"
 
-def distancePointLine(thePoint, theLine):
-    aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint")).pnt().xy()
-    aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint")).pnt().xy()
-    aLineDir = aLineEnd.decreased(aLineStart)
-    aLineLen = aLineEnd.distance(aLineStart)
-    aPntDir = thePoint.pnt().xy().decreased(aLineStart)
-    return math.fabs(aPntDir.cross(aLineDir) / aLineLen)
-
 
 #=========================================================================
 # Start of test
@@ -182,7 +168,7 @@ aPassed.setValue(aPrevCenter.pnt())
 aRadius = model.distancePointPoint(aPrevCenter, aPointCoord)
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 6)
-verifyPointCoordinates(aPointCoord, aPointCoordinates[0], aPointCoordinates[1])
+model.assertPoint(aPointCoord, aPointCoordinates)
 verifyLastCircle(aSketchFeature, aPointCoord.x(), aPointCoord.y(), aRadius)
 model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 2)
 
@@ -223,14 +209,13 @@ aRadius = model.distancePointPoint(aCenter, aPassed)
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 10)
 # check connected features do not change their positions
-verifyPointCoordinates(aPrevCenter, aPrevCenterXY[0], aPrevCenterXY[1])
+model.assertPoint(aPrevCenter, aPrevCenterXY)
 assert(aPrevCircle.real("circle_radius").value() == aPrevRadius)
-verifyPointCoordinates(aStartPnt, aLineStart[0], aLineStart[1])
-verifyPointCoordinates(aEndPnt, aLineEnd[0], aLineEnd[1])
+model.assertLine(aLine, aLineStart, aLineEnd)
 # verify newly created circle
 aCircle = model.lastSubFeature(aSketchFeature, "SketchCircle")
 aCenter = geomDataAPI_Point2D(aCircle.attribute("circle_center"))
-verifyPointCoordinates(aCenter, anExpectedCenter[0], anExpectedCenter[1])
+model.assertPoint(aCenter, anExpectedCenter)
 verifyPointOnLine(aCenter, aLine)
 verifyTangentCircles(aCircle, aPrevCircle)
 model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3)
index 321e37ab9d87c0addd56d7a5d52bbec0d165fcc7..558f2f86f86b6341bc7cea0043c38b14aff7884c 100644 (file)
@@ -47,13 +47,7 @@ def verifyLastCircle(theSketch, theX, theY, theR):
     subroutine to verify position of last circle in the sketch
     """
     aLastCircle = model.lastSubFeature(theSketch, "SketchCircle")
-    aCenter = geomDataAPI_Point2D(aLastCircle.attribute("circle_center"))
-    verifyPointCoordinates(aCenter, theX, theY)
-    aRadius = aLastCircle.real("circle_radius")
-    assert aRadius.value() == theR, "Wrong radius {0}, expected {1}".format(aRadius.value(), theR)
-
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.attributeType(), thePoint.x(), thePoint.y(), theX, theY)
+    model.assertCircle(aLastCircle, [theX, theY], theR)
 
 def verifyPointOnCircle(thePoint, theCircle):
     aCircleCenter = geomDataAPI_Point2D(theCircle.attribute("circle_center"))
@@ -86,17 +80,9 @@ def verifyTangentCircular(theDistBetweenCenters, theRadius1, theRadius2):
 def verifyTangentCircleLine(theCircle, theLine):
     aCenter = geomDataAPI_Point2D(theCircle.attribute("circle_center"))
     aRadius = theCircle.real("circle_radius").value()
-    aDistCL = distancePointLine(aCenter, theLine)
+    aDistCL = model.distancePointLine(aCenter, theLine)
     assert math.fabs(aDistCL - aRadius) < TOLERANCE, "Circle and line are not tangent"
 
-def distancePointLine(thePoint, theLine):
-    aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint")).pnt().xy()
-    aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint")).pnt().xy()
-    aLineDir = aLineEnd.decreased(aLineStart)
-    aLineLen = aLineEnd.distance(aLineStart)
-    aPntDir = thePoint.pnt().xy().decreased(aLineStart)
-    return math.fabs(aPntDir.cross(aLineDir) / aLineLen)
-
 
 #=========================================================================
 # Start of test
@@ -186,9 +172,9 @@ aCirclePnt3.setValue(aLineStart[0], aLineStart[1])
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 7)
 # check the points do not change their positions
-verifyPointCoordinates(aPrevCenter, aPrevCenterXY[0], aPrevCenterXY[1])
-verifyPointCoordinates(aPointCoord, aPointCoordinates[0], aPointCoordinates[1])
-verifyPointCoordinates(aStartPnt, aLineStart[0], aLineStart[1])
+model.assertPoint(aPrevCenter, aPrevCenterXY)
+model.assertPoint(aPointCoord, aPointCoordinates)
+model.assertPoint(aStartPnt, aLineStart)
 # check newly created circle passes through the points
 aCircle = model.lastSubFeature(aSketchFeature, "SketchCircle")
 verifyPointOnCircle(aPrevCenter, aCircle)
@@ -235,13 +221,10 @@ aCirclePnt3.setValue(anArcCenter[0] + anArcRadius, anArcCenter[1])
 aSession.finishOperation()
 assert (aSketchFeature.numberOfSubs() == 12)
 # check the tangent entities do not change their positions
-verifyPointCoordinates(aPrevCenter, aPrevCenterXY[0], aPrevCenterXY[1])
+model.assertPoint(aPrevCenter, aPrevCenterXY)
 assert (aPrevCircle.real("circle_radius").value() == aPrevCircleRadius)
-verifyPointCoordinates(aStartPnt, aLineStart[0], aLineStart[1])
-verifyPointCoordinates(aEndPnt, aLineEnd[0], aLineEnd[1])
-verifyPointCoordinates(anArcCenterPnt, anArcCenter[0], anArcCenter[1])
-verifyPointCoordinates(anArcStartPnt, anArcStart[0], anArcStart[1])
-verifyPointCoordinates(anArcEndPnt, anArcEnd[0], anArcEnd[1])
+model.assertLine(aLine, aLineStart, aLineEnd)
+model.assertArc(anArc, anArcCenter, anArcStart, anArcEnd)
 # check newly created circle passes through the points
 aCircle = model.lastSubFeature(aSketchFeature, "SketchCircle")
 verifyTangentCircles(aCircle, aPrevCircle)
index 882e686d8989b2f5c30f2a90f94d568b5a7ccab9..5a4677d6794175b9a49bd397b480294373a6a332 100644 (file)
@@ -72,13 +72,7 @@ def verifyLastCircle(theSketch, theX, theY, theR):
     subroutine to verify position of last circle in the sketch
     """
     aLastCircle = model.lastSubFeature(theSketch, "SketchCircle")
-    aCenter = geomDataAPI_Point2D(aLastCircle.attribute("circle_center"))
-    verifyPointCoordinates(aCenter, theX, theY)
-    aRadius = aLastCircle.real("circle_radius")
-    assert aRadius.value() == theR, "Wrong radius {0}, expected {1}".format(aRadius.value(), theR)
-
-def verifyPointCoordinates(thePoint, theX, theY):
-    assert thePoint.x() == theX and thePoint.y() == theY, "Wrong '{0}' point ({1}, {2}), expected ({3}, {4})".format(thePoint.attributeType(), thePoint.x(), thePoint.y(), theX, theY)
+    model.assertCircle(aLastCircle, [theX, theY], theR)
 
 
 #=========================================================================
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned01.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned01.py
new file mode 100644 (file)
index 0000000..6ab1c23
--- /dev/null
@@ -0,0 +1,66 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Origin = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Origin.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Point_1 = Sketch_1.addPoint(230, 40)
+Sketch_1.setSignedDistance(Point_1.result(), SketchAPI_Line(Line_4).result(), "d")
+Point_2 = Sketch_1.addPoint(230, 80)
+Sketch_1.setUnsignedDistance(Point_2.result(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(Point_1, line)
+signedDist2 = model.signedDistancePointLine(Point_2, line)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(Point_2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(Point_2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned02.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned02.py
new file mode 100644 (file)
index 0000000..f518caa
--- /dev/null
@@ -0,0 +1,68 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Point_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Point_1.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Circle_1 = Sketch_1.addCircle(230, 40, 20)
+Sketch_1.setSignedDistance(Circle_1.center(), SketchAPI_Line(Line_4).result(), "d")
+Circle_2 = Sketch_1.addCircle(230, 80, 20)
+Sketch_1.setUnsignedDistance(Circle_2.center(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+center1 = Circle_1.center()
+center2 = Circle_2.center()
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(center1, line)
+signedDist2 = model.signedDistancePointLine(center2, line)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(center1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(center2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(center1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(center2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned03.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned03.py
new file mode 100644 (file)
index 0000000..f059900
--- /dev/null
@@ -0,0 +1,67 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Point_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Point_1.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Line_5 = Sketch_1.addLine(230, 40, 230, 80)
+Sketch_1.setSignedDistance(Line_5.startPoint(), SketchAPI_Line(Line_4).result(), "d")
+Sketch_1.setUnsignedDistance(Line_5.endPoint(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+start = Line_5.startPoint()
+end = Line_5.endPoint()
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(start, line)
+signedDist2 = model.signedDistancePointLine(end, line)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned04.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned04.py
new file mode 100644 (file)
index 0000000..e26fd42
--- /dev/null
@@ -0,0 +1,69 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Point_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Point_1.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Arc_1 = Sketch_1.addArc(250, 60, 230, 40, 230, 80, False)
+Sketch_1.setSignedDistance(Arc_1.startPoint(), SketchAPI_Line(Line_4).result(), "d")
+Sketch_1.setUnsignedDistance(Arc_1.endPoint(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+start = Arc_1.startPoint()
+end = Arc_1.endPoint()
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(start, line)
+signedDist2 = model.signedDistancePointLine(end, line)
+
+# change rectangle width and check distances
+widthParam.setValue(1000)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+model.assertArcValidity(Arc_1)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+model.assertArcValidity(Arc_1)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned05.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned05.py
new file mode 100644 (file)
index 0000000..3d476c3
--- /dev/null
@@ -0,0 +1,80 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Origin = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Origin.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Point_1 = Sketch_1.addPoint(230, 40)
+Sketch_1.setSignedDistance(Point_1.result(), SketchAPI_Line(Line_4).result(), "d")
+Point_2 = Sketch_1.addPoint(230, 80)
+Sketch_1.setUnsignedDistance(Point_2.result(), SketchAPI_Line(Line_4).result(), "d")
+Line_5 = Sketch_1.addLine(260, 0, 260, 100)
+Sketch_1.setSignedDistance(Point_1.result(), Line_5.result(), "d")
+Sketch_1.setUnsignedDistance(Point_2.result(), Line_5.result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+line4 = model.toSketchFeature(Line_4)
+line5 = model.toSketchFeature(Line_5)
+signedDist14 = model.signedDistancePointLine(Point_1, line4)
+signedDist15 = model.signedDistancePointLine(Point_1, line5)
+signedDist24 = model.signedDistancePointLine(Point_2, line4)
+signedDist25 = model.signedDistancePointLine(Point_2, line5)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line4)
+assert(math.fabs(signedDist14 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist14, curDist)
+curDist = model.signedDistancePointLine(Point_2, line4)
+assert(math.fabs(math.fabs(signedDist24) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist24, -curDist)
+curDist = model.signedDistancePointLine(Point_1, line5)
+assert(math.fabs(signedDist15 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist15, curDist)
+curDist = model.signedDistancePointLine(Point_2, line5)
+assert(math.fabs(math.fabs(signedDist25) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist25, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line4)
+assert(math.fabs(signedDist14 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist14, curDist)
+curDist = model.signedDistancePointLine(Point_2, line4)
+assert(math.fabs(math.fabs(signedDist24) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist24, -curDist)
+curDist = model.signedDistancePointLine(Point_1, line5)
+assert(math.fabs(signedDist15 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist15, curDist)
+curDist = model.signedDistancePointLine(Point_2, line5)
+assert(math.fabs(math.fabs(signedDist25) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist25, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
index 3e0f6617c32a345dbab7473f233034f2b715df63..a8b1f08b3a1ea82e8c37d56ee83d81b1c6a495fd 100644 (file)
@@ -125,7 +125,7 @@ def checkSmoothness(theSketch):
 
 def checkArcLineSmoothness(theArc, theLine):
     aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
-    aDistance = distancePointLine(aCenter, theLine)
+    aDistance = model.distancePointLine(aCenter, theLine)
     aRadius = arcRadius(theArc)
     assert(math.fabs(aRadius - aDistance) < TOLERANCE)
 
@@ -162,16 +162,6 @@ def arcRadius(theArc):
     aStart = geomDataAPI_Point2D(theArc.attribute("start_point"))
     return model.distancePointPoint(aCenter, aStart)
 
-def distancePointLine(thePoint, theLine):
-    aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint"))
-    aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint"))
-    aLength = model.distancePointPoint(aLineStart, aLineEnd)
-
-    aDir1x, aDir1y = aLineEnd.x() - aLineStart.x(), aLineEnd.y() - aLineStart.y()
-    aDir2x, aDir2y = thePoint.x() - aLineStart.x(), thePoint.y() - aLineStart.y()
-    aCross = aDir1x * aDir2y - aDir1y * aDir2x
-    return math.fabs(aCross) / aLength
-
 
 #=========================================================================
 # Initialization of the test
index 04160ace6312d62e5c7a2d6c9a121c93fa864b94..60783ed527bff4b6f0af2ba9c270341a679160df 100644 (file)
@@ -35,7 +35,7 @@ __updated__ = "2017-03-06"
 
 def isArcLineSmooth(theArc, theLine, theTolerance):
   aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
-  aDistance = distancePointLine(aCenter, theLine)
+  aDistance = model.distancePointLine(aCenter, theLine)
   aRadius = arcRadius(theArc)
   return math.fabs(aRadius - aDistance) < theTolerance
 
@@ -54,15 +54,6 @@ def arcRadius(theArc):
   aStart = geomDataAPI_Point2D(theArc.attribute("start_point"))
   return model.distancePointPoint(aCenter, aStart)
 
-def distancePointLine(thePoint, theLine):
-  aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint"))
-  aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint"))
-  aLength = model.distancePointPoint(aLineStart, aLineEnd)
-  aDir1x, aDir1y = aLineEnd.x() - aLineStart.x(), aLineEnd.y() - aLineStart.y()
-  aDir2x, aDir2y = thePoint.x() - aLineStart.x(), thePoint.y() - aLineStart.y()
-  aCross = aDir1x * aDir2y - aDir1y * aDir2x
-  return math.fabs(aCross) / aLength
-
 
 
 class TestFilletInteracting(unittest.TestCase):
diff --git a/src/SketchPlugin/Test/TestMoveArc.py b/src/SketchPlugin/Test/TestMoveArc.py
new file mode 100644 (file)
index 0000000..4419d85
--- /dev/null
@@ -0,0 +1,349 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    Test movement of the sketch arc of circle
+"""
+
+import unittest
+from GeomDataAPI import geomDataAPI_Point2D
+from salome.shaper import model
+
+__updated__ = "2017-05-11"
+
+class TestMoveArc(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myCenter = [50., 50.]
+    self.myStart = [70., 50.]
+    self.myEnd = [50., 70.]
+    self.myArc = self.mySketch.addArc(self.myCenter[0], self.myCenter[1], self.myStart[0], self.myStart[1], self.myEnd[0], self.myEnd[1], False)
+    self.myDOF = 5
+    model.do()
+    self.checkDOF()
+
+  def tearDown(self):
+    model.assertArcValidity(self.myArc)
+    self.checkDOF()
+    model.end()
+    assert(model.checkPythonDump())
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointCoordinates(self, thePoint, theCoordinates):
+    self.assertAlmostEqual(thePoint.x(), theCoordinates[0])
+    self.assertAlmostEqual(thePoint.y(), theCoordinates[1])
+
+  def checkPointOnArc(self, theCoordinates):
+    distPC = model.distancePointPoint(self.myArc.center(),  theCoordinates)
+    radius = model.distancePointPoint(self.myArc.center(), self.myArc.startPoint())
+    self.assertAlmostEqual(distPC, radius)
+
+  def checkArcRadius(self):
+    radius = model.distancePointPoint(self.myArc.center(), self.myArc.startPoint())
+    self.assertAlmostEqual(radius, self.myRadius)
+
+  def fixArcRadius(self):
+    self.myRadius = 20.
+    self.mySketch.setRadius(self.myArc.results()[1], self.myRadius)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+  def fixPoint(self, thePoint):
+    self.mySketch.setFixed(thePoint)
+    self.myDOF -= 2
+    model.do()
+    self.checkDOF()
+
+  def fixArc(self):
+    self.mySketch.setFixed(self.myArc.results()[1])
+    self.myDOF -= 5
+    model.do()
+    self.checkDOF()
+
+
+  def test_move_center_of_free_arc(self):
+    """ Test 1. Movement of center of a free arc
+    """
+    newPosition = [self.myCenter[0] + 10., self.myCenter[1] - 15.]
+    self.mySketch.move(self.myArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), newPosition)
+
+  def test_move_start_of_free_arc(self):
+    """ Test 2. Movement of start point of a free arc
+    """
+    newPosition = [self.myStart[0] - 10., self.myStart[1] + 5.]
+    self.mySketch.move(self.myArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), newPosition)
+
+  def test_move_end_of_free_arc(self):
+    """ Test 3. Movement of end point of a free arc
+    """
+    newPosition = [self.myEnd[0] + 10., self.myEnd[1] + 5.]
+    self.mySketch.move(self.myArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.endPoint(), newPosition)
+
+  def test_move_free_arc(self):
+    """ Test 4. Movement of a free arc dragging the edge
+    """
+    newPosition = [100., 80.]
+    self.mySketch.move(self.myArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointOnArc(newPosition)
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+
+  def test_move_center_of_arc_fixed_center(self):
+    """ Test 5. Movement of center of the arc with fixed center (nothing should be changed)
+    """
+    self.fixPoint(self.myArc.center())
+
+    newPosition = [self.myCenter[0] + 10., self.myCenter[1] - 15.]
+    self.mySketch.move(self.myArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+
+  def test_move_start_of_arc_fixed_center(self):
+    """ Test 6. Movement of start point of the arc with fixed center
+    """
+    self.fixPoint(self.myArc.center())
+
+    newPosition = [self.myStart[0] - 10., self.myStart[1] + 5.]
+    self.mySketch.move(self.myArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), newPosition)
+
+  def test_move_end_of_arc_fixed_center(self):
+    """ Test 7. Movement of end point of the arc with fixed center
+    """
+    self.fixPoint(self.myArc.center())
+
+    newPosition = [self.myEnd[0] + 10., self.myEnd[1] + 5.]
+    self.mySketch.move(self.myArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.endPoint(), newPosition)
+
+  def test_move_arc_fixed_center(self):
+    """ Test 8. Movement of the arc with fixed center dragging the edge
+    """
+    self.fixPoint(self.myArc.center())
+
+    newPosition = [100., 80.]
+    self.mySketch.move(self.myArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointOnArc(newPosition)
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+
+  def test_move_center_of_arc_fixed_start(self):
+    """ Test 9. Movement of center of the arc with fixed start point
+    """
+    self.fixPoint(self.myArc.startPoint())
+
+    newPosition = [self.myCenter[0] + 10., self.myCenter[1] - 15.]
+    self.mySketch.move(self.myArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), newPosition)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+
+  def test_move_start_of_arc_fixed_start(self):
+    """ Test 10. Movement of start point of the arc with fixed start point (nothing should be changed)
+    """
+    self.fixPoint(self.myArc.startPoint())
+
+    newPosition = [self.myStart[0] - 10., self.myStart[1] + 5.]
+    self.mySketch.move(self.myArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+  def test_move_end_of_arc_fixed_start(self):
+    """ Test 11. Movement of end point of the arc with fixed start point
+    """
+    self.fixPoint(self.myArc.startPoint())
+
+    newPosition = [self.myEnd[0] + 10., self.myEnd[1] + 5.]
+    self.mySketch.move(self.myArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.assertNotEqual(self.myArc.center().x(), self.myCenter[0])
+    self.assertNotEqual(self.myArc.center().y(), self.myCenter[1])
+
+  def test_move_arc_fixed_start(self):
+    """ Test 12. Movement of the arc with fixed start point dragging the edge
+    """
+    self.fixPoint(self.myArc.startPoint())
+
+    newPosition = [100., 80.]
+    self.mySketch.move(self.myArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.assertNotEqual(self.myArc.center().x(), self.myCenter[0])
+    self.assertNotEqual(self.myArc.center().y(), self.myCenter[1])
+
+  def test_move_center_of_arc_fixed_end(self):
+    """ Test 13. Movement of center of the arc with fixed end point
+    """
+    self.fixPoint(self.myArc.endPoint())
+
+    newPosition = [self.myCenter[0] + 10., self.myCenter[1] - 15.]
+    self.mySketch.move(self.myArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), newPosition)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+  def test_move_start_of_arc_fixed_end(self):
+    """ Test 14. Movement of start point of the arc with fixed end point
+    """
+    self.fixPoint(self.myArc.endPoint())
+
+    newPosition = [self.myStart[0] - 10., self.myStart[1] + 5.]
+    self.mySketch.move(self.myArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+    self.assertNotEqual(self.myArc.center().x(), self.myCenter[0])
+    self.assertNotEqual(self.myArc.center().y(), self.myCenter[1])
+
+  def test_move_end_of_arc_fixed_end(self):
+    """ Test 15. Movement of end point of the arc with fixed end point (nothing should be changed)
+    """
+    self.fixPoint(self.myArc.endPoint())
+
+    newPosition = [self.myEnd[0] + 10., self.myEnd[1] + 5.]
+    self.mySketch.move(self.myArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+  def test_move_arc_fixed_end(self):
+    """ Test 16. Movement of the arc with fixed end point dragging the edge
+    """
+    self.fixPoint(self.myArc.endPoint())
+
+    newPosition = [100., 80.]
+    self.mySketch.move(self.myArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+    self.assertNotEqual(self.myArc.center().x(), self.myCenter[0])
+    self.assertNotEqual(self.myArc.center().y(), self.myCenter[1])
+
+  def test_move_center_of_arc_fixed_radius(self):
+    """ Test 17. Movement of center of the arc with fixed radius
+    """
+    self.fixArcRadius()
+
+    newPosition = [self.myCenter[0] + 10., self.myCenter[1] - 15.]
+    self.mySketch.move(self.myArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), newPosition)
+    self.checkArcRadius()
+
+  def test_move_start_of_arc_fixed_radius(self):
+    """ Test 18. Movement of start point of the arc with fixed radius
+    """
+    self.fixArcRadius()
+
+    newPosition = [self.myStart[0] - 10., self.myStart[1] + 5.]
+    self.mySketch.move(self.myArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkArcRadius()
+
+  def test_move_end_of_arc_fixed_radius(self):
+    """ Test 19. Movement of end point of the arc with fixed radius
+    """
+    self.fixArcRadius()
+
+    newPosition = [self.myEnd[0] + 10., self.myEnd[1] + 5.]
+    self.mySketch.move(self.myArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkArcRadius()
+
+  def test_move_arc_fixed_radius(self):
+    """ Test 20. Movement of the arc with fixed radius dragging the edge
+    """
+    self.fixArcRadius()
+
+    newPosition = [100., 80.]
+    self.mySketch.move(self.myArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkArcRadius()
+
+  def test_move_center_of_fixed_arc(self):
+    """ Test 21. Movement of center of fully fixed arc (nothing should be changed)
+    """
+    self.fixArc()
+
+    newPosition = [self.myCenter[0] + 10., self.myCenter[1] - 15.]
+    self.mySketch.move(self.myArc.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+  def test_move_start_of_fixed_arc(self):
+    """ Test 22. Movement of start point of fully fixed arc (nothing should be changed)
+    """
+    self.fixArc()
+
+    newPosition = [self.myStart[0] - 10., self.myStart[1] + 5.]
+    self.mySketch.move(self.myArc.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+  def test_move_end_of_fixed_arc(self):
+    """ Test 23. Movement of end point of fully fixed arc (nothing should be changed)
+    """
+    self.fixArc()
+
+    newPosition = [self.myEnd[0] + 10., self.myEnd[1] + 5.]
+    self.mySketch.move(self.myArc.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+  def test_move_fixed_arc(self):
+    """ Test 24. Movement of fully fixed arc (nothing should be changed)
+    """
+    self.fixArc()
+
+    newPosition = [100., 80.]
+    self.mySketch.move(self.myArc.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myArc.center(), self.myCenter)
+    self.checkPointCoordinates(self.myArc.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myArc.endPoint(), self.myEnd)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/SketchPlugin/Test/TestMoveCircle.py b/src/SketchPlugin/Test/TestMoveCircle.py
new file mode 100644 (file)
index 0000000..54a9b58
--- /dev/null
@@ -0,0 +1,149 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    Test movement of the sketch circle
+"""
+
+import unittest
+from GeomDataAPI import geomDataAPI_Point2D
+from salome.shaper import model
+
+__updated__ = "2017-05-11"
+
+class TestMoveCircle(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.myRadius = 20.
+    self.myCircle = self.mySketch.addCircle(self.myCenter[0], self.myCenter[1], self.myRadius)
+    self.myDOF = 3
+    model.do()
+    self.checkDOF()
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+    assert(model.checkPythonDump())
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointCoordinates(self, thePoint, theCoordinates):
+    self.assertAlmostEqual(thePoint.x(), theCoordinates[0])
+    self.assertAlmostEqual(thePoint.y(), theCoordinates[1])
+
+  def checkPointOnCircle(self, theCoordinates):
+    self.assertAlmostEqual(model.distancePointPoint(self.myCircle.center(),  theCoordinates), self.myCircle.radius().value())
+
+  def fixCircleRadius(self):
+    self.mySketch.setRadius(self.myCircle.results()[1], self.myRadius)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+  def fixCircleCenter(self):
+    self.mySketch.setFixed(self.myCircle.center())
+    self.myDOF -= 2
+    model.do()
+    self.checkDOF()
+
+
+  def test_move_center_free_circle(self):
+    """ Test 1. Movement of central point of a free circle
+    """
+    newPosition = [self.myCenter[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myCircle.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myCircle.center(), newPosition)
+    self.assertAlmostEqual(self.myCircle.radius().value(), self.myRadius)
+
+  def test_move_free_circle(self):
+    """ Test 2. Movement of a free circle dragging the edge
+    """
+    newPosition = [120., 90.]
+    self.mySketch.move(self.myCircle.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myCircle.center(), self.myCenter)
+    self.checkPointOnCircle(newPosition)
+    self.assertNotEqual(self.myCircle.radius().value(), self.myRadius)
+
+  def test_move_center_circle_fixed_radius(self):
+    """ Test 3. Movement of central point of a circle with fixed radius
+    """
+    self.fixCircleRadius()
+
+    newPosition = [self.myCenter[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myCircle.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myCircle.center(), newPosition)
+    self.assertAlmostEqual(self.myCircle.radius().value(), self.myRadius)
+
+  def test_move_circle_fixed_radius(self):
+    """ Test 4. Movement of a circle with fixed radius
+    """
+    self.fixCircleRadius()
+
+    newPosition = [120., 90.]
+    self.mySketch.move(self.myCircle.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.assertAlmostEqual(self.myCircle.radius().value(), self.myRadius)
+    self.assertNotEqual(self.myCircle.center().x(), self.myCenter[0])
+    self.assertNotEqual(self.myCircle.center().y(), self.myCenter[1])
+
+  def test_move_center_circle_fixed_center(self):
+    """ Test 5. Movement of central point of a circle with fixed center (nothing should be changed)
+    """
+    self.fixCircleCenter()
+
+    newPosition = [self.myCenter[0] + 20., self.myCenter[1] + 10.]
+    self.mySketch.move(self.myCircle.center(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myCircle.center(), self.myCenter)
+    self.assertAlmostEqual(self.myCircle.radius().value(), self.myRadius)
+
+  def test_move_circle_fixed_center(self):
+    """ Test 6. Movement of a circle with fixed center
+    """
+    self.fixCircleCenter()
+
+    newPosition = [120., 90.]
+    self.mySketch.move(self.myCircle.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointOnCircle(newPosition)
+    self.assertNotEqual(self.myCircle.radius().value(), self.myRadius)
+
+  def test_move_fixed_circle(self):
+    """ Test 7. Trying to move fully fixed circle
+    """
+    self.fixCircleCenter()
+    self.fixCircleRadius()
+
+    newPosition = [120., 90.]
+    self.mySketch.move(self.myCircle.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myCircle.center(), self.myCenter)
+    self.assertAlmostEqual(self.myCircle.radius().value(), self.myRadius)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/SketchPlugin/Test/TestMoveLine.py b/src/SketchPlugin/Test/TestMoveLine.py
new file mode 100644 (file)
index 0000000..3d4efa1
--- /dev/null
@@ -0,0 +1,136 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    Test movement of the sketch line
+"""
+
+import unittest
+from GeomDataAPI import geomDataAPI_Point2D
+from salome.shaper import model
+
+__updated__ = "2017-05-11"
+
+class TestMoveLine(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myStart = [70., 50.]
+    self.myEnd = [100., 20.]
+    self.myLine = self.mySketch.addLine(self.myStart[0], self.myStart[1], self.myEnd[0], self.myEnd[1])
+    self.myDOF = 4
+    model.do()
+    self.checkDOF()
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+    assert(model.checkPythonDump())
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointCoordinates(self, thePoint, theCoordinates):
+    self.assertAlmostEqual(thePoint.x(), theCoordinates[0])
+    self.assertAlmostEqual(thePoint.y(), theCoordinates[1])
+
+  def checkPointOnLine(self, theCoordinates):
+    self.assertAlmostEqual(model.distancePointLine(theCoordinates, self.myLine), 0.)
+
+  def test_move_start_of_free_line(self):
+    """ Test 1. Movement of start point of a free line
+    """
+    newPosition = [self.myStart[0] + 20., self.myStart[1] + 10.]
+    self.mySketch.move(self.myLine.startPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myLine.startPoint(), newPosition)
+    self.checkPointCoordinates(self.myLine.endPoint(), self.myEnd)
+
+  def test_move_end_of_free_line(self):
+    """ Test 2. Movement of end point of a free line
+    """
+    newPosition = [self.myEnd[0] + 20., self.myEnd[1] + 10.]
+    self.mySketch.move(self.myLine.endPoint(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myLine.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myLine.endPoint(), newPosition)
+
+  def test_move_free_line(self):
+    """ Test 3. Movement of free line
+    """
+    diff = [self.myEnd[0] - self.myStart[0], self.myEnd[1] - self.myStart[1]]
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myLine.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointOnLine(newPosition)
+
+    # additionally check the line keeps geometry (relative positions of extremities)
+    startPoint = self.myLine.startPoint()
+    endPoint = [startPoint.x() + diff[0], startPoint.y() + diff[1]]
+    self.checkPointCoordinates(self.myLine.endPoint(), endPoint)
+
+  def test_move_line_start_fixed(self):
+    """ Test 4. Movement of a line, which start point is fixed
+    """
+    fixed = self.mySketch.setFixed(self.myLine.startPoint())
+    self.myDOF -= 2
+    model.do()
+    self.checkDOF()
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myLine.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myLine.startPoint(), self.myStart)
+    self.assertNotEqual(self.myLine.endPoint().x(), self.myEnd[0])
+    self.assertNotEqual(self.myLine.endPoint().y(), self.myEnd[1])
+
+  def test_move_line_end_fixed(self):
+    """ Test 5. Movement of a line, which end point is fixed
+    """
+    fixed = self.mySketch.setFixed(self.myLine.endPoint())
+    self.myDOF -= 2
+    model.do()
+    self.checkDOF()
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myLine.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.assertNotEqual(self.myLine.startPoint().x(), self.myStart[0])
+    self.assertNotEqual(self.myLine.startPoint().y(), self.myStart[1])
+    self.checkPointCoordinates(self.myLine.endPoint(), self.myEnd)
+
+  def test_move_line_fully_fixed(self):
+    """ Test 6. Movement of fully fixed line (should not change its coordinates)
+    """
+    fixed = self.mySketch.setFixed(self.myLine.defaultResult())
+    self.myDOF -= 4
+    model.do()
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myLine.defaultResult(), newPosition[0], newPosition[1])
+    model.do()
+    self.checkPointCoordinates(self.myLine.startPoint(), self.myStart)
+    self.checkPointCoordinates(self.myLine.endPoint(), self.myEnd)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/SketchPlugin/Test/TestMovePoint.py b/src/SketchPlugin/Test/TestMovePoint.py
new file mode 100644 (file)
index 0000000..60b0a43
--- /dev/null
@@ -0,0 +1,108 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    Test movement of the sketch point
+"""
+
+import unittest
+from GeomDataAPI import geomDataAPI_Point2D
+from salome.shaper import model
+
+__updated__ = "2017-05-11"
+
+class TestMovePoint(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myOrigin = self.mySketch.addPoint(model.selection("VERTEX", "Origin"))
+    self.myPoint = self.mySketch.addPoint(70, 50)
+    self.myPointCoordinates = geomDataAPI_Point2D(self.myPoint.coordinates())
+    self.myDOF = 2
+    model.do()
+    self.checkDOF()
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+    assert(model.checkPythonDump())
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def test_move_free_point(self):
+    """ Test 1. Movement of free point
+    """
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myPoint, newPosition[0], newPosition[1])
+    model.do()
+    self.assertAlmostEqual(self.myPointCoordinates.x(), newPosition[0])
+    self.assertAlmostEqual(self.myPointCoordinates.y(), newPosition[1])
+
+  def test_move_fixed_x(self):
+    """ Test 2. Movement of partially fixed point (fixed x coordinate)
+    """
+    DISTANCE = 50.
+    horizDistance = self.mySketch.setHorizontalDistance(self.myOrigin.result(), self.myPoint.coordinates(), DISTANCE)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myPoint, newPosition[0], newPosition[1])
+    model.do()
+    self.assertAlmostEqual(self.myPointCoordinates.x(), DISTANCE)
+    self.assertAlmostEqual(self.myPointCoordinates.y(), newPosition[1])
+
+  def test_move_fixed_y(self):
+    """ Test 3. Movement of partially fixed point (fixed y coordinate)
+    """
+    DISTANCE = 50.
+    vertDistance = self.mySketch.setVerticalDistance(self.myOrigin.result(), self.myPoint.coordinates(), DISTANCE)
+    self.myDOF -= 1
+    model.do()
+    self.checkDOF()
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myPoint, newPosition[0], newPosition[1])
+    model.do()
+    self.assertAlmostEqual(self.myPointCoordinates.x(), newPosition[0])
+    self.assertAlmostEqual(self.myPointCoordinates.y(), DISTANCE)
+
+  def test_move_fully_fixed(self):
+    """ Test 4. Movement of fully fixed point (should not be changed)
+    """
+    coord = [self.myPointCoordinates.x(), self.myPointCoordinates.y()]
+
+    fixed = self.mySketch.setFixed(self.myPoint.result())
+    self.myDOF -= 2
+    model.do()
+    self.checkDOF()
+
+    newPosition = [100., 100.]
+    self.mySketch.move(self.myPoint, newPosition[0], newPosition[1])
+    model.do()
+    self.assertAlmostEqual(self.myPointCoordinates.x(), coord[0])
+    self.assertAlmostEqual(self.myPointCoordinates.y(), coord[1])
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/SketchPlugin/Test/TestMovementComplex.py b/src/SketchPlugin/Test/TestMovementComplex.py
new file mode 100644 (file)
index 0000000..6fe6afe
--- /dev/null
@@ -0,0 +1,384 @@
+## Copyright (C) 2017  CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    Test moving the entities in the complex sketch by the example of a clamp
+"""
+
+from salome.shaper import model
+from SketchAPI import *
+from GeomAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+# Create sketch representing main part of clamp
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(20, 165, 175, 165)
+SketchLine_2 = Sketch_1.addLine(175, 165, 175, 120)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(175, 120, 80, 20)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(80, 20, 20, 20)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(20, 20, 20, 165)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.endPoint())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 155)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintParallel_1 = Sketch_1.setParallel(SketchLine_1.result(), SketchLine_4.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_5.result())
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 45)
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_4.startPoint(), SketchLine_1.result(), 145)
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchLine_3.startPoint(), 95)
+SketchPoint_1 = Sketch_1.addPoint(model.selection("VERTEX", "PartSet/Origin"))
+SketchConstraintDistanceHorizontal_2 = Sketch_1.setHorizontalDistance(SketchPoint_1.coordinates(), SketchLine_5.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchPoint_1.coordinates(), SketchLine_5.endPoint(), 165)
+model.do()
+
+# =============================================================================
+# Test 1. Create fillet and move fillet arc
+# =============================================================================
+Sketch_1.setFillet(SketchLine_5.startPoint())
+SketchArc_1 = SketchAPI_Arc(model.lastSubFeature(Sketch_1, "SketchArc"))
+model.do()
+anArcCenter = [SketchArc_1.center().x(), SketchArc_1.center().y()]
+anArcStart  = [SketchArc_1.startPoint().x(), SketchArc_1.startPoint().y()]
+anArcEnd    = [SketchArc_1.endPoint().x(), SketchArc_1.endPoint().y()]
+# move arc dragging center
+delta = [1., 1.]
+for i in range(1, 10):
+    anArcCenter = [anArcCenter[0] + delta[0], anArcCenter[1] + delta[1]]
+    Sketch_1.move(SketchArc_1.center(), anArcCenter[0], anArcCenter[1])
+    model.do()
+    model.assertArcValidity(SketchArc_1)
+    model.assertPoint(SketchArc_1.center(), anArcCenter)
+    assert(SketchArc_1.startPoint().x() == anArcStart[0])
+    assert(SketchArc_1.endPoint().y() == anArcEnd[1])
+    if i == 5:
+        delta = [-1., -1.]
+# move arc dragging start point
+delta = [1., 1.]
+aPosition = anArcStart
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchArc_1.startPoint(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertArcValidity(SketchArc_1)
+    assert(SketchArc_1.startPoint().x() == anArcStart[0])
+    assert(SketchArc_1.endPoint().y() == anArcEnd[1])
+    if i == 5:
+        delta = [-1., -1.]
+# move arc dragging end point
+delta = [1., 1.]
+aPosition = anArcEnd
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchArc_1.endPoint(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertArcValidity(SketchArc_1)
+    assert(SketchArc_1.startPoint().x() == anArcStart[0])
+    assert(SketchArc_1.endPoint().y() == anArcEnd[1])
+    if i == 5:
+        delta = [-1., -1.]
+
+# =============================================================================
+# Test 2. Create circle and move it near its potential position
+# =============================================================================
+aCircleCenter = [0, 0]
+aCircleRadius = 5
+SketchCircle_1 = Sketch_1.addCircle(aCircleCenter[0], aCircleCenter[1], aCircleRadius)
+model.do()
+# move center
+delta = [3., 2.]
+for i in range(1, 15):
+    aCircleCenter = [aCircleCenter[0] + delta[0], aCircleCenter[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.center(), aCircleCenter[0], aCircleCenter[1])
+    model.do()
+    model.assertPoint(SketchCircle_1.center(), aCircleCenter)
+    assert(SketchCircle_1.radius().value() == aCircleRadius)
+# move circle by dragging edge
+aPosition = [aCircleCenter[0] + aCircleRadius, aCircleCenter[1]]
+delta = [1., 1.]
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.defaultResult(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertPoint(SketchCircle_1.center(), aCircleCenter)
+    assert(math.fabs(SketchCircle_1.radius().value() - model.distancePointPoint(aPosition, aCircleCenter)) < TOLERANCE)
+
+# =============================================================================
+# Test 3. Constrain center of circle and move it again
+# =============================================================================
+SketchConstraintDistanceHorizontal_3 = Sketch_1.setHorizontalDistance(SketchCircle_1.center(), SketchArc_1.startPoint(), -30)
+model.do()
+# move center
+delta = [1., 1.]
+aCircleCenter = [SketchCircle_1.center().x(), SketchCircle_1.center().y()]
+aPosition = aCircleCenter
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.center(), aPosition[0], aPosition[1])
+    model.do()
+    assert(SketchCircle_1.center().x() == aCircleCenter[0])
+    if i == 5:
+        delta = [-1., -1.]
+# move circle by dragging edge
+aCircleCenter = [SketchCircle_1.center().x(), SketchCircle_1.center().y()]
+aPosition = [aCircleCenter[0] + aCircleRadius, aCircleCenter[1]]
+delta = [1., 1.]
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.defaultResult(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertPoint(SketchCircle_1.center(), aCircleCenter)
+    assert(math.fabs(SketchCircle_1.radius().value() - model.distancePointPoint(aPosition, aCircleCenter)) < TOLERANCE)
+# set radius of the circle
+aCircleRadius = 17.5
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], aCircleRadius)
+model.do()
+# move center
+delta = [1., 1.]
+aCircleCenter = [SketchCircle_1.center().x(), SketchCircle_1.center().y()]
+aPosition = aCircleCenter
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.center(), aPosition[0], aPosition[1])
+    model.do()
+    assert(SketchCircle_1.center().x() == aCircleCenter[0])
+    assert(SketchCircle_1.radius().value() == aCircleRadius)
+    if i == 5:
+        delta = [-1., -1.]
+# move circle by dragging edge
+aCircleCenter = [SketchCircle_1.center().x(), SketchCircle_1.center().y()]
+aPosition = [aCircleCenter[0] + aCircleRadius, aCircleCenter[1]]
+delta = [1., 1.]
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.defaultResult(), aPosition[0], aPosition[1])
+    model.do()
+    assert(SketchCircle_1.center().x() == aCircleCenter[0])
+    assert(SketchCircle_1.radius().value() == aCircleRadius)
+
+# =============================================================================
+# Test 4. Set centers of circle and arc coincident and move circle
+# =============================================================================
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchArc_1.center())
+model.do()
+assert(model.dof(Sketch_1) == 0)
+# move circle
+aCircleCenter = [SketchCircle_1.center().x(), SketchCircle_1.center().y()]
+aPosition = [aCircleCenter[0], aCircleCenter[1] + aCircleRadius]
+delta = [0., 1.]
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_1.defaultResult(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertPoint(SketchCircle_1.center(), aCircleCenter)
+    assert(SketchCircle_1.radius().value() == aCircleRadius)
+assert(model.dof(Sketch_1) == 0)
+
+# Extrude main part of clamp
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2r-SketchLine_3r-SketchLine_4r-SketchLine_5r-SketchArc_1_2f-SketchCircle_1_2r")], model.selection(), 10, 0)
+model.do()
+
+
+# Create sketch representing orthogonal part of clamp
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchRectangle_1 = Sketch_2.addRectangle(20, 0, 100, 50)
+[SketchLine_6, SketchLine_7, SketchLine_8, SketchLine_9] = SketchRectangle_1.lines()
+SketchProjection_1 = Sketch_2.addProjection(model.selection("EDGE", "Sketch_1/Edge-SketchLine_1"))
+SketchLine_10 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_7).startPoint(), SketchAPI_Line(SketchLine_10).startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_8.result(), SketchLine_10.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_7.result(), 80)
+model.do()
+assert(model.dof(Sketch_2) == 0)
+
+# Create auxiliary lines for further holes
+SketchLine_11 = Sketch_2.addLine(20, 10, 175, 10)
+SketchLine_11.setAuxiliary(True)
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchLine_11.startPoint(), SketchLine_7.result())
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchLine_9.result())
+SketchConstraintParallel_2 = Sketch_2.setParallel(SketchLine_11.result(), SketchLine_8.result())
+SketchLine_12 = Sketch_2.addLine(150, 0, 150, 80)
+SketchLine_12.setAuxiliary(True)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_12.startPoint(), SketchLine_6.result())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_12.endPoint(), SketchLine_8.result())
+SketchConstraintPerpendicular_2 = Sketch_2.setPerpendicular(SketchLine_11.result(), SketchLine_12.result())
+model.do()
+assert(model.dof(Sketch_2) == 2)
+
+# =============================================================================
+# Test 5. Create circular hole and move it
+# =============================================================================
+SketchCircle_2 = Sketch_2.addCircle(50, 10, 10)
+SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchCircle_2.center(), SketchLine_11.result())
+model.do()
+# move center
+delta = [2., 1.]
+aCircleCenter = [SketchCircle_2.center().x(), SketchCircle_2.center().y()]
+aCircleRadius = SketchCircle_2.radius().value()
+for i in range(1, 10):
+    aCircleCenter = [aCircleCenter[0] + delta[0], aCircleCenter[1] + delta[1]]
+    Sketch_2.move(SketchCircle_2.center(), aCircleCenter[0], aCircleCenter[1])
+    model.do()
+    model.assertPoint(SketchCircle_2.center(), aCircleCenter)
+    assert(aCircleRadius == SketchCircle_2.radius().value())
+# move circle by dragging edge
+aCircleCenter = [SketchCircle_2.center().x(), SketchCircle_2.center().y()]
+aPosition = [aCircleCenter[0] + aCircleRadius, aCircleCenter[1]]
+delta = [0., 1.]
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_1.move(SketchCircle_2.defaultResult(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertPoint(SketchCircle_2.center(), aCircleCenter)
+    assert(math.fabs(SketchCircle_2.radius().value() - model.distancePointPoint(aPosition, aCircleCenter)) < TOLERANCE)
+
+SketchConstraintDistanceHorizontal_4 = Sketch_2.setHorizontalDistance(SketchLine_11.startPoint(), SketchCircle_2.center(), 21.5)
+model.do()
+assert(model.dof(Sketch_2) == 3)
+
+# =============================================================================
+# Test 6. Create oval hole and move it
+# =============================================================================
+anArcRadius = 5
+anArcCenter = [SketchLine_11.endPoint().x() + anArcRadius, SketchCircle_2.center().y()]
+SketchArc_2 = Sketch_2.addArc(anArcCenter[0], anArcCenter[1], anArcCenter[0], anArcCenter[1] + anArcRadius, anArcCenter[0], anArcCenter[1] - anArcRadius, True)
+SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchArc_2.center(), SketchLine_11.result())
+SketchLine_13 = Sketch_2.addLine(anArcCenter[0], anArcCenter[1] + anArcRadius, SketchLine_12.startPoint().x(), anArcCenter[1] + anArcRadius)
+SketchConstraintCoincidence_14 = Sketch_2.setCoincident(SketchArc_2.startPoint(), SketchLine_13.startPoint())
+SketchConstraintCoincidence_15 = Sketch_2.setCoincident(SketchLine_13.endPoint(), SketchLine_12.result())
+SketchConstraintPerpendicular_3 = Sketch_2.setPerpendicular(SketchLine_13.result(), SketchLine_12.result())
+SketchLine_14 = Sketch_2.addLine(anArcCenter[0], anArcCenter[1] - anArcRadius, SketchLine_12.startPoint().x(), anArcCenter[1] - anArcRadius)
+SketchConstraintCoincidence_16 = Sketch_2.setCoincident(SketchArc_2.endPoint(), SketchLine_14.startPoint())
+SketchConstraintCoincidence_17 = Sketch_2.setCoincident(SketchLine_14.endPoint(), SketchLine_12.result())
+SketchConstraintPerpendicular_4 = Sketch_2.setPerpendicular(SketchLine_14.result(), SketchLine_12.result())
+SketchConstraintTangent_1 = Sketch_2.setTangent(SketchArc_2.results()[1], SketchLine_13.result())
+SketchConstraintTangent_2 = Sketch_2.setTangent(SketchArc_2.results()[1], SketchLine_14.result())
+model.do()
+assert(model.dof(Sketch_2) == 5)
+# move center of arc
+delta = [-2., 1.]
+anArcCenter = [SketchArc_2.center().x(), SketchArc_2.center().y()]
+for i in range(1, 10):
+    anArcCenter = [anArcCenter[0] + delta[0], anArcCenter[1] + delta[1]]
+    Sketch_2.move(SketchArc_2.center(), anArcCenter[0], anArcCenter[1])
+    model.do()
+    model.assertArc(SketchArc_2, anArcCenter, [], [])
+
+# Complete the oval hole
+SketchConstraintMirror_1_objects = [SketchLine_13.result(), SketchArc_2.results()[1], SketchLine_14.result()]
+SketchConstraintMirror_1 = Sketch_2.addMirror(SketchLine_12.result(), SketchConstraintMirror_1_objects)
+[SketchLine_15, SketchArc_3, SketchLine_16] = SketchConstraintMirror_1.mirrored()
+model.do()
+
+# =============================================================================
+# Test 7. Set arc and circle equal radii and move arc
+# =============================================================================
+SketchConstraintEqual_2 = Sketch_2.setEqual(SketchCircle_2.results()[1], SketchArc_2.results()[1])
+model.do()
+# move center of arc
+delta = [-1., -1.]
+anArcCenter = [SketchArc_2.center().x(), SketchArc_2.center().y()]
+aCircleCenter = [SketchCircle_2.center().x(), SketchCircle_2.center().y()]
+for i in range(1, 10):
+    anArcCenter = [anArcCenter[0] + delta[0], anArcCenter[1] + delta[1]]
+    Sketch_2.move(SketchArc_2.center(), anArcCenter[0], anArcCenter[1])
+    model.do()
+    model.assertArc(SketchArc_2, anArcCenter, [], [])
+    model.assertPoint(SketchCircle_2.center(), [aCircleCenter[0], anArcCenter[1]])
+    anArcRadius = model.distancePointPoint(SketchArc_2.center(), SketchArc_2.startPoint())
+    assert(math.fabs(SketchCircle_2.radius().value() - anArcRadius) < TOLERANCE)
+# move arc by dragging edge
+aCircleCenter = [SketchCircle_2.center().x(), SketchCircle_2.center().y()]
+anArcCenter = [SketchArc_2.center().x(), SketchArc_2.center().y()]
+aPosition = [anArcCenter[0] + anArcRadius, anArcCenter[1]]
+delta = [1., 1.]
+for i in range(1, 10):
+    aPosition = [aPosition[0] + delta[0], aPosition[1] + delta[1]]
+    Sketch_2.move(SketchArc_2.defaultResult(), aPosition[0], aPosition[1])
+    model.do()
+    model.assertArc(SketchArc_2, anArcCenter, [], [])
+    model.assertPoint(SketchCircle_2.center(), aCircleCenter)
+    anArcRadius = model.distancePointPoint(SketchArc_2.center(), SketchArc_2.startPoint())
+    assert(math.fabs(SketchCircle_2.radius().value() - anArcRadius) < TOLERANCE)
+    if i == 5:
+        delta = [-1., -1.]
+
+# Fix all DOF in Sketch_2
+SketchConstraintDistance_2 = Sketch_2.setDistance(SketchArc_2.center(), SketchLine_9.result(), 21.5)
+SketchConstraintLength_4 = Sketch_2.setLength(SketchLine_13.result(), 3.5)
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_2.results()[1], 6.5)
+SketchConstraintDistance_3 = Sketch_2.setDistance(SketchCircle_2.center(), SketchLine_8.result(), 30)
+model.do()
+
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_6r-SketchLine_7r-SketchLine_8r-SketchLine_9r-SketchCircle_2_2r-SketchArc_2_2r-SketchLine_13r-SketchLine_14f-SketchLine_15f-SketchArc_3_2r-SketchLine_16r")], model.selection(), -165, 155)
+Boolean_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], [model.selection("SOLID", "Extrusion_2_1")])
+
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Boolean_1_1/Modified_8"))
+SketchLine_17 = Sketch_3.addLine(145, 0, 165, 0)
+SketchPoint_2 = Sketch_3.addPoint(model.selection("VERTEX", "Boolean_1_1/Modified_7&Boolean_1_1/Modified_6&Boolean_1_1/Modified_2"))
+SketchConstraintCoincidence_23 = Sketch_3.setCoincident(SketchLine_17.endPoint(), SketchPoint_2.result())
+SketchLine_18 = Sketch_3.addLine(165, 0, 165, -20)
+SketchLine_19 = Sketch_3.addLine(165, -20, 145, -20)
+SketchLine_20 = Sketch_3.addLine(145, -20, 145, 0)
+SketchConstraintCoincidence_24 = Sketch_3.setCoincident(SketchLine_20.endPoint(), SketchLine_17.startPoint())
+SketchConstraintCoincidence_25 = Sketch_3.setCoincident(SketchLine_17.endPoint(), SketchLine_18.startPoint())
+SketchConstraintCoincidence_26 = Sketch_3.setCoincident(SketchLine_18.endPoint(), SketchLine_19.startPoint())
+SketchConstraintCoincidence_27 = Sketch_3.setCoincident(SketchLine_19.endPoint(), SketchLine_20.startPoint())
+SketchConstraintHorizontal_4 = Sketch_3.setHorizontal(SketchLine_17.result())
+SketchConstraintVertical_4 = Sketch_3.setVertical(SketchLine_18.result())
+SketchConstraintHorizontal_5 = Sketch_3.setHorizontal(SketchLine_19.result())
+SketchConstraintVertical_5 = Sketch_3.setVertical(SketchLine_20.result())
+SketchArc_4 = Sketch_3.addArc(145, -20, 165, -20, 145, 0, False)
+SketchConstraintCoincidence_28 = Sketch_3.setCoincident(SketchLine_19.endPoint(), SketchArc_4.center())
+SketchConstraintCoincidence_29 = Sketch_3.setCoincident(SketchLine_18.endPoint(), SketchArc_4.startPoint())
+SketchConstraintCoincidence_30 = Sketch_3.setCoincident(SketchArc_4.endPoint(), SketchLine_20.endPoint())
+SketchConstraintRadius_3 = Sketch_3.setRadius(SketchArc_4.results()[1], 20)
+SketchArc_5 = Sketch_3.addArc(145, -20, 155, -20, 145, -10, False)
+SketchConstraintCoincidence_31 = Sketch_3.setCoincident(SketchLine_19.endPoint(), SketchArc_5.center())
+SketchConstraintCoincidence_32 = Sketch_3.setCoincident(SketchLine_20.result(), SketchArc_5.endPoint())
+SketchConstraintCoincidence_33 = Sketch_3.setCoincident(SketchArc_5.startPoint(), SketchLine_19.result())
+SketchLine_21 = Sketch_3.addLine(model.selection("EDGE", "Boolean_1_1/Modified_12&Boolean_1_1/Modified_11"))
+SketchConstraintTangent_5 = Sketch_3.setTangent(SketchArc_5.results()[1], SketchLine_21.result())
+model.do()
+
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Sketch_3/Face-SketchLine_17r-SketchLine_18r-SketchArc_4_2r")], model.selection(), model.selection("FACE", "Boolean_1_1/Modified_5"), 0, model.selection(), 0, [model.selection("SOLID", "Boolean_1_1")])
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [model.selection("FACE", "Sketch_3/Face-SketchLine_19r-SketchLine_20r-SketchArc_4_2f-SketchArc_5_2r")], model.selection(), model.selection("FACE", "ExtrusionCut_1_1/Modfied_7"), 0, model.selection(), 0, [model.selection("SOLID", "ExtrusionCut_1_1")])
+model.do()
+
+model.end()
+
+model.testNbResults(ExtrusionFuse_1, 1)
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.FACE, [30])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.EDGE, [140])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.VERTEX, [280])
+model.testResultsVolumes(ExtrusionFuse_1, [260653.824775497108930721879005432])
+
+assert(model.checkPythonDump())
index 4b358529c72f3a7fd3fda6f35d782606ad58f9bd..7e24e3ed5b3916a2794bcabc919992dafb416b42 100644 (file)
@@ -95,14 +95,17 @@ aSession.finishOperation()
 aSession.startOperation()
 aLineProjector = aSketchFeature.addFeature("SketchProjection")
 aLineProjector.selection("ExternalFeature").selectSubShape("EDGE", "Sketch_1/Edge-SketchLine_1")
+aLineProjector.boolean("IncludeToResult").setValue(False)
 aLineProjector.execute()
 
 aCircleProjector = aSketchFeature.addFeature("SketchProjection")
 aCircleProjector.selection("ExternalFeature").selectSubShape("EDGE", "Sketch_1/Edge-SketchCircle_1_2")
+aCircleProjector.boolean("IncludeToResult").setValue(False)
 aCircleProjector.execute()
 
 anArcProjector = aSketchFeature.addFeature("SketchProjection")
 anArcProjector.selection("ExternalFeature").selectSubShape("EDGE", "Sketch_1/Edge-SketchArc_1_2")
+anArcProjector.boolean("IncludeToResult").setValue(False)
 anArcProjector.execute()
 aSession.finishOperation()
 assert (model.dof(aSketchFeature) == 0)
diff --git a/src/SketchPlugin/Test/TestProjectionIntoResult.py b/src/SketchPlugin/Test/TestProjectionIntoResult.py
new file mode 100644 (file)
index 0000000..6ec5968
--- /dev/null
@@ -0,0 +1,141 @@
+from salome.shaper import model
+from GeomAPI import *
+
+#==============================================================================
+# Auxiliary functions
+#==============================================================================
+
+# Project all features from 'theProjected' list.
+# Argument 'theFailed' shows indices of projections which should fail because of validator
+def testProjections(theDocument, theSketch, theProjected, theFailed):
+    # generate list of projected features
+    ind = 0
+    edgeProj = set()
+    for type, name in theProjected:
+        proj = theSketch.addProjection(model.selection(type, name), True)
+        assert(bool(proj.feature().error() != '') == bool(ind in theFailed))
+        if proj.feature().error() != '':
+            if proj.createdFeature() is not None:
+                theDocument.removeFeature(proj.createdFeature().feature())
+            theDocument.removeFeature(proj.feature())
+            model.do()
+        elif type == "EDGE":
+            edgeProj.add(proj)
+        ind += 1
+    model.do()
+    model.testNbSubShapes(theSketch, GeomAPI_Shape.EDGE, [len(edgeProj)])
+
+    # exclude some edges from result
+    NB_TO_EXCLUDE = 2
+    num = 0
+    for proj in edgeProj:
+        proj.setIncludeToResult(False)
+        num += 1
+        if num >= NB_TO_EXCLUDE:
+            break
+    model.do()
+    model.testNbSubShapes(theSketch, GeomAPI_Shape.EDGE, [len(edgeProj) - num])
+
+
+#==============================================================================
+# Initial 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(-187.9303398287678, -363.2915373234726, 182.2190183849013)
+SketchArc_1 = Sketch_1.addArc(-229.9631763073051, -65.7360230979784, -105.4201011859997, -97.06956797196608, -326.3502666769664, 19.13032715412109, False)
+SketchLine_1 = Sketch_1.addLine(-438.4308780225287, -71.00741660505224, 161.0737545348623, -582.1237015141244)
+SketchPoint_1 = Sketch_1.addPoint(-446.0706301668712, -312.4620987423343)
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+SketchLine_2 = Sketch_2.addLine(27.19276215608871, 61.51157581079401, 72.96621462024476, 0)
+SketchLine_3 = Sketch_2.addLine(model.selection("EDGE", "PartSet/OZ"))
+SketchLine_4 = Sketch_2.addLine(model.selection("EDGE", "PartSet/OY"))
+SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_4.result())
+SketchLine_5 = Sketch_2.addLine(72.96621462024476, 0, 0, 0)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_3.startPoint(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_2.addLine(0, 0, 0, 61.51157581079401)
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_3.startPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_3.result())
+SketchLine_7 = Sketch_2.addLine(0, 61.51157581079401, 27.19276215608871, 61.51157581079401)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchLine_2.startPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_1 = Sketch_2.setHorizontal(SketchLine_7.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_2r-SketchLine_5r-SketchLine_6r-SketchLine_7r")], model.selection(), 100, 0)
+model.do()
+
+#==============================================================================
+# Tests
+#==============================================================================
+
+aProjectedList = [("EDGE", "Sketch_1/Edge-SketchCircle_1_2"),
+                  ("EDGE", "Sketch_1/Edge-SketchArc_1_2"),
+                  ("EDGE", "Sketch_1/Edge-SketchLine_1"),
+                  ("VERTEX", "Sketch_1/Vertex-SketchPoint_1"),
+                  #
+                  ("VERTEX", "Sketch_1/Vertex-SketchCircle_1"),
+                  ("VERTEX", "Sketch_1/Vertex-SketchLine_1e"),
+                  ("VERTEX", "Sketch_1/Vertex-SketchLine_1s"),
+                  ("VERTEX", "Sketch_1/Vertex-SketchArc_1_2s"),
+                  ("VERTEX", "Sketch_1/Vertex-SketchArc_1_2e"),
+                  ("VERTEX", "Sketch_1/Vertex-SketchArc_1"),
+                  #
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/Generated_Face_2&Extrusion_1_1/From_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/From_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1"),
+                  ("VERTEX", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1"),
+                  #
+                  ("EDGE", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/From_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/From_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/From_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1"),
+                  #
+                  ("EDGE", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/Generated_Face_2"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_1"),
+                  #
+                  ("EDGE", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1"),
+                  ("EDGE", "Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1")
+                  ]
+
+# Test projection to the same plane
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_2"))
+aFailedIDs = set([21, 29])
+testProjections(Part_1_doc, Sketch_3, aProjectedList, aFailedIDs)
+
+# Test projection to parallel plane
+Sketch_4 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_4"))
+testProjections(Part_1_doc, Sketch_4, aProjectedList, aFailedIDs)
+
+# Test projection to lower base of the prism
+Sketch_5 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/From_Face_1"))
+aFailedIDs = set([0, 1, 22, 23, 24, 25])
+testProjections(Part_1_doc, Sketch_5, aProjectedList, aFailedIDs)
+
+# Test projection to upper base of the prism
+Sketch_6 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"))
+testProjections(Part_1_doc, Sketch_6, aProjectedList, aFailedIDs)
+
+# Test projection to orthogonal side face of the prism
+Sketch_7 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_1"))
+aFailedIDs = set([0, 1, 18, 20, 26, 28])
+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_3"))
+aFailedIDs = set([0, 1])
+testProjections(Part_1_doc, Sketch_8, aProjectedList, aFailedIDs)
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestSignedDistancePointLine.py b/src/SketchPlugin/Test/TestSignedDistancePointLine.py
new file mode 100644 (file)
index 0000000..5339a7a
--- /dev/null
@@ -0,0 +1,129 @@
+from salome.shaper import model
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "clearance", "210")
+model.addParameter(Part_1_doc, "wheel_R", "203")
+model.addParameter(Part_1_doc, "arc_R", "wheel_R+70")
+model.addParameter(Part_1_doc, "hood_height", "290")
+HeightParam = model.addParameter(Part_1_doc, "height", "900")
+LengthParam = model.addParameter(Part_1_doc, "length", "1460")
+PosParam = model.addParameter(Part_1_doc, "position", "71.99905090248758")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-281.378739745974, 78.99909999999998, -98.87873974597397, 78.99909999999998)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchArc_1 = Sketch_1.addArc(174.031501908677, 71.9991, -98.87873974597397, 78.99909999999998, 446.941743563328, 78.9991, True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+SketchArc_2 = Sketch_1.addArc(-554.288981400625, 71.9991, -281.378739745974, 78.99909999999998, -827.1992230552759, 78.9991, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchArc_2.results()[1], SketchArc_1.results()[1])
+SketchCircle_1 = Sketch_1.addCircle(-554.288981400625, 71.9991, 203)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.center(), SketchCircle_1.center())
+SketchCircle_2 = Sketch_1.addCircle(174.031501908677, 71.9991, 203)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_1.center(), SketchCircle_2.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "wheel_R")
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+SketchLine_2 = Sketch_1.addLine(-827.1992230552759, 78.9991, -960.4001854579536, 78.9991)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-960.4001854579536, 78.9991, -960.4001854579536, 368.9991)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-891.6236641114499, 437.7756213465037, -540.5628729569305, 437.7756213465037)
+SketchLine_5 = Sketch_1.addLine(-540.5628729569305, 437.7756213465037, -349.330908394406, 768.9991)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-349.330908394406, 768.9991, 308.3678499795216, 768.9991)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(308.3678499795216, 768.9991, 499.5998145420464, 437.7756213465038)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(499.5998145420464, 437.7756213465038, 499.5998145420464, 78.9991)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(499.5998145420464, 78.9991, 446.941743563328, 78.9991)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_9.endPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_5 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_8.result())
+SketchArc_3 = Sketch_1.addArc(-891.6236641114499, 368.9991, -891.6236641114499, 437.7756213465037, -960.4001854579536, 368.9991, False)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchArc_3.startPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_3.endPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_3.result())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_4.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), 120.0000000000006)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_4.result())
+SketchConstraintAngle_2 = Sketch_1.setAngleBackward(SketchLine_7.result(), SketchLine_6.result(), 120.0000000000006)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_2.startPoint(), "arc_R", True)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_2.endPoint(), SketchLine_5.endPoint(), "height-clearance")
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchLine_9.startPoint(), "length", True)
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_2.result(), "hood_height", True)
+SketchLine_10 = Sketch_1.addLine(model.selection("EDGE", "PartSet/OX"))
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchCircle_2.center(), SketchLine_10.result(), "position", True)
+SketchPoint_1 = Sketch_1.addPoint(-910.4001854579535, 347.7756213465037)
+SketchPoint_2 = Sketch_1.addPoint(-910.9041532173604, 297.7781612460398)
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.result(), 50, True)
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_4.result(), 90, True)
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchPoint_1.coordinates(), 50, True)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), "length/8")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchArc_1_2r-SketchArc_2_2r-SketchLine_2r-SketchLine_3r-SketchLine_4r-SketchLine_5r-SketchLine_6r-SketchLine_7r-SketchLine_8r-SketchLine_9r-SketchArc_3_2f")], model.selection(), 500, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 500, -400)
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 100, 0)
+model.do()
+
+# Verify point-line signed distance
+dist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+dist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+dist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+dist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+dist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+
+PosParam.setValue(300)
+model.do()
+curDist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+curDist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+curDist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+curDist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+curDist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+assert(math.fabs(dist3 - curDist3) < TOLERANCE), "Expected {}, actual {}".format(dist3, curDist3)
+assert(math.fabs(dist4 - curDist4) < TOLERANCE), "Expected {}, actual {}".format(dist4, curDist4)
+assert(math.fabs(dist5 - curDist5) < TOLERANCE), "Expected {}, actual {}".format(dist5, curDist5)
+
+LengthParam.setValue(2000)
+model.do()
+curDist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+curDist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+curDist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+curDist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+curDist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+assert(math.fabs(dist3 - curDist3) < TOLERANCE), "Expected {}, actual {}".format(dist3, curDist3)
+assert(math.fabs(dist4 - curDist4) < TOLERANCE), "Expected {}, actual {}".format(dist4, curDist4)
+assert(math.fabs(dist5 - curDist5) < TOLERANCE), "Expected {}, actual {}".format(dist5, curDist5)
+
+HeightParam.setValue(1200)
+model.do()
+curDist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+curDist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+curDist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+curDist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+curDist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+assert(math.fabs(dist3 - curDist3) < TOLERANCE), "Expected {}, actual {}".format(dist3, curDist3)
+assert(math.fabs(dist4 - curDist4) < TOLERANCE), "Expected {}, actual {}".format(dist4, curDist4)
+assert(math.fabs(dist5 - curDist5) < TOLERANCE), "Expected {}, actual {}".format(dist5, curDist5)
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestSignedDistancePointPoint.py b/src/SketchPlugin/Test/TestSignedDistancePointPoint.py
new file mode 100644 (file)
index 0000000..d2bca85
--- /dev/null
@@ -0,0 +1,108 @@
+from salome.shaper import model
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "clearance", "210")
+model.addParameter(Part_1_doc, "wheel_R", "203")
+model.addParameter(Part_1_doc, "arc_R", "wheel_R+70")
+model.addParameter(Part_1_doc, "hood_height", "290")
+HeightParam = model.addParameter(Part_1_doc, "height", "900")
+LengthParam = model.addParameter(Part_1_doc, "length", "1460")
+PosParam = model.addParameter(Part_1_doc, "position", "71.99905090248758")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-281.378739745974, 78.99909999999998, -98.87873974597397, 78.99909999999998)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchArc_1 = Sketch_1.addArc(174.031501908677, 71.9991, -98.87873974597397, 78.99909999999998, 446.941743563328, 78.9991, True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+SketchArc_2 = Sketch_1.addArc(-554.288981400625, 71.9991, -281.378739745974, 78.99909999999998, -827.1992230552759, 78.9991, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchArc_2.results()[1], SketchArc_1.results()[1])
+SketchCircle_1 = Sketch_1.addCircle(-554.288981400625, 71.9991, 203)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.center(), SketchCircle_1.center())
+SketchCircle_2 = Sketch_1.addCircle(174.031501908677, 71.9991, 203)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_1.center(), SketchCircle_2.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "wheel_R")
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+SketchLine_2 = Sketch_1.addLine(-827.1992230552759, 78.9991, -960.4001854579536, 78.9991)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-960.4001854579536, 78.9991, -960.4001854579536, 368.9991)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-891.6236641114499, 437.7756213465037, -540.5628729569305, 437.7756213465037)
+SketchLine_5 = Sketch_1.addLine(-540.5628729569305, 437.7756213465037, -349.330908394406, 768.9991)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-349.330908394406, 768.9991, 308.3678499795216, 768.9991)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(308.3678499795216, 768.9991, 499.5998145420464, 437.7756213465038)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(499.5998145420464, 437.7756213465038, 499.5998145420464, 78.9991)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(499.5998145420464, 78.9991, 446.941743563328, 78.9991)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_9.endPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_5 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_8.result())
+SketchArc_3 = Sketch_1.addArc(-891.6236641114499, 368.9991, -891.6236641114499, 437.7756213465037, -960.4001854579536, 368.9991, False)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchArc_3.startPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_3.endPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_3.result())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_4.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), 120.0000000000006)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_4.result())
+SketchConstraintAngle_2 = Sketch_1.setAngleBackward(SketchLine_7.result(), SketchLine_6.result(), 120.0000000000006)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_2.startPoint(), "arc_R", True)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_2.endPoint(), SketchLine_5.endPoint(), "height-clearance")
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchLine_9.startPoint(), "length", True)
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_2.result(), "hood_height", True)
+SketchLine_10 = Sketch_1.addLine(model.selection("EDGE", "PartSet/OX"))
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchCircle_2.center(), SketchLine_10.result(), "position", True)
+SketchPoint_1 = Sketch_1.addPoint(-910.4001854579535, 347.7756213465037)
+SketchPoint_2 = Sketch_1.addPoint(-910.9041532173604, 297.7781612460398)
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.result(), 50, True)
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_4.result(), 90, True)
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchPoint_1.coordinates(), 50, True)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), "length/8")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchArc_1_2r-SketchArc_2_2r-SketchLine_2r-SketchLine_3r-SketchLine_4r-SketchLine_5r-SketchLine_6r-SketchLine_7r-SketchLine_8r-SketchLine_9r-SketchArc_3_2f")], model.selection(), 500, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 500, -400)
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 100, 0)
+model.do()
+
+# Verify point-point distance
+dist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+dist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+
+PosParam.setValue(300)
+model.do()
+curDist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+curDist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+
+LengthParam.setValue(2000)
+model.do()
+curDist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+curDist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+
+HeightParam.setValue(1200)
+model.do()
+curDist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+curDist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+
+model.end()
diff --git a/src/SketchPlugin/icons/distance_h.png b/src/SketchPlugin/icons/distance_h.png
new file mode 100644 (file)
index 0000000..b88db21
Binary files /dev/null and b/src/SketchPlugin/icons/distance_h.png differ
diff --git a/src/SketchPlugin/icons/distance_v.png b/src/SketchPlugin/icons/distance_v.png
new file mode 100644 (file)
index 0000000..027a384
Binary files /dev/null and b/src/SketchPlugin/icons/distance_v.png differ
diff --git a/src/SketchPlugin/icons/ellipse.png b/src/SketchPlugin/icons/ellipse.png
new file mode 100644 (file)
index 0000000..6f31163
Binary files /dev/null and b/src/SketchPlugin/icons/ellipse.png differ
index aa9fd2ce58e019117922f8ae68027d6d8b8a6c9b..9bc2d8b7280e738f93b2b82159ff54fb3a920c54 100644 (file)
@@ -28,7 +28,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
                 SketchRectangle
                 SketchProjection
-                SketchConstraintLength SketchConstraintRadius SketchConstraintDistance
+                SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
                 SketchConstraintParallel SketchConstraintPerpendicular
                 SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical
                 SketchConstraintEqual SketchConstraintTangent
@@ -359,6 +359,97 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
       </feature>
     </group>
 
+<excluded>
+    <group id="Elliptic geometry">
+      <!-- SketchEllipse is a hidden feature. It is created inside SketchMacroEllipse. -->
+      <feature id="SketchEllipse"
+               title="Ellipse"
+               tooltip="Create ellipse"
+               icon="icons/Sketch/ellipse.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_focus"
+                                 title="Focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <labelvalue id="ellipse_major_radius"
+                    icon="icons/Sketch/radius.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:"
+                    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>
+      <!-- SketchMacroEllipse -->
+      <feature id="SketchMacroEllipse"
+               icon="icons/Sketch/ellipse.png"
+               title="Ellipse"
+               tooltip="Create ellipse">
+        <sketch-2dpoint_selector id="center_point"
+                                 reference_attribute="center_point_ref"
+                                 title="Center point"
+                                 tooltip="Center point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="major_axis_point"
+                                 reference_attribute="major_axis_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">
+<!--          <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:"
+                    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:"
+                    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"
+                   label="Auxiliary"
+                   default="false"
+                   obligatory="0"/>
+      </feature>
+    </group>
+</excluded>
+
     <group id="Projection">
       <!-- Intersection Point -->
       <!-- feature
@@ -388,12 +479,13 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
               id="ExternalFeature"
               label="Edge"
               tooltip="Select external edge."
-              shape_types="edge"
+              shape_types="edge vertex"
               use_external="true"
               can_create_external="false"
               use_sketch_plane="false">
           <validator id="SketchPlugin_ProjectionValidator"/>
         </sketch_shape_selector>
+        <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"/>
         <validator id="PartSet_ProjectionSelection"/>
       </feature>
     </group>
@@ -564,10 +656,75 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
           <validator id="GeomValidators_Positive"/>
         </doublevalue_editor>
 
+        <boolvalue id="SignedDistance" label="Keep orientation" default="true" tooltip="Keep distance orientation" obligatory="0"/>
+        <validator id="PartSet_DistanceSelection"/>
+      </feature>
+
+      <!--  SketchConstraintDistanceHorizontal  -->
+      <feature
+        id="SketchConstraintDistanceHorizontal"
+        title="Horizontal Distance"
+        tooltip="Set horizontal distance between two points"
+        icon="icons/Sketch/distance_h.png">
+        <label title="Select points for distance definition."/>
+        <sketch_shape_selector
+              id="ConstraintEntityA"
+              label="First point"
+              tooltip="Select point."
+              shape_types="vertex">
+          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+          <validator id="PartSet_DifferentObjects"/>
+          <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+        </sketch_shape_selector>
+        <sketch_shape_selector
+          id="ConstraintEntityB"
+          label="Second point"
+          tooltip="Select point."
+          shape_types="vertex">
+          <validator id="PartSet_DifferentObjects"/>
+          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+          <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+        </sketch_shape_selector>
+        <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
+
+        <doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed"/>
+
+        <validator id="PartSet_DistanceSelection"/>
+      </feature>
+
+      <!--  SketchConstraintDistanceVertical  -->
+      <feature
+        id="SketchConstraintDistanceVertical"
+        title="Vertical Distance"
+        tooltip="Set vertical distance between two points"
+        icon="icons/Sketch/distance_v.png">
+        <label title="Select points for distance definition."/>
+        <sketch_shape_selector
+              id="ConstraintEntityA"
+              label="First point"
+              tooltip="Select point."
+              shape_types="vertex">
+          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+          <validator id="PartSet_DifferentObjects"/>
+          <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+        </sketch_shape_selector>
+        <sketch_shape_selector
+          id="ConstraintEntityB"
+          label="Second point"
+          tooltip="Select point."
+          shape_types="vertex">
+          <validator id="PartSet_DifferentObjects"/>
+          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+          <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+        </sketch_shape_selector>
+        <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
+
+        <doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed"/>
+
         <validator id="PartSet_DistanceSelection"/>
       </feature>
 
-    <!--  SketchConstraintLength  -->
+      <!--  SketchConstraintLength  -->
       <feature id="SketchConstraintLength" title="Length" tooltip="Set fixed length of a line segment" icon="icons/Sketch/length.png">
         <label title="Select a line on which to calculate length" tooltip="Select a line on which to calculate length"/>
         <shape_selector id="ConstraintEntityA" label="Line" tooltip="Select a line" shape_types="edge" >
@@ -629,6 +786,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
         <sketch_shape_selector id="ConstraintEntityA"
             label="Line" tooltip="Select a line" shape_types="edge" use_external="false">
           <validator id="GeomValidators_ShapeType" parameters="line"/>
+          <validator id="SketchPlugin_HasNoConstraint" parameters="SketchConstraintHorizontal, SketchConstraintVertical"/>
         </sketch_shape_selector>
         <validator id="PartSet_HVDirSelection"/>
       </feature>
@@ -638,6 +796,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
         <sketch_shape_selector id="ConstraintEntityA"
             label="Line" tooltip="Select a line" shape_types="edge" use_external="false">
           <validator id="GeomValidators_ShapeType" parameters="line"/>
+          <validator id="SketchPlugin_HasNoConstraint" parameters="SketchConstraintHorizontal, SketchConstraintVertical"/>
         </sketch_shape_selector>
         <validator id="PartSet_HVDirSelection"/>
       </feature>
index 50c4fab20984fd6f7618c88917ae74472182d5a7..5dab71a4f86d93d4dd22b49ce7b8e601995e3f04 100644 (file)
@@ -55,6 +55,7 @@ SET(SKETCHSOLVER_CONSTRAINT_HEADERS
     SketchSolver_ConstraintMulti.h
     SketchSolver_ConstraintMultiRotation.h
     SketchSolver_ConstraintMultiTranslation.h
+    SketchSolver_ConstraintMovement.h
 )
 
 SET(SKETCHSOLVER_SOURCES
@@ -78,6 +79,7 @@ SET(SKETCHSOLVER_CONSTRAINT_SOURCES
     SketchSolver_ConstraintMulti.cpp
     SketchSolver_ConstraintMultiRotation.cpp
     SketchSolver_ConstraintMultiTranslation.cpp
+    SketchSolver_ConstraintMovement.cpp
 )
 
 SET(SKETCHSOLVER_LIBRARIES
index 081f3425c55397d70cd94d9b5470db542acafdd0..722d0ed24b14dec4cbaaf91d8e78323d1aaefab7 100644 (file)
@@ -112,6 +112,10 @@ SET(PROJECT_SOURCES
     ${SKETCHSOLVER_CONSTRAINT_SOURCES}
 )
 
+if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
+  ADD_DEFINITIONS(-DCHANGE_RADIUS_WHILE_MOVE)
+endif()
+
 ADD_LIBRARY(PlaneGCSSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${SKETCHSOLVER_TEXT_RESOURCES})
 TARGET_LINK_LIBRARIES(PlaneGCSSolver ${PROJECT_LIBRARIES} ${SKETCHSOLVER_LIBRARIES})
 INSTALL(TARGETS PlaneGCSSolver DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES})
index 981769fc20bb5bd31023c78f741738b0769a2124..0f31d2e2c7de02d706d70b2bd5273a063c2a7a36 100644 (file)
@@ -40,6 +40,7 @@ typedef int ConstraintID;
 // Predefined values for identifiers
 const ConstraintID CID_UNKNOWN  =  0;
 const ConstraintID CID_MOVEMENT = -1;
+const ConstraintID CID_FICTIVE = 1024;
 
 /// Types of entities
 enum SketchSolver_EntityType {
@@ -63,6 +64,8 @@ enum SketchSolver_ConstraintType {
   CONSTRAINT_DISTANCE,         // base distance if we don't know the measured objects yet
   CONSTRAINT_PT_PT_DISTANCE,
   CONSTRAINT_PT_LINE_DISTANCE,
+  CONSTRAINT_HORIZONTAL_DISTANCE,
+  CONSTRAINT_VERTICAL_DISTANCE,
   CONSTRAINT_RADIUS,
   CONSTRAINT_ANGLE,
   CONSTRAINT_FIXED,
index 38b60f7fef31009e8b4725e8c251fb53af5c7466..75919af5f55a50f941f15f9e7d1ad41bf7253261 100644 (file)
@@ -27,7 +27,8 @@ PlaneGCSSolver_Solver::PlaneGCSSolver_Solver()
     myDiagnoseBeforeSolve(false),
     myInitilized(false),
     myConfCollected(false),
-    myDOF(0)
+    myDOF(0),
+    myFictiveConstraint(0)
 {
 }
 
@@ -43,6 +44,8 @@ void PlaneGCSSolver_Solver::clear()
   myConstraints.clear();
   myConflictingIDs.clear();
   myDOF = 0;
+
+  removeFictiveConstraint();
 }
 
 void PlaneGCSSolver_Solver::addConstraint(GCSConstraintPtr theConstraint)
@@ -109,6 +112,7 @@ void PlaneGCSSolver_Solver::removeParameters(const GCS::SET_pD& theParams)
 void PlaneGCSSolver_Solver::initialize()
 {
   Events_LongOp::start(this);
+  addFictiveConstraintIfNecessary();
   if (myDiagnoseBeforeSolve)
     diagnose();
   myEquationSystem->declareUnknowns(myParameters);
@@ -134,6 +138,8 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
   if (myInitilized) {
     aResult = (GCS::SolveStatus)myEquationSystem->solve();
   } else {
+    addFictiveConstraintIfNecessary();
+
     if (myDiagnoseBeforeSolve)
       diagnose();
     aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters);
@@ -146,6 +152,30 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
   collectConflicting();
   if (!myConflictingIDs.empty())
     aResult = GCS::Failed;
+  else if (aResult == GCS::Failed) {
+    // DogLeg solver failed without conflicting constraints, try to use Levenberg-Marquardt solver
+    // if there are point-line distance constraints
+    ConstraintMap::iterator aCIt = myConstraints.begin();
+    for (; aCIt != myConstraints.end(); ++aCIt) {
+      if (aCIt->second.size() <= 1)
+        continue;
+      std::set<GCSConstraintPtr>::const_iterator anIt = aCIt->second.begin();
+      for (; anIt != aCIt->second.end(); ++anIt)
+        if ((*anIt)->getTypeId() == GCS::P2LDistance)
+          break;
+      if (anIt != aCIt->second.end())
+        break;
+    }
+
+    if (aCIt != myConstraints.end()) {
+      aResult = (GCS::SolveStatus)myEquationSystem->solve(
+          myParameters, true, GCS::LevenbergMarquardt);
+      myConfCollected = false;
+      collectConflicting();
+      if (!myConflictingIDs.empty())
+        aResult = GCS::Failed;
+    }
+  }
 
   SolveStatus aStatus;
   if (aResult == GCS::Failed)
@@ -157,6 +187,7 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
     aStatus = STATUS_OK;
   }
 
+  removeFictiveConstraint();
   myInitilized = false;
   return aStatus;
 }
@@ -198,3 +229,34 @@ void PlaneGCSSolver_Solver::diagnose()
   myDOF = myEquationSystem->diagnose();
   myDiagnoseBeforeSolve = false;
 }
+
+void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
+{
+  if (!myConstraints.empty() &&
+      myConstraints.find(CID_MOVEMENT) == myConstraints.end())
+    return;
+
+  if (myFictiveConstraint)
+    return; // no need several fictive constraints
+
+  double* aParam = createParameter();
+  double* aFictiveParameter = new double(0.0);
+
+  myFictiveConstraint = new GCS::ConstraintEqual(aFictiveParameter, aParam);
+  myFictiveConstraint->setTag(CID_FICTIVE);
+  myEquationSystem->addConstraint(myFictiveConstraint);
+}
+
+void PlaneGCSSolver_Solver::removeFictiveConstraint()
+{
+  if (myFictiveConstraint) {
+    myEquationSystem->removeConstraint(myFictiveConstraint);
+    myParameters.pop_back();
+
+    GCS::VEC_pD aParams = myFictiveConstraint->params();
+    for (GCS::VEC_pD::iterator anIt = aParams.begin(); anIt != aParams.end(); ++ anIt)
+      delete *anIt;
+    delete myFictiveConstraint;
+    myFictiveConstraint = 0;
+  }
+}
index 2e49798a1c90b052a563a735d35c8cfe921f57f1..572f2df25ecce3fd5dd38b47e2d6a401c9ebc45f 100644 (file)
@@ -81,6 +81,11 @@ public:
 private:
   void collectConflicting();
 
+  /// \brief Add fictive constraint if the sketch contains temporary constraints only
+  void addFictiveConstraintIfNecessary();
+  /// \brief Remove previously added fictive constraint
+  void removeFictiveConstraint();
+
 private:
   typedef std::map<ConstraintID, std::set<GCSConstraintPtr> > ConstraintMap;
 
@@ -96,6 +101,8 @@ private:
   bool                         myConfCollected;
 
   int                          myDOF;            ///< degrees of freedom
+
+  GCS::Constraint*             myFictiveConstraint;
 };
 
 typedef std::shared_ptr<PlaneGCSSolver_Solver> SolverPtr;
index 56567d292dfbb4a444b6c7c2f3d0349a3cdeafc0..16122052155c527b9c72a2177db06753c79a556c 100644 (file)
@@ -66,12 +66,9 @@ void PlaneGCSSolver_Storage::addConstraint(
   constraintsToSolver(theSolverConstraint, mySketchSolver);
 }
 
-void PlaneGCSSolver_Storage::addTemporaryConstraint(
+void PlaneGCSSolver_Storage::addMovementConstraint(
     const ConstraintWrapperPtr& theSolverConstraint)
 {
-  if (myConstraintMap.empty())
-    return; // no need to process temporary constraints if there is no active constraint
-
   // before adding movement constraint to solver, re-check its DOF
   if (mySketchSolver->dof() == 0)
     mySketchSolver->diagnose();
index 28eaed091781ecfedfcb86e64ba02d9827b82c8d..48526b9c734cd83d524f8b790a35c0a981061680 100644 (file)
@@ -44,10 +44,10 @@ public:
   virtual void addConstraint(ConstraintPtr        theConstraint,
                              ConstraintWrapperPtr theSolverConstraint);
 
-  /// \brief Add list of temporary constraints which will be destroyed
+  /// \brief Add a movement constraint which will be destroyed
   ///        after the next solving of the set of constraints.
   /// \param theSolverConstraint [in]  solver's constraint
-  virtual void addTemporaryConstraint(const ConstraintWrapperPtr& theSolverConstraint);
+  virtual void addMovementConstraint(const ConstraintWrapperPtr& theSolverConstraint);
 
 
   /// \brief Convert feature to the form applicable for specific solver and map it
index 51460d9af8bf662181de4d1825cb2c8a7b6acee3..a4e461ada6afe7a04c830f84d2eedcdf19a214eb 100644 (file)
@@ -42,6 +42,8 @@
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMiddle.h>
@@ -76,6 +78,11 @@ static ConstraintWrapperPtr
   createConstraintDistancePointLine(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
                                     std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint,
                                     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintHVDistance(const SketchSolver_ConstraintType& theType,
+                             std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
+                             std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+                             std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2);
 static ConstraintWrapperPtr
   createConstraintRadius(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
                          std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
@@ -118,7 +125,9 @@ SolverConstraintPtr PlaneGCSSolver_Tools::createConstraint(ConstraintPtr theCons
     return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintCollinear(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID() ||
+             theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+             theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
@@ -143,11 +152,18 @@ SolverConstraintPtr PlaneGCSSolver_Tools::createConstraint(ConstraintPtr theCons
   return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint));
 }
 
-std::shared_ptr<SketchSolver_ConstraintFixed> PlaneGCSSolver_Tools::createMovementConstraint(
+std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMovementConstraint(
     FeaturePtr theMovedFeature)
 {
-  return std::shared_ptr<SketchSolver_ConstraintFixed>(
-      new SketchSolver_ConstraintFixed(theMovedFeature));
+  return std::shared_ptr<SketchSolver_ConstraintMovement>(
+      new SketchSolver_ConstraintMovement(theMovedFeature));
+}
+
+std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMovementConstraint(
+    AttributePtr theMovedAttribute)
+{
+  return std::shared_ptr<SketchSolver_ConstraintMovement>(
+      new SketchSolver_ConstraintMovement(theMovedAttribute));
 }
 
 
@@ -186,6 +202,10 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
                                                 aPoint1,
                                                 GCS_EDGE_WRAPPER(theEntity1));
     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));
@@ -379,6 +399,32 @@ ConstraintWrapperPtr createConstraintDistancePointLine(
   return aResult;
 }
 
+ConstraintWrapperPtr createConstraintHVDistance(
+    const SketchSolver_ConstraintType& theType,
+    std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2)
+{
+  GCSPointPtr aPoint1 = thePoint1->point();
+  GCSPointPtr aPoint2 = thePoint2->point();
+
+  double *aParam1, *aParam2;
+  if (theType == CONSTRAINT_HORIZONTAL_DISTANCE) {
+    aParam1 = aPoint1->x;
+    aParam2 = aPoint2->x;
+  } else if (theType == CONSTRAINT_VERTICAL_DISTANCE) {
+    aParam1 = aPoint1->y;
+    aParam2 = aPoint2->y;
+  }
+
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintDifference(aParam1, aParam2, theValue->scalar()));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType));
+  aResult->setValueParameter(theValue);
+  return aResult;
+}
+
 ConstraintWrapperPtr createConstraintRadius(
     std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
index e06acb15923efe5dbb251b1a576ac0443a7144d8..69cc966803ecd95cb9b401e6a815ece98358aaf4 100644 (file)
@@ -22,7 +22,7 @@
 #define PlaneGCSSolver_Tools_H_
 
 #include <SketchSolver_Constraint.h>
-#include <SketchSolver_ConstraintFixed.h>
+#include <SketchSolver_ConstraintMovement.h>
 #include <SketchPlugin_Constraint.h>
 
 #include <GeomAPI_Lin2d.h>
@@ -39,8 +39,11 @@ namespace PlaneGCSSolver_Tools
   SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
 
   /// \brief Creates temporary constraint to fix the feature after movement
-  std::shared_ptr<SketchSolver_ConstraintFixed>
+  std::shared_ptr<SketchSolver_ConstraintMovement>
       createMovementConstraint(FeaturePtr theMovedFeature);
+  /// \brief Creates temporary constraint to fix the attribute after movement
+  std::shared_ptr<SketchSolver_ConstraintMovement>
+      createMovementConstraint(AttributePtr theMovedAttribute);
 
   /// \brief Creates new constraint using given parameters
   /// \param theConstraint [in]  original constraint
index f0e6365ccb029128e38035e37dfb8519ade143a7..4a78cc548d772a7ea1c7bde38680abc5018b83cd 100644 (file)
@@ -134,6 +134,10 @@ void SketchSolver_Constraint::process()
   ConstraintWrapperPtr aNewConstraint = PlaneGCSSolver_Tools::createConstraint(
       myBaseConstraint, aConstrType,
       aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+  if (!aNewConstraint) {
+    myErrorMsg = SketchSolver_Error::WRONG_CONSTRAINT_TYPE();
+    return;
+  }
   myStorage->addConstraint(myBaseConstraint, aNewConstraint);
 
   adjustConstraint();
index 3a6a0fa48b7d4080b42927d911fda6bfb634f3d7..4aa15648da14c82c36c8e290a0d591224c0b5f60 100644 (file)
 #include <SketchSolver_Error.h>
 #include <SketchSolver_Manager.h>
 
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
+
 #include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Lin2d.h>
 #include <GeomAPI_Pnt2d.h>
@@ -40,9 +48,14 @@ void SketchSolver_ConstraintDistance::getAttributes(
     return;
   }
 
-  if (theAttributes[1])
-    myType = CONSTRAINT_PT_PT_DISTANCE;
-  else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
+  if (theAttributes[1]) {
+    if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
+      myType = CONSTRAINT_HORIZONTAL_DISTANCE;
+    else if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+      myType = CONSTRAINT_VERTICAL_DISTANCE;
+    else
+      myType = CONSTRAINT_PT_PT_DISTANCE;
+  } else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
     myType = CONSTRAINT_PT_LINE_DISTANCE;
   else
     theAttributes.clear();
@@ -52,53 +65,18 @@ void SketchSolver_ConstraintDistance::getAttributes(
 
 void SketchSolver_ConstraintDistance::adjustConstraint()
 {
-  ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint);
+  if (getType() == CONSTRAINT_PT_LINE_DISTANCE) {
+    bool isSigned = myBaseConstraint->boolean(SketchPlugin_ConstraintDistance::SIGNED())->value();
+    if (myIsSigned == isSigned)
+      return; // distance type is not changed => nothing to adjust
 
-  // Adjust point-point distance if the points are equal
-  if (getType() == CONSTRAINT_PT_PT_DISTANCE) {
-////    AttributePtr aPt1 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A());
-////    AttributePtr aPt2 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B());
-////
-////    BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
-////    std::shared_ptr<GeomAPI_Pnt2d> aPoint1 = aBuilder->point(myStorage->entity(aPt1));
-////    EntityWrapperPtr anEntity2 = myStorage->entity(aPt2);
-////    std::shared_ptr<GeomAPI_Pnt2d> aPoint2 = aBuilder->point(anEntity2);
-////
-////////    if (aPoint1->distance(aPoint2) < tolerance) {
-////////      // Change X coordinate of second point to eliminate coincidence
-////////      ParameterWrapperPtr aX = aSubs.back()->parameters().front();
-////////      aX->setValue(aX->value() + 1.0);
-////////      myStorage->update(aX);
-////////    }
-    return;
-  }
-
-  // Adjust point-line distance
-  if (fabs(myPrevValue) == fabs(aConstraint->value())) {
-    // sign of distance is not changed
-////    aConstraint->setValue(myPrevValue);
-////    myStorage->addConstraint(myBaseConstraint, aConstraint);
-    return;
+    // Adjust point-line distance by setting/removing additional constraints
+    if (isSigned)
+      addConstraintsToKeepSign();
+    else
+      removeConstraintsKeepingSign();
+    myIsSigned = isSigned;
   }
-
-////  // Adjust the sign of constraint value
-////  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
-////
-////  std::shared_ptr<GeomAPI_Lin2d> aLine;
-////  std::shared_ptr<GeomAPI_Pnt2d> aPoint;
-////  for (int i = 0; i < 2; ++i) {
-////    AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i));
-////    EntityWrapperPtr anEntity = myStorage->entity(anAttr);
-////    if (anEntity->type() == ENTITY_POINT)
-////      aPoint = aBuilder->point(anEntity);
-////    else if (anEntity->type() == ENTITY_LINE)
-////      aLine = aBuilder->line(anEntity);
-////  }
-////
-////  std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
-////  std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
-////  if (aLineVec->cross(aPtLineVec) * aConstraint->value() < 0.0)
-////    aConstraint->setValue(aConstraint->value() * (-1.0));
 }
 
 void SketchSolver_ConstraintDistance::update()
@@ -108,3 +86,80 @@ void SketchSolver_ConstraintDistance::update()
 
   SketchSolver_Constraint::update();
 }
+
+void SketchSolver_ConstraintDistance::addConstraintsToKeepSign()
+{
+  std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+  ConstraintWrapperPtr aConstraint = aStorage->constraint(myBaseConstraint);
+  std::list<GCSConstraintPtr> aGCSConstraints = aConstraint->constraints();
+
+  // calculate projection of the point on the line and find a sign of a distance
+  EntityWrapperPtr aDistPoint, aDistLine;
+  for (int i = 0; i < 2; ++i) {
+    AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i));
+    EntityWrapperPtr anEntity = myStorage->entity(anAttr);
+    if (anEntity->type() == ENTITY_POINT)
+      aDistPoint = anEntity;
+    else if (anEntity->type() == ENTITY_LINE)
+      aDistLine = anEntity;
+  }
+  std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aDistLine);
+  std::shared_ptr<GeomAPI_Pnt2d> aPoint = PlaneGCSSolver_Tools::point(aDistPoint);
+
+  std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
+  std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
+  if (aLineVec->cross(aPtLineVec) >= 0.)
+    mySignValue = PI/2.0;
+  else
+    mySignValue = - PI/2.0;
+  double aDot = aPtLineVec->dot(aLineVec);
+  std::shared_ptr<GeomAPI_XY> aProjectedPnt =
+      aLine->location()->xy()->added(aLineVec->multiplied(aDot));
+
+  // create auxiliary point on the line and set auxiliary constraints
+  myOddPoint = GCSPointPtr(new GCS::Point);
+  myOddPoint->x = aStorage->createParameter();
+  myOddPoint->y = aStorage->createParameter();
+  *(myOddPoint->x) = aProjectedPnt->x();
+  *(myOddPoint->y) = aProjectedPnt->y();
+
+  PointWrapperPtr aPointWr = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aDistPoint);
+  EdgeWrapperPtr anEdgeWr = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aDistLine);
+  std::shared_ptr<GCS::Line> aGCSLine = std::dynamic_pointer_cast<GCS::Line>(anEdgeWr->entity());
+  // point-on-line
+  GCSConstraintPtr aNewConstraint(new GCS::ConstraintPointOnLine(*myOddPoint, *aGCSLine));
+  aGCSConstraints.push_back(aNewConstraint);
+  // angle which keep orientation
+  aNewConstraint = GCSConstraintPtr(new GCS::ConstraintL2LAngle(
+      aGCSLine->p1, aGCSLine->p2, *myOddPoint, *(aPointWr->point()), &mySignValue));
+  aGCSConstraints.push_back(aNewConstraint);
+
+  aConstraint->setConstraints(aGCSConstraints);
+
+  aStorage->removeConstraint(myBaseConstraint);
+  aStorage->addConstraint(myBaseConstraint, aConstraint);
+}
+
+void SketchSolver_ConstraintDistance::removeConstraintsKeepingSign()
+{
+  std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+  ConstraintWrapperPtr aConstraint = aStorage->constraint(myBaseConstraint);
+  std::list<GCSConstraintPtr> aGCSConstraints = aConstraint->constraints();
+
+  aStorage->removeConstraint(myBaseConstraint);
+
+  // remove parameters related to auxiliary point
+  GCS::SET_pD aParams;
+  aParams.insert(myOddPoint->x);
+  aParams.insert(myOddPoint->y);
+  aStorage->removeParameters(aParams);
+
+  aGCSConstraints.pop_back();
+  aGCSConstraints.pop_back();
+  aConstraint->setConstraints(aGCSConstraints);
+  aStorage->addConstraint(myBaseConstraint, aConstraint);
+}
index ec7cbd3b6cd3a8db2c75e22c87ed02d856b8388e..b11ab1ea317c36e45156392a3de5870847ea3b3b 100644 (file)
@@ -33,7 +33,8 @@ public:
   /// Constructor based on SketchPlugin constraint
   SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
       SketchSolver_Constraint(theConstraint),
-      myIsNegative(false)
+      myIsSigned(false),
+      mySignValue(0.0)
   {}
 
   /// \brief Update constraint
@@ -51,10 +52,14 @@ protected:
   virtual void adjustConstraint();
 
 private:
-  double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign)
+  void addConstraintsToKeepSign();
+  void removeConstraintsKeepingSign();
 
-  /// \c true, if the point if placed rightside of line direction (SLVS_C_PT_LINE_DISTANCE only)
-  bool myIsNegative;
+private:
+  double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign)
+  bool   myIsSigned;  ///< true if the sign of point-line distance should be kept everytime
+  GCSPointPtr myOddPoint; ///< auxiliary point to keep sign of distance
+  double mySignValue;
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp
new file mode 100644 (file)
index 0000000..f5d6df0
--- /dev/null
@@ -0,0 +1,225 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <SketchSolver_ConstraintMovement.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
+
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+
+SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature)
+  : SketchSolver_ConstraintFixed(ConstraintPtr()),
+    myMovedFeature(theFeature),
+    mySimpleMove(true)
+{
+}
+
+SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr thePoint)
+  : SketchSolver_ConstraintFixed(ConstraintPtr()),
+    myDraggedPoint(thePoint),
+    mySimpleMove(true)
+{
+  myMovedFeature = ModelAPI_Feature::feature(thePoint->owner());
+}
+
+void SketchSolver_ConstraintMovement::blockEvents(bool isBlocked)
+{
+  if (myMovedFeature)
+    myMovedFeature->data()->blockSendAttributeUpdated(isBlocked);
+}
+
+void SketchSolver_ConstraintMovement::process()
+{
+  cleanErrorMsg();
+  if (!myMovedFeature || !myStorage) {
+    // Not enough parameters are initialized
+    return;
+  }
+
+  mySolverConstraint = initMovement();
+  if (!myErrorMsg.empty() || !mySolverConstraint) {
+    // Nothing to move, clear the feature to avoid changing its group
+    // after removing the Movement constraint.
+    myMovedFeature = FeaturePtr();
+    return;
+  }
+  myStorage->addMovementConstraint(mySolverConstraint);
+}
+
+
+static bool isSimpleMove(FeaturePtr theMovedFeature, AttributePtr theDraggedPoint)
+{
+  bool isSimple = true;
+#ifdef CHANGE_RADIUS_WHILE_MOVE
+  if (theMovedFeature->getKind() == SketchPlugin_Circle::ID())
+    isSimple = (theDraggedPoint.get() != 0);
+  else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID()) {
+    isSimple = (theDraggedPoint.get() != 0 &&
+                theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID());
+  }
+#endif
+  return isSimple;
+}
+
+ConstraintWrapperPtr SketchSolver_ConstraintMovement::initMovement()
+{
+  ConstraintWrapperPtr aConstraint;
+
+  // if the feature is copy, do not move it
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(myMovedFeature);
+  if (!aSketchFeature || aSketchFeature->isCopy()) {
+    myStorage->setNeedToResolve(true);
+    return aConstraint;
+  }
+
+  EntityWrapperPtr anEntity =
+      myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+  if (!anEntity) {
+    myStorage->update(myMovedFeature, true);
+    anEntity =
+        myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+    if (!anEntity)
+      return aConstraint;
+  }
+
+  mySimpleMove = isSimpleMove(myMovedFeature, myDraggedPoint);
+
+  if (mySimpleMove)
+    aConstraint = fixFeature(anEntity);
+  else {
+    if (myDraggedPoint) // start or end point of arc has been moved
+      aConstraint = fixArcExtremity(anEntity);
+    else // arc or circle has been moved
+      aConstraint = fixPointOnCircle(anEntity);
+  }
+
+  return aConstraint;
+}
+
+ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixArcExtremity(
+    const EntityWrapperPtr& theArcExtremity)
+{
+  static const int nbParams = 4;
+  myFixedValues.reserve(nbParams); // moved point and center of arc
+
+  EdgeWrapperPtr aCircularEntity = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+      myStorage->entity(myMovedFeature));
+  std::shared_ptr<GCS::Arc> anArc =
+      std::dynamic_pointer_cast<GCS::Arc>(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 };
+
+  std::list<GCSConstraintPtr> aConstraints;
+  for (int i = 0; i < nbParams; ++i) {
+    myFixedValues.push_back(*aParams[i]);
+    GCSConstraintPtr aNewConstraint(new GCS::ConstraintEqual(&myFixedValues[i], aParams[i]));
+    aNewConstraint->rescale(0.01);
+    aConstraints.push_back(aNewConstraint);
+  }
+
+  return ConstraintWrapperPtr(
+      new PlaneGCSSolver_ConstraintWrapper(aConstraints, getType()));
+}
+
+ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnCircle(
+    const EntityWrapperPtr& theCircular)
+{
+  static const double scale = 0.01;
+  static const int nbParams = 4;
+  myFixedValues.reserve(nbParams); // moved point and center of arc/circle
+
+  EdgeWrapperPtr aCircularEntity =
+      std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCircular);
+  std::shared_ptr<GCS::Circle> aCircular =
+      std::dynamic_pointer_cast<GCS::Circle>(aCircularEntity->entity());
+
+  // initialize fixed values
+  myFixedValues.push_back(*aCircular->center.x + *aCircular->rad);
+  myFixedValues.push_back(*aCircular->center.y);
+  myFixedValues.push_back(*aCircular->center.x);
+  myFixedValues.push_back(*aCircular->center.y);
+
+  // create a moved point
+  GCS::Point aPointOnCircle;
+  aPointOnCircle.x = &myFixedValues[0];
+  aPointOnCircle.y = &myFixedValues[1];
+
+  std::list<GCSConstraintPtr> aConstraints;
+  // point-on-circle
+  GCSConstraintPtr aNewConstraint(
+      new GCS::ConstraintP2PDistance(aPointOnCircle, aCircular->center, aCircular->rad));
+  aNewConstraint->rescale(scale);
+  aConstraints.push_back(aNewConstraint);
+  // fixed center (x)
+  aNewConstraint = GCSConstraintPtr(
+      new GCS::ConstraintEqual(&myFixedValues[2], aCircular->center.x));
+  aNewConstraint->rescale(scale);
+  aConstraints.push_back(aNewConstraint);
+  // fixed center (y)
+  aNewConstraint = GCSConstraintPtr(
+      new GCS::ConstraintEqual(&myFixedValues[3], aCircular->center.y));
+  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)
+{
+  myStartPoint = theStartPoint;
+  if (!mySimpleMove) {
+    myFixedValues[0] = myStartPoint->x();
+    myFixedValues[1] = myStartPoint->y();
+  }
+}
+
+void SketchSolver_ConstraintMovement::moveTo(
+    const std::shared_ptr<GeomAPI_Pnt2d>& theDestinationPoint)
+{
+  double aDelta[2] = { theDestinationPoint->x() - myStartPoint->x(),
+                       theDestinationPoint->y() - myStartPoint->y() };
+
+#ifdef CHANGE_RADIUS_WHILE_MOVE
+  int aMaxSize = mySimpleMove ? (int)myFixedValues.size() : 2;
+#else
+  int aMaxSize = myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedPoint ? 4 : 2;
+#endif
+  for (int i = 0; i < aMaxSize; ++i)
+    myFixedValues[i] += aDelta[i % 2];
+}
diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.h b/src/SketchSolver/SketchSolver_ConstraintMovement.h
new file mode 100644 (file)
index 0000000..8614f30
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (C) 2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+// File:    SketchSolver_ConstraintMovement.h
+// Created: 15 Jun 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintMovement_H_
+#define SketchSolver_ConstraintMovement_H_
+
+#include <SketchSolver_ConstraintFixed.h>
+
+class GeomAPI_Pnt2d;
+
+/** \class   SketchSolver_ConstraintMovement
+ *  \ingroup Plugins
+ *  \brief   Stores data to the Fixed constraint for the moved feature only
+ */
+class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintFixed
+{
+public:
+  /// Creates movement constraint based on feature
+  SketchSolver_ConstraintMovement(FeaturePtr theFeature);
+
+  /// Creates movement constraint based on point
+  SketchSolver_ConstraintMovement(AttributePtr thePoint);
+
+  /// \brief Set coordinates of the start point of the movement
+  void startPoint(const std::shared_ptr<GeomAPI_Pnt2d>& theStartPoint);
+
+  /// \brief Set coordinates of fixed feature to the values where it has been dragged.
+  ///        Useful when the feature is being moved.
+  void moveTo(const std::shared_ptr<GeomAPI_Pnt2d>& theDestinationPoint);
+
+  /// \brief Block or unblock events from this constraint
+  virtual void blockEvents(bool isBlocked);
+
+  /// \brief Returns moved feature
+  FeaturePtr movedFeature() const
+  { return myMovedFeature; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Create Fixed constraint for the feature basing on its type and moved point
+  /// \return Fixed constraint
+  ConstraintWrapperPtr initMovement();
+
+  /// \brief Create constraint to fix moved arc extremity
+  ConstraintWrapperPtr fixArcExtremity(const EntityWrapperPtr& theArcExtremity);
+
+  /// \brief Creat constraint to fix moved point on circle/arc
+  ConstraintWrapperPtr fixPointOnCircle(const EntityWrapperPtr& theCircular);
+
+private:
+  FeaturePtr       myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL)
+  AttributePtr     myDraggedPoint; ///< one of the feature points which has been moved
+  std::shared_ptr<GeomAPI_Pnt2d> myStartPoint; ///< start point of the movement
+
+  bool mySimpleMove; ///< simple move, thus all parameters should be increased by movement delta
+};
+
+#endif
index 4b4347f364de9bb44e3126b8abd90088fe296134..3093e7bc9ac20f73330e224af1021104ef8d2178 100644 (file)
@@ -103,6 +103,12 @@ class SketchSolver_Error
     static const std::string MY_ERROR_VALUE("Caution: SolveSpace crash! Constraints are wrong");
     return MY_ERROR_VALUE;
   }
+  /// Constraint has wrong type
+  inline static const std::string& WRONG_CONSTRAINT_TYPE()
+  {
+    static const std::string MY_ERROR_VALUE("Unsupported type of constraint");
+    return MY_ERROR_VALUE;
+  }
 };
 
 #endif
index f437103ac38527035421f86396b2fe5c6c0d26fd..93bbfa69d406369bea25307cbe7a7ea0eb3d498e 100644 (file)
@@ -70,7 +70,7 @@ static void sendMessage(const char* theMessageName,
 
 
 // ========================================================
-// =========  SketchSolver_Group  ===============
+// =========       SketchSolver_Group       ===============
 // ========================================================
 
 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
@@ -129,32 +129,56 @@ bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
   return myStorage->update(theFeature);
 }
 
-bool SketchSolver_Group::moveFeature(FeaturePtr theFeature)
+template <class Type>
+static SolverConstraintPtr move(StoragePtr theStorage,
+                                SolverPtr theSketchSolver,
+                                int theSketchDOF,
+                                bool theEventsBlocked,
+                                Type theFeatureOrPoint,
+                                const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+                                const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
 {
-  bool isFeatureExists = (myStorage->entity(theFeature).get() != 0);
-  if (myDOF == 0 && isFeatureExists) {
+  bool isEntityExists = (theStorage->entity(theFeatureOrPoint).get() != 0);
+  if (theSketchDOF == 0 && isEntityExists) {
     // avoid moving elements of fully constrained sketch
-    myStorage->refresh();
-    return true;
+    theStorage->refresh();
+    return SolverConstraintPtr();
   }
 
   // Create temporary Fixed constraint
-  std::shared_ptr<SketchSolver_ConstraintFixed> aConstraint =
-      PlaneGCSSolver_Tools::createMovementConstraint(theFeature);
-  if (!aConstraint)
-    return false;
-  SolverConstraintPtr(aConstraint)->process(myStorage, myIsEventsBlocked);
-  if (aConstraint->error().empty()) {
-    setTemporary(aConstraint);
-    if (!myStorage->isEmpty())
-      myStorage->setNeedToResolve(true);
-
-    mySketchSolver->initialize();
-    aConstraint->moveFeature();
+  std::shared_ptr<SketchSolver_ConstraintMovement> aConstraint =
+      PlaneGCSSolver_Tools::createMovementConstraint(theFeatureOrPoint);
+  if (aConstraint) {
+    SolverConstraintPtr(aConstraint)->process(theStorage, theEventsBlocked);
+    if (aConstraint->error().empty()) {
+      aConstraint->startPoint(theFrom);
+      theSketchSolver->initialize();
+      aConstraint->moveTo(theTo);
+      theStorage->setNeedToResolve(true);
+    } else
+      theStorage->notify(aConstraint->movedFeature());
   }
 
-  // notify all observers that theFeature has been changed
-  myStorage->notify(theFeature);
+  return aConstraint;
+}
+
+bool SketchSolver_Group::moveFeature(FeaturePtr theFeature,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
+{
+  SolverConstraintPtr aConstraint =
+      move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theFeature, theFrom, theTo);
+  setTemporary(aConstraint);
+  return true;
+}
+
+bool SketchSolver_Group::movePoint(AttributePtr theAttribute,
+                                   const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+                                   const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
+{
+  SolverConstraintPtr aConstraint =
+      move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theAttribute, theFrom, theTo);
+  setTemporary(aConstraint);
   return true;
 }
 
@@ -372,7 +396,8 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
 // ============================================================================
 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
 {
-  myTempConstraints.insert(theConstraint);
+  if (theConstraint)
+    myTempConstraints.insert(theConstraint);
 }
 
 // ============================================================================
index 9a78d9a2c6fa8404c7883067af9742b15d38297e..4a65bf258f37c50a4d26bee21eec46add297d355 100644 (file)
@@ -31,6 +31,8 @@
 #include <memory>
 #include <map>
 
+class GeomAPI_Pnt2d;
+
 typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
 
 /** \class   SketchSolver_Group
@@ -72,11 +74,25 @@ class SketchSolver_Group
   bool updateFeature(FeaturePtr theFeature);
 
   /** \brief Updates the data corresponding the specified feature moved in GUI.
-   *         Additional Fixed constraints are created.
+   *         Special kind of Fixed constraints is created.
    *  \param[in] theFeature the feature to be updated
-   *  \return \c true, if the feature is moved
+   *  \param[in] theFrom    start point of the movement
+   *  \param[in] theTo      final point of the movement
+   *  \return \c true, if the feature is really moved
+   */
+  bool moveFeature(FeaturePtr theFeature,
+                   const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+                   const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
+  /** \brief Updates the data corresponding the specified point moved in GUI.
+   *         Special kind of Fixed constraints is created.
+   *  \param[in] thePoint the attribute to be updated
+   *  \param[in] theFrom  start point of the movement
+   *  \param[in] theTo    final point of the movement
+   *  \return \c true, if the attribute is really moved
    */
-  bool moveFeature(FeaturePtr theFeature);
+  bool movePoint(AttributePtr thePoint,
+                 const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+                 const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
 
   /// Returns the current workplane
   inline const CompositeFeaturePtr& getWorkplane() const
index 70161208fb1c1333f59889e5c1f7622ddcb46127..4921a4d0322ae32e01d8d6d9c60174739ff59aae 100644 (file)
@@ -196,7 +196,7 @@ void SketchSolver_Manager::processEvent(
 }
 
 // ============================================================================
-//  Function: changeConstraintOrEntity
+//  Function: updateFeature
 //  Purpose:  create/update the constraint or the feature and place it into appropriate group
 // ============================================================================
 bool SketchSolver_Manager::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature,
@@ -223,6 +223,67 @@ bool SketchSolver_Manager::updateFeature(std::shared_ptr<SketchPlugin_Feature> t
   return isOk;
 }
 
+// ============================================================================
+//  Function: moveFeature
+//  Purpose:  move given feature in appropriate group
+// ============================================================================
+bool SketchSolver_Manager::moveFeature(
+    const std::shared_ptr<SketchPlugin_Feature>& theMovedFeature,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
+{
+  SketchGroupPtr aGroup = findGroup(theMovedFeature);
+  if (!aGroup)
+    return false;
+
+  std::shared_ptr<SketchPlugin_Constraint> aConstraint =
+      std::dynamic_pointer_cast<SketchPlugin_Constraint>(theMovedFeature);
+  if (aConstraint)
+  {
+    std::shared_ptr<GeomDataAPI_Point2D> aPntAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+    aPntAttr->setValue(theTo);
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+    return true;
+  }
+
+  aGroup->blockEvents(true);
+  return aGroup->moveFeature(theMovedFeature, theFrom, theTo);
+}
+
+// ============================================================================
+//  Function: moveAttribute
+//  Purpose:  move given attribute in appropriate group
+// ============================================================================
+bool SketchSolver_Manager::moveAttribute(
+    const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
+{
+  FeaturePtr anOwner = ModelAPI_Feature::feature(theMovedAttribute->owner());
+  std::shared_ptr<SketchPlugin_Constraint> aConstraint =
+      std::dynamic_pointer_cast<SketchPlugin_Constraint>(anOwner);
+  if (aConstraint)
+  {
+    theMovedAttribute->setValue(theTo);
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+    return true;
+  }
+
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(anOwner);
+  SketchGroupPtr aGroup;
+  if (aSketchFeature)
+    aGroup = findGroup(aSketchFeature);
+  if (!aGroup) {
+    theMovedAttribute->setValue(theTo);
+    return false;
+  }
+
+  aGroup->blockEvents(true);
+  return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
+}
+
 // ============================================================================
 //  Function: findGroup
 //  Purpose:  search groups of entities interacting with given feature
index 45c1a4284bbaff4df86690f1669785e1dd0cb923..d3509c7078f33cee6d7ab049de1f4a3adf2b3e9d 100644 (file)
 #include <SketchSolver_Group.h>
 
 #include <Events_Listener.h>
-#include <SketchPlugin_Constraint.h>
 
 #include <list>
 #include <set>
 
+class GeomAPI_Pnt2d;
+class GeomDataAPI_Point2D;
+class SketchPlugin_Constraint;
+
 /** \class   SketchSolver_Manager
  *  \ingroup Plugins
  *  \brief   Listens the changes of SketchPlugin features and transforms the Constraint
@@ -66,6 +69,26 @@ protected:
    */
   bool updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature, bool theMoved = false);
 
+  /** \brief Move feature
+   *  \param[in] theMovedFeature dragged sketch feature
+   *  \param[in] theFromPoint    original position of the feature
+   *  \param[in] theToPoint      prefereble position of the feature (current position of the mouse)
+   *  \return \c true if the feature has been changed successfully
+   */
+  bool moveFeature(const std::shared_ptr<SketchPlugin_Feature>& theMovedFeature,
+                   const std::shared_ptr<GeomAPI_Pnt2d>& theFromPoint,
+                   const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
+
+  /** \brief Move feature using its moved attribute
+   *  \param[in] theMovedAttribute dragged point attribute of sketch feature
+   *  \param[in] theFromPoint      original position of the moved point
+   *  \param[in] theToPoint        prefereble position (current position of the mouse)
+   *  \return \c true if the attribute owner has been changed successfully
+   */
+  bool moveAttribute(const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+                     const std::shared_ptr<GeomAPI_Pnt2d>& theFromPoint,
+                     const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
+
   /** \brief Removes a constraint from the manager
    *  \param[in] theConstraint constraint to be removed
    *  \return \c true if the constraint removed successfully
index f4f6e7254cd7a504a1f11a8679dca39809ef6707..8017703488077d7add53fd5d4859fd7eb992a3e6 100644 (file)
@@ -57,10 +57,10 @@ public:
   virtual void addConstraint(ConstraintPtr        theConstraint,
                              ConstraintWrapperPtr theSolverConstraint);
 
-  /// \brief Add list of temporary constraints which will be destroyed
+  /// \brief Add a movement constraint which will be destroyed
   ///        after the next solving of the set of constraints.
   /// \param theSolverConstraint [in]  solver's constraint
-  virtual void addTemporaryConstraint(const ConstraintWrapperPtr& theSolverConstraint) = 0;
+  virtual void addMovementConstraint(const ConstraintWrapperPtr& theSolverConstraint) = 0;
 
   /// \brief Change mapping feature from SketchPlugin and
   ///        the entity applicable for corresponding solver.
index 1d8a8134ceefe9c544d14075411534513b51caeb..fba498a281e8f0f930ca1a140e4f5ca3170a1872 100755 (executable)
@@ -33,8 +33,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Collinear, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Collinear::SketcherPrs_Collinear(ModelAPI_Feature* theConstraint,
+                                      ModelAPI_CompositeFeature* theSketcher,
                                      const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
index 86f8837aa2c9b4164350eff25392fc29535c3ec6..dfa4d853ef1afc7106ff4271bb9816bf6549f34a 100755 (executable)
@@ -36,8 +36,10 @@ class SketcherPrs_Collinear: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Collinear(ModelAPI_Feature* theConstraint,
+                                        ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Collinear, SketcherPrs_SymbolPrs)
 
index f534e27c93e7b64310934cb31c5ffbcf56897a50..7077e1a7ae14de4262105cd49101bd6d44686eaf 100644 (file)
@@ -33,8 +33,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Equal, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Equal::SketcherPrs_Equal(ModelAPI_Feature* theConstraint,
+                                      ModelAPI_CompositeFeature* theSketcher,
                                      const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
index 8285b814566be12c8f182dd30d7b58dd0015ccea..0b2066d38e7e4f6162a997ee3ca69de913200c6b 100644 (file)
@@ -36,9 +36,11 @@ class SketcherPrs_Equal: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Equal(ModelAPI_Feature* theConstraint,
-                                       const std::shared_ptr<GeomAPI_Ax3>& thePlane);
+                                    ModelAPI_CompositeFeature* theSketcher,
+                                    const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Equal, SketcherPrs_SymbolPrs)
 
   /// Returns true if the constraint feature arguments are correcly filled to build AIS presentation
index ab8e6378c9861b9bc407700ac1cf485ab022fec3..6059e0ce0dd643132de9fe999d79c2b8defc24c0 100644 (file)
@@ -38,6 +38,7 @@
 // Macros for constraint presentation definition
 #define CONSTRAINT_PRS_IMPL(NAME, CLASS) \
 AISObjectPtr SketcherPrs_Factory::NAME(ModelAPI_Feature* theConstraint, \
+                                       ModelAPI_CompositeFeature* theSketcher, \
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane, \
                                        AISObjectPtr thePrevious) \
 { \
@@ -47,28 +48,52 @@ AISObjectPtr SketcherPrs_Factory::NAME(ModelAPI_Feature* theConstraint, \
       anAISObj = thePrevious; \
     else { \
       anAISObj = AISObjectPtr(new GeomAPI_AISObject()); \
-      Handle(CLASS) aPrs = new CLASS(theConstraint, thePlane); \
+      Handle(CLASS) aPrs = new CLASS(theConstraint, theSketcher, thePlane); \
       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aPrs)); \
     } \
   } \
   return anAISObj; \
 }
 
-CONSTRAINT_PRS_IMPL(coincidentConstraint, SketcherPrs_Coincident);
+
 CONSTRAINT_PRS_IMPL(collinearConstraint, SketcherPrs_Collinear);
 CONSTRAINT_PRS_IMPL(parallelConstraint, SketcherPrs_Parallel);
 CONSTRAINT_PRS_IMPL(perpendicularConstraint, SketcherPrs_Perpendicular);
 CONSTRAINT_PRS_IMPL(rigidConstraint, SketcherPrs_Rigid);
 CONSTRAINT_PRS_IMPL(equalConstraint, SketcherPrs_Equal);
 CONSTRAINT_PRS_IMPL(tangentConstraint, SketcherPrs_Tangent);
-CONSTRAINT_PRS_IMPL(radiusConstraint, SketcherPrs_Radius);
-CONSTRAINT_PRS_IMPL(lengthDimensionConstraint, SketcherPrs_LengthDimension);
 CONSTRAINT_PRS_IMPL(middleConstraint, SketcherPrs_Middle);
 CONSTRAINT_PRS_IMPL(mirrorConstraint, SketcherPrs_Mirror);
-CONSTRAINT_PRS_IMPL(angleConstraint, SketcherPrs_Angle);
+
+
+
+#define CONSTRAINT2_PRS_IMPL(NAME, CLASS) \
+AISObjectPtr SketcherPrs_Factory::NAME(ModelAPI_Feature* theConstraint, \
+                                       const std::shared_ptr<GeomAPI_Ax3>& thePlane, \
+                                       AISObjectPtr thePrevious) \
+{ \
+  std::shared_ptr<GeomAPI_AISObject> anAISObj; \
+  if (CLASS::IsReadyToDisplay(theConstraint, thePlane)) { \
+    if (thePrevious.get()) \
+      anAISObj = thePrevious; \
+    else { \
+      anAISObj = AISObjectPtr(new GeomAPI_AISObject()); \
+      Handle(CLASS) aPrs = new CLASS(theConstraint, thePlane); \
+      anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aPrs)); \
+    } \
+  } \
+  return anAISObj; \
+}
+
+
+CONSTRAINT2_PRS_IMPL(coincidentConstraint, SketcherPrs_Coincident);
+CONSTRAINT2_PRS_IMPL(angleConstraint, SketcherPrs_Angle);
+CONSTRAINT2_PRS_IMPL(radiusConstraint, SketcherPrs_Radius);
+CONSTRAINT2_PRS_IMPL(lengthDimensionConstraint, SketcherPrs_LengthDimension);
 
 // Non-standard constraints definition
 AISObjectPtr SketcherPrs_Factory::horisontalConstraint(ModelAPI_Feature* theConstraint,
+                                        ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                        AISObjectPtr thePrevious)
 {
@@ -79,7 +104,7 @@ AISObjectPtr SketcherPrs_Factory::horisontalConstraint(ModelAPI_Feature* theCons
     else {
       anAISObj = AISObjectPtr(new GeomAPI_AISObject());
       Handle(SketcherPrs_HVDirection) aPrs =
-        new SketcherPrs_HVDirection(theConstraint, thePlane, true);
+        new SketcherPrs_HVDirection(theConstraint, theSketcher, thePlane, true);
       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aPrs));
     }
   }
@@ -87,6 +112,7 @@ AISObjectPtr SketcherPrs_Factory::horisontalConstraint(ModelAPI_Feature* theCons
 }
 
 AISObjectPtr SketcherPrs_Factory::verticalConstraint(ModelAPI_Feature* theConstraint,
+                                        ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                        AISObjectPtr thePrevious)
 {
@@ -97,7 +123,7 @@ AISObjectPtr SketcherPrs_Factory::verticalConstraint(ModelAPI_Feature* theConstr
     else {
       anAISObj = AISObjectPtr(new GeomAPI_AISObject());
       Handle(SketcherPrs_HVDirection) aPrs =
-        new SketcherPrs_HVDirection(theConstraint, thePlane, false);
+        new SketcherPrs_HVDirection(theConstraint, theSketcher, thePlane, false);
       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aPrs));
     }
   }
@@ -105,6 +131,7 @@ AISObjectPtr SketcherPrs_Factory::verticalConstraint(ModelAPI_Feature* theConstr
 }
 
 AISObjectPtr SketcherPrs_Factory::translateConstraint(ModelAPI_Feature* theConstraint,
+                                        ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                        AISObjectPtr thePrevious)
 {
@@ -115,7 +142,7 @@ AISObjectPtr SketcherPrs_Factory::translateConstraint(ModelAPI_Feature* theConst
     else {
       anAISObj = AISObjectPtr(new GeomAPI_AISObject());
       Handle(SketcherPrs_Transformation) aPrs =
-        new SketcherPrs_Transformation(theConstraint, thePlane, true);
+        new SketcherPrs_Transformation(theConstraint, theSketcher, thePlane, true);
       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aPrs));
     }
   }
@@ -123,6 +150,7 @@ AISObjectPtr SketcherPrs_Factory::translateConstraint(ModelAPI_Feature* theConst
 }
 
 AISObjectPtr SketcherPrs_Factory::rotateConstraint(ModelAPI_Feature* theConstraint,
+                                        ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                        AISObjectPtr thePrevious)
 {
@@ -133,7 +161,7 @@ AISObjectPtr SketcherPrs_Factory::rotateConstraint(ModelAPI_Feature* theConstrai
     else {
       anAISObj = AISObjectPtr(new GeomAPI_AISObject());
       Handle(SketcherPrs_Transformation) aPrs =
-        new SketcherPrs_Transformation(theConstraint, thePlane, false);
+        new SketcherPrs_Transformation(theConstraint, theSketcher, thePlane, false);
       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aPrs));
     }
   }
index ba4123cfb3451964d07c2282b32ee013db52080e..f59bd0d6173d7dfc316f02ead0e7262558c1d4aa 100644 (file)
 #include "SketcherPrs.h"
 
 #include <ModelAPI_Feature.h>
+#include <ModelAPI_CompositeFeature.h>
 
 #include <GeomAPI_Ax3.h>
 #include <GeomAPI_AISObject.h>
 
 #define GET_CONSTRAINT_PRS(NAME) \
   static AISObjectPtr NAME(ModelAPI_Feature* theConstraint, \
+                           ModelAPI_CompositeFeature* theSketcher, \
                            const std::shared_ptr<GeomAPI_Ax3>& thePlane, \
                            AISObjectPtr thePrevious);
 
 class SKETCHERPRS_EXPORT SketcherPrs_Factory
 {
 public:
-  /// Creates coincedent constraint presentation
-  /// \param theConstraint the constraint
-  /// \param thePlane the current sketch plane
-  /// \param thePrevious the previous presentation
-  GET_CONSTRAINT_PRS(coincidentConstraint)
-
   /// Creates collinear constraint presentation
   /// \param theConstraint the constraint
   /// \param thePlane the current sketch plane
@@ -93,18 +89,6 @@ public:
   /// \param thePrevious the previous presentation
   GET_CONSTRAINT_PRS(tangentConstraint)
 
-  /// Creates radius dimension presentation
-  /// \param theConstraint the constraint
-  /// \param thePlane the current sketch plane
-  /// \param thePrevious the previous presentation
-  GET_CONSTRAINT_PRS(radiusConstraint)
-
-  /// Creates length dimension presentation
-  /// \param theConstraint the constraint
-  /// \param thePlane the current sketch plane
-  /// \param thePrevious the previous presentation
-  GET_CONSTRAINT_PRS(lengthDimensionConstraint)
-
   /// Creates middle constraint presentation
   /// \param theConstraint the constraint
   /// \param thePlane the current sketch plane
@@ -129,11 +113,34 @@ public:
   /// \param thePrevious the previous presentation
   GET_CONSTRAINT_PRS(rotateConstraint)
 
+#define GET_CONSTRAINT2_PRS(NAME) \
+  static AISObjectPtr NAME(ModelAPI_Feature* theConstraint, \
+                           const std::shared_ptr<GeomAPI_Ax3>& thePlane, \
+                           AISObjectPtr thePrevious);
+
+  /// Creates coincedent constraint presentation
+  /// \param theConstraint the constraint
+  /// \param thePlane the current sketch plane
+  /// \param thePrevious the previous presentation
+  GET_CONSTRAINT2_PRS(coincidentConstraint)
+
   /// Creates angle constraint presentation
   /// \param theConstraint the constraint
   /// \param thePlane the current sketch plane
   /// \param thePrevious the previous presentation
-  GET_CONSTRAINT_PRS(angleConstraint)
+  GET_CONSTRAINT2_PRS(angleConstraint)
+
+  /// Creates length dimension presentation
+  /// \param theConstraint the constraint
+  /// \param thePlane the current sketch plane
+  /// \param thePrevious the previous presentation
+  GET_CONSTRAINT2_PRS(lengthDimensionConstraint)
+
+  /// Creates radius dimension presentation
+  /// \param theConstraint the constraint
+  /// \param thePlane the current sketch plane
+  /// \param thePrevious the previous presentation
+  GET_CONSTRAINT2_PRS(radiusConstraint)
 };
 
 #endif
index a53bd64aaf3b3093040c9cb3914ccc539aacd30a..d599d492cc1e16b0c78aa97b14367e73b0967d53 100644 (file)
@@ -33,9 +33,11 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_HVDirection, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_HVDirection::SketcherPrs_HVDirection(ModelAPI_Feature* theConstraint,
+                                           ModelAPI_CompositeFeature* theSketcher,
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                            bool isHorisontal)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane), myIsHorisontal(isHorisontal)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane),
+ myIsHorisontal(isHorisontal)
 {
 }
 
index ea50c41d55ea9262f89e46e94b6837d628af305c..07ffa9a07b6846d661e8b7ec7a0fd130386997bd 100644 (file)
@@ -37,9 +37,11 @@ class SketcherPrs_HVDirection: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   /// \param isHorisontal a flag horizontal or vertical presentation
   Standard_EXPORT SketcherPrs_HVDirection(ModelAPI_Feature* theConstraint,
+                                          ModelAPI_CompositeFeature* theSketcher,
                                          const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                          bool isHorisontal);
 
index 6a64f6eba70228097a59fc4ca9981e825b886503..34fb6a6eed108e69660e376bb0a35e19eec050a9 100644 (file)
@@ -25,6 +25,8 @@
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 #include <SketchPlugin_Circle.h>
@@ -40,6 +42,7 @@
 
 #include <AIS_DisplaySpecialSymbol.hxx>
 
+//#ifdef OCCT_28850_FIXED
 
 /// Creates an aspect to be shown in length/radius dimension presentations
 /// \return an instance of aspect
@@ -101,6 +104,13 @@ SketcherPrs_LengthDimension::SketcherPrs_LengthDimension(ModelAPI_Feature* theCo
 {
   SetDimensionAspect(createDimensionAspect());
   myStyleListener = new SketcherPrs_DimensionStyleListener();
+
+#ifdef OCCT_28850_FIXED
+  if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
+    SetDirection(true, mySketcherPlane->dirX()->impl<gp_Dir>());
+  else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+    SetDirection(true, mySketcherPlane->dirY()->impl<gp_Dir>());
+#endif
 }
 
 SketcherPrs_LengthDimension::~SketcherPrs_LengthDimension()
@@ -183,7 +193,9 @@ bool SketcherPrs_LengthDimension::readyToDisplay(ModelAPI_Feature* theConstraint
     thePnt2 = thePlane->to3D(aEndPoint->x(), aEndPoint->y())->impl<gp_Pnt>();
     return true;
 
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID() ||
+             theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+             theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
     // The constraint is distance
     std::shared_ptr<GeomDataAPI_Point2D> aPoint_A = SketcherPrs_Tools::getFeaturePoint(
         aData, SketchPlugin_Constraint::ENTITY_A(), thePlane);
index bfe35b8e5532d96bacb60d2f83c4ead29c7b75ab..ef272b49d898d73129fef0ee812b7f7d8cbc1fb2 100755 (executable)
@@ -33,8 +33,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Middle, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Middle::SketcherPrs_Middle(ModelAPI_Feature* theConstraint,
+                                      ModelAPI_CompositeFeature* theSketcher,
                                      const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
index 64871852e174f435233b719312e2f4d8c8b7f064..e5fbda622193d8586cfddccc30e8f7a10b579d28 100755 (executable)
@@ -36,9 +36,11 @@ class SketcherPrs_Middle: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Middle(ModelAPI_Feature* theConstraint,
-                                       const std::shared_ptr<GeomAPI_Ax3>& thePlane);
+                                     ModelAPI_CompositeFeature* theSketcher,
+                                     const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Middle, SketcherPrs_SymbolPrs)
 
   /// Returns true if the constraint feature arguments are correcly filled to build AIS presentation
index 82f61923b2860f0a6835f2d577a9eec6d2839a56..33a650116deaed59f480758d9db6355352847e6b 100644 (file)
@@ -35,8 +35,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Mirror, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Mirror::SketcherPrs_Mirror(ModelAPI_Feature* theConstraint,
+                                      ModelAPI_CompositeFeature* theSketcher,
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
index 758c2ba098e06176f02529e8a8b5ea53e0aa7293..7857e711884eb736630f99236d1f98610ab5c2c3 100644 (file)
@@ -36,8 +36,10 @@ class SketcherPrs_Mirror: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Mirror(ModelAPI_Feature* theConstraint,
+                                     ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Mirror, SketcherPrs_SymbolPrs)
 
index cfdad6de9bd196631590aa5fcaed0281bc652487..90cdfd1299de6bf9e86b99570675c3fcf4798afb 100644 (file)
@@ -34,8 +34,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Parallel, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Parallel::SketcherPrs_Parallel(ModelAPI_Feature* theConstraint,
+                                          ModelAPI_CompositeFeature* theSketcher,
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
index 0ce747818487c4f84afe0e023cd049d10aabd0a8..d963fcc8b45fbc05a3216134a7672b4ac23fe814 100644 (file)
@@ -36,8 +36,10 @@ class SketcherPrs_Parallel: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Parallel(ModelAPI_Feature* theConstraint,
+                                       ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Parallel, SketcherPrs_SymbolPrs)
 
index bce82ffbaa8fce3b49fc5e0c35e910c7d78adf01..16b5531009417c484c53acbc634e8aa005d68e2c 100644 (file)
@@ -27,6 +27,9 @@
 #include <Graphic3d_AspectLine3d.hxx>
 #include <Prs3d_Root.hxx>
 
+#include <GeomAPI_Curve.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Lin.h>
 
 
 IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Perpendicular, SketcherPrs_SymbolPrs);
@@ -34,8 +37,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Perpendicular, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Perpendicular::SketcherPrs_Perpendicular(ModelAPI_Feature* theConstraint,
+                                                     ModelAPI_CompositeFeature* theSketcher,
                                                      const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
@@ -64,13 +68,24 @@ bool SketcherPrs_Perpendicular::updateIfReadyToDisplay(double theStep, bool with
   ObjectPtr aObj2 =
     SketcherPrs_Tools::getResult(myConstraint, SketchPlugin_Constraint::ENTITY_B());
 
+  GeomShapePtr aShp1 = SketcherPrs_Tools::getShape(aObj1);
+  GeomShapePtr aShp2 = SketcherPrs_Tools::getShape(aObj2);
+
+  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);
+
   // Compute position of symbols
   SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
-  gp_Pnt aP1 = aMgr->getPosition(aObj1, this, theStep);
-  gp_Pnt aP2 = aMgr->getPosition(aObj2, this, theStep);
-  myPntArray = new Graphic3d_ArrayOfPoints(2, withColor);
+  gp_Pnt aP1 = aMgr->getPosition(aObj1, this, theStep, aPnt);
+  //gp_Pnt aP2 = aMgr->getPosition(aObj2, this, theStep);
+  myPntArray = new Graphic3d_ArrayOfPoints(1, withColor);
   myPntArray->AddVertex(aP1);
-  myPntArray->AddVertex(aP2);
+  //myPntArray->AddVertex(aP2);
   return true;
 }
 
index 5b33377f0c33401caad518aa26aa237ee68cea41..b075d4aa4855dea6ba192953c970ea38dd02b3d5 100644 (file)
@@ -38,8 +38,10 @@ class SketcherPrs_Perpendicular: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Perpendicular(ModelAPI_Feature* theConstraint,
+                                            ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Perpendicular, SketcherPrs_SymbolPrs)
index d77e0301390a2bc432e1be1c97dbc075d82fab64..65b1d045166f3044044e2917d7f1119f52af0e71 100644 (file)
 #include <GeomAPI_Curve.h>
 #include <GeomAPI_Vertex.h>
 #include <GeomAPI_Dir.h>
+#include <GeomAPI_Ax3.h>
+#include <GeomAPI_Circ.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+
+#include <BRepExtrema_ExtPC.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <Geom_Curve.hxx>
+#include <TColGeom_SequenceOfCurve.hxx>
+#include <gp_Dir.hxx>
+
+#include <array>
 
 static SketcherPrs_PositionMgr* MyPosMgr = NULL;
 
+#define PI 3.1415926535897932
+
 // The class is implemented as a singlton
 SketcherPrs_PositionMgr* SketcherPrs_PositionMgr::get()
 {
@@ -65,50 +85,183 @@ int SketcherPrs_PositionMgr::getPositionIndex(ObjectPtr theLine,
   }
 }
 
-gp_Pnt SketcherPrs_PositionMgr::getPosition(ObjectPtr theShape,
-                                            const SketcherPrs_SymbolPrs* thePrs,
-                                            double theStep)
+
+bool SketcherPrs_PositionMgr::isPntConstraint(const std::string& theName)
+{
+  static std::list<std::string> aConstraints;
+  if (aConstraints.size() == 0) {
+    aConstraints.push_back(SketchPlugin_ConstraintTangent::ID());
+    aConstraints.push_back(SketchPlugin_ConstraintPerpendicular::ID());
+  }
+  std::list<std::string>::const_iterator aIt;
+  for (aIt = aConstraints.cbegin(); aIt != aConstraints.cend(); ++aIt) {
+    if ((*aIt) == theName)
+      return true;
+  }
+  return false;
+}
+
+bool containsPoint(const FeaturePtr& theFeature, GeomPnt2dPtr thePnt2d, GeomPointPtr thePos)
+{
+  if (theFeature->getKind() == SketchPlugin_Line::ID()) {
+    AttributePoint2DPtr aSPnt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->data()->attribute(SketchPlugin_Line::START_ID()));
+    AttributePoint2DPtr aSPnt2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->data()->attribute(SketchPlugin_Line::END_ID()));
+
+    GeomPnt2dPtr aPnt1 = aSPnt1->pnt();
+    GeomPnt2dPtr aPnt2 = aSPnt2->pnt();
+
+    if (aPnt1->isEqual(thePnt2d) || aPnt2->isEqual(thePnt2d))
+      return true;
+  } else if ((theFeature->getKind() == SketchPlugin_Circle::ID()) ||
+             (theFeature->getKind() == SketchPlugin_Arc::ID())) {
+    GeomCurvePtr aCurve;
+    ObjectPtr aResObj;
+    std::list<ResultPtr> aResults = theFeature->results();
+    std::list<ResultPtr>::const_iterator aIt;
+    for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
+      GeomShapePtr aShp = SketcherPrs_Tools::getShape((*aIt));
+      if (aShp->isEdge()) {
+        aResObj = (*aIt);
+        aCurve = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp));
+        break;
+      }
+    }
+    if (aCurve.get()) {
+      double aStart = aCurve->startParam();
+      double aEnd = aCurve->endParam();
+      GeomCirclePtr  aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
+      double aParam;
+      if (aCircle->parameter(thePos, 1.e-4, aParam) && (aParam >= aStart) && (aParam <= aEnd))
+        return true;
+    }
+  }
+  return false;
+}
+
+const std::array<int, 2>& SketcherPrs_PositionMgr::getPositionIndex(GeomPointPtr thePos,
+                                              const SketcherPrs_SymbolPrs* thePrs)
 {
+  if (myPntShapes.count(thePrs->feature()) == 0) {
+    // Renumerate positions around the specified constraint point for all constraints
+    GeomAx3Ptr aAx3 = thePrs->plane();
+    ModelAPI_CompositeFeature* aOwner = thePrs->sketcher();
+    GeomPnt2dPtr aPnt2d = thePos->to2D(aAx3->origin(), aAx3->dirX(), aAx3->dirY());
+
+    int aNbSubs = aOwner->numberOfSubs();
+    int aId = 0;
+    std::list<const ModelAPI_Feature*> aFeaList;
+    for (int i = 0; i < aNbSubs; i++) {
+      FeaturePtr aFeature = aOwner->subFeature(i);
+
+      if (myPntShapes.count(aFeature.get()) == 1) {
+        myPntShapes[aFeature.get()][0] = aId;
+        aId++;
+        aFeaList.push_back(aFeature.get());
+      } else {
+        if (isPntConstraint(aFeature->getKind())) {
+          DataPtr aData = aFeature->data();
+          AttributeRefAttrPtr aObjRef = aData->refattr(SketchPlugin_Constraint::ENTITY_A());
+          FeaturePtr aObj = ModelAPI_Feature::feature(aObjRef->object());
+          bool aContains = false;
+          if (containsPoint(aObj, aPnt2d, thePos)) {
+            aContains = true;
+          } else {
+            aObjRef = aData->refattr(SketchPlugin_Constraint::ENTITY_B());
+            aObj = ModelAPI_Feature::feature(aObjRef->object());
+            if (containsPoint(aObj, aPnt2d, thePos)) {
+              aContains = true;
+            }
+          }
+          if (aContains) {
+            myPntShapes[aFeature.get()][0] = aId;
+            aId++;
+            aFeaList.push_back(aFeature.get());
+          }
+        }
+      }
+    }
+    int aSize = (int) aFeaList.size();
+    std::list<const ModelAPI_Feature*>::const_iterator aIt;
+    for (aIt = aFeaList.cbegin(); aIt != aFeaList.cend(); aIt++) {
+      myPntShapes[*aIt][1] = aSize;
+    }
+  }
+  return myPntShapes[thePrs->feature()];
+}
+
+//*****************************************************************
+gp_Vec getVector(ObjectPtr theShape, GeomDirPtr theDir, gp_Pnt theP)
+{
+  gp_Vec aVec;
   std::shared_ptr<GeomAPI_Shape> aShape = SketcherPrs_Tools::getShape(theShape);
-  gp_Pnt aP; // Central point
-  gp_Vec aVec1; // main vector
   if (aShape->isEdge()) {
     std::shared_ptr<GeomAPI_Curve> aCurve =
       std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape));
-    std::shared_ptr<GeomAPI_Pnt> aPnt1; // Start point of main vector
-    std::shared_ptr<GeomAPI_Pnt> aPnt2; // End point of main vector
-    if (aCurve->isLine()) {
-      std::shared_ptr<GeomAPI_Edge> aEdge =
-        std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aShape));
 
-      aPnt1 = aEdge->firstPoint();
-      aPnt2 = aEdge->lastPoint();
+    if (aCurve->isCircle()) {
+      GeomEdgePtr aEdgePtr(new GeomAPI_Edge(aShape));
+      GeomVertexPtr aVertexPtr(new GeomAPI_Vertex(theP.X(), theP.Y(), theP.Z()));
+      BRepExtrema_ExtPC aExtrema(aVertexPtr->impl<TopoDS_Vertex>(),
+                                 aEdgePtr->impl<TopoDS_Edge>());
+      int aNb = aExtrema.NbExt();
+      if (aNb > 0) {
+        for (int i = 1; i <= aNb; i++) {
+          if (aExtrema.IsMin(i)) {
+            double aParam = aExtrema.Parameter(i);
+            Handle(Geom_Curve) aCurv = aCurve->impl<Handle_Geom_Curve>();
+            gp_Pnt aP;
+            aCurv->D1(aParam, aP, aVec);
+            break;
+          }
+        }
+      }
+    } else {
+      GeomPointPtr aPnt1 = aCurve->getPoint(aCurve->endParam());
+      GeomPointPtr aPnt2 = aCurve->getPoint(aCurve->startParam());
 
-      // Find the middle point
-      aP = gp_Pnt((aPnt1->x() + aPnt2->x())/2.,
-                  (aPnt1->y() + aPnt2->y())/2.,
-                  (aPnt1->z() + aPnt2->z())/2.);
+      gp_Pnt aPn2 = aPnt2->impl<gp_Pnt>();
+      if (aPn2.IsEqual(theP, Precision::Confusion()))
+        aVec = gp_Vec(aPn2, aPnt1->impl<gp_Pnt>());
+      else
+        aVec = gp_Vec(aPnt1->impl<gp_Pnt>(), aPn2);
+    }
+  } else {
+    aVec = gp_Vec(theDir->impl<gp_Dir>());
+  }
+  return aVec;
+}
 
-    } else {
+//*****************************************************************
+gp_Pnt SketcherPrs_PositionMgr::getPosition(ObjectPtr theShape,
+                                            const SketcherPrs_SymbolPrs* thePrs,
+                                            double theStep, GeomPointPtr thePnt)
+{
+  std::shared_ptr<GeomAPI_Shape> aShape = SketcherPrs_Tools::getShape(theShape);
+  gp_Pnt aP; // Central point
+
+  if (thePnt.get()) {
+    return getPointPosition(theShape, thePrs, theStep, thePnt);
+  } else {
+    if (aShape->isEdge()) {
+      std::shared_ptr<GeomAPI_Curve> aCurve =
+        std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape));
       // this is a circle or arc
       double aMidParam = (aCurve->startParam() + aCurve->endParam()) / 2.;
       std::shared_ptr<GeomAPI_Pnt> aPnt = aCurve->getPoint(aMidParam);
       aP = aPnt->impl<gp_Pnt>();
-
-      aPnt1 = aCurve->getPoint((aMidParam + aCurve->endParam()) / 2.);
-      aPnt2 = aCurve->getPoint((aMidParam + aCurve->startParam()) / 2.);
+    } else {
+      // This is a point
+      std::shared_ptr<GeomAPI_Vertex> aVertex =
+        std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aShape));
+      std::shared_ptr<GeomAPI_Pnt> aPnt = aVertex->point();
+      aP = aPnt->impl<gp_Pnt>();
     }
-    aVec1 = gp_Vec(aPnt1->impl<gp_Pnt>(), aPnt2->impl<gp_Pnt>());
-  } else {
-    // This is a point
-    std::shared_ptr<GeomAPI_Vertex> aVertex =
-      std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aShape));
-    std::shared_ptr<GeomAPI_Pnt> aPnt = aVertex->point();
-    aP = aPnt->impl<gp_Pnt>();
-
-    std::shared_ptr<GeomAPI_Dir> aDir = thePrs->plane()->dirX();
-    aVec1 = gp_Vec(aDir->impl<gp_Dir>());
   }
+  // main vector
+  gp_Vec aVec1 = getVector(theShape, thePrs->plane()->dirX(), aP);
+
   // Compute shifting vector for a one symbol
   gp_Vec aShift = aVec1.Crossed(thePrs->plane()->normal()->impl<gp_Dir>());
   aShift.Normalize();
@@ -145,6 +298,152 @@ gp_Pnt SketcherPrs_PositionMgr::getPosition(ObjectPtr theShape,
   return aP;
 }
 
+
+//*****************************************************************
+//! Returns curves connected to the given point
+std::list<ObjectPtr> getCurves(const GeomPointPtr& thePnt, const SketcherPrs_SymbolPrs* thePrs)
+{
+  std::list<ObjectPtr> aList;
+  GeomAx3Ptr aAx3 = thePrs->plane();
+  ModelAPI_CompositeFeature* aOwner = thePrs->sketcher();
+  GeomPnt2dPtr aPnt2d = thePnt->to2D(aAx3->origin(), aAx3->dirX(), aAx3->dirY());
+
+  int aNbSubs = aOwner->numberOfSubs();
+  for (int i = 0; i < aNbSubs; i++) {
+    FeaturePtr aFeature = aOwner->subFeature(i);
+    if (!aFeature->firstResult().get()) // There is no result
+      continue;
+
+    if (aFeature->getKind() == SketchPlugin_Line::ID()) {
+      AttributePoint2DPtr aSPnt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature->data()->attribute(SketchPlugin_Line::START_ID()));
+      AttributePoint2DPtr aSPnt2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature->data()->attribute(SketchPlugin_Line::END_ID()));
+
+      GeomPnt2dPtr aPnt1 = aSPnt1->pnt();
+      GeomPnt2dPtr aPnt2 = aSPnt2->pnt();
+
+      if (aPnt1->isEqual(aPnt2d) || aPnt2->isEqual(aPnt2d)) {
+        GeomShapePtr aShp = SketcherPrs_Tools::getShape(aFeature->firstResult());
+        GeomCurvePtr aCurv = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp));
+        aList.push_back(aFeature->firstResult());
+      }
+    } else if ((aFeature->getKind() == SketchPlugin_Circle::ID()) ||
+              (aFeature->getKind() == SketchPlugin_Arc::ID())) {
+      GeomCurvePtr aCurve;
+      ObjectPtr aResObj;
+      std::list<ResultPtr> aResults = aFeature->results();
+      std::list<ResultPtr>::const_iterator aIt;
+      for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
+        GeomShapePtr aShp = SketcherPrs_Tools::getShape((*aIt));
+        if (aShp->isEdge()) {
+          aResObj = (*aIt);
+          aCurve = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp));
+          break;
+        }
+      }
+      if (aCurve.get()) {
+        double aStart = aCurve->startParam();
+        double aEnd = aCurve->endParam();
+        GeomCirclePtr  aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
+        double aParam;
+        if (aCircle->parameter(thePnt, 1.e-4, aParam) && (aParam >= aStart) && (aParam <= aEnd))
+          aList.push_back(aResObj);
+      }
+    }
+  }
+  return aList;
+}
+
+//*****************************************************************
+gp_Pnt SketcherPrs_PositionMgr::getPointPosition(
+  ObjectPtr theLine, const SketcherPrs_SymbolPrs* thePrs,
+  double theStep, GeomPointPtr thePnt)
+{
+  gp_Pnt aP = thePnt->impl<gp_Pnt>();
+  GeomDirPtr aNormal = thePrs->plane()->normal();
+  gp_Dir aNormDir = aNormal->impl<gp_Dir>();
+
+  std::list<ObjectPtr> aCurves = getCurves(thePnt, thePrs);
+  std::list<ObjectPtr>::const_iterator aItCurv;
+  std::list<gp_Vec> aVectorsList;
+  // Calculate all vectors
+  for (aItCurv = aCurves.cbegin(); aItCurv != aCurves.cend(); aItCurv++) {
+    aVectorsList.push_back(getVector((*aItCurv), thePrs->plane()->dirX(), aP));
+  }
+
+  // Position of the symbol
+  const std::array<int, 2>& aPos = getPositionIndex(thePnt, thePrs);
+
+  // Angle size of a symbol
+  double aAngleStep = PI * 50./180.;
+
+  std::list<gp_Vec>::const_iterator aItVec;
+  std::list<double> aAngles;
+  std::list<gp_Vec> aVectors;
+  // Select closest vectors and calculate angles between base vector and closest vector
+  for (aItVec = aVectorsList.cbegin(); aItVec != aVectorsList.cend(); aItVec++) {
+    std::list<gp_Vec>::const_iterator aIt;
+    double aMinAng = 0;
+    gp_Vec aVec = *aItVec;
+    for (aIt = aVectorsList.cbegin(); aIt != aVectorsList.cend(); aIt++) {
+      double aAng = aVec.AngleWithRef(*aIt, aNormDir);
+      if (aAng != 0) {
+        if (aAng < 0)
+          aAng = 2 * PI + aAng;
+
+        if (aMinAng == 0)
+          aMinAng = aAng;
+        else if (aAng < aMinAng) {
+          aMinAng = aAng;
+        }
+      }
+    }
+    aVectors.push_back(aVec);
+    aAngles.push_back(aMinAng);
+  }
+
+  int aPosCount = 0;
+  double aAng;
+  std::list<double>::const_iterator aItAng;
+
+  double aAngPos;
+  gp_Vec aVecPos;
+  bool aHasPlace = false;
+  int aIntId = 0; // a position inside a one sector
+  while (aPosCount < aPos[1]) {
+    for (aItAng = aAngles.cbegin(), aItVec = aVectors.cbegin();
+         aItAng != aAngles.cend(); ++aItAng, ++aItVec) {
+      aAng = (*aItAng);
+      int Nb = int(aAng / aAngleStep);
+      aPosCount += Nb;
+
+      if ((!aHasPlace) && (aPosCount >= (aPos[0] + 1))) {
+        aHasPlace = true;
+        aAngPos = (*aItAng);
+        aVecPos = (*aItVec);
+        aIntId = aPos[0] - (aPosCount - Nb);
+      }
+    }
+    if (aPosCount < aPos[1]) {
+      aAngleStep -= 0.1;
+      aHasPlace = false;
+      aPosCount = 0;
+    }
+  }
+
+  gp_Ax1 aRotAx(aP, aNormDir);
+  if (aHasPlace) {
+    // rotate base vector on a necessary angle
+    gp_Vec aShift = aVecPos.Rotated(aRotAx, aAngleStep + aAngleStep * aIntId);
+    aShift.Normalize();
+    aShift.Multiply(theStep * 1.5);
+    return aP.Translated(aShift);
+  }
+  return aP;
+}
+
+//*****************************************************************
 void SketcherPrs_PositionMgr::deleteConstraint(const SketcherPrs_SymbolPrs* thePrs)
 {
   std::map<ObjectPtr, PositionsMap>::iterator aIt;
index d9bb444ee17776a7470a45417ff5352a4c3f8c28..8695126b2ae06aa83d010caa8f4834614464504c 100644 (file)
 #include "SketcherPrs_SymbolPrs.h"
 
 #include <GeomAPI_Shape.h>
+#include <GeomAPI_Pnt.h>
 #include <gp_Pnt.hxx>
 #include <ModelAPI_Object.h>
 
 #include <map>
+#include <array>
 
 /**
 * \ingroup GUI
@@ -44,7 +46,8 @@ public:
   /// \param theLine constrained object
   /// \param thePrs a presentation of constraint
   /// \param theStep step between symbols
-  gp_Pnt getPosition(ObjectPtr theLine, const SketcherPrs_SymbolPrs* thePrs, double theStep = 20);
+  gp_Pnt getPosition(ObjectPtr theLine, const SketcherPrs_SymbolPrs* thePrs,
+                     double theStep = 20, GeomPointPtr thePnt = GeomPointPtr());
 
   /// Deletes constraint object from internal structures. Has to be called on constraint delete.
   /// \param thePrs a constraint presentation
@@ -59,14 +62,34 @@ private:
   /// \param thePrs a presentation of constraint
   int getPositionIndex(ObjectPtr theLine, const SketcherPrs_SymbolPrs* thePrs);
 
+  /// Returns position index of the given constraint around a point
+  /// \param theLine constrained object
+  /// \param thePrs a presentation of constraint
+  const std::array<int, 2>& getPositionIndex(GeomPointPtr thePos,
+                                      const SketcherPrs_SymbolPrs* thePrs);
+
+  /// Returns position of a constraint around a point
+  /// \param theLine a base object of the constraint
+  /// \param thePrs a presentation of the constraint symbol
+  /// \param theStep step from base point
+  /// \param thePnt a base point
+  gp_Pnt getPointPosition(ObjectPtr theLine, const SketcherPrs_SymbolPrs* thePrs,
+                          double theStep, GeomPointPtr thePnt);
+
+  static bool isPntConstraint(const std::string& theName);
+
 private:
   typedef std::map<const SketcherPrs_SymbolPrs*, int> PositionsMap;
+  typedef std::map<const ModelAPI_Feature*, std::array<int, 2>> FeaturesMap;
 
   /// The map which contains position of presentation
   PositionsMap myIndexes;
 
   /// The map contains position index
   std::map<ObjectPtr, PositionsMap> myShapes;
+
+  /// The map contains position of index for constraints around a point
+  FeaturesMap myPntShapes;
 };
 
 #endif
\ No newline at end of file
index 3ce84501c3bafacab19feeb6831e6112c9b9d1ae..88ad963b7fe5c20090ee0f113023e7994e0d2e19 100644 (file)
@@ -51,8 +51,9 @@ static Handle(Image_AlienPixMap) MyPixMap;
 
 
 SketcherPrs_Rigid::SketcherPrs_Rigid(ModelAPI_Feature* theConstraint,
+                                      ModelAPI_CompositeFeature* theSketcher,
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
index c1aaf2fe0a7ad65f18b291e330121cf7eb944a84..e35045ab7874095632c7c788e110e8e45cceba69 100644 (file)
@@ -38,8 +38,10 @@ class SketcherPrs_Rigid: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Rigid(ModelAPI_Feature* theConstraint,
+                                    ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
 
index 2f0758204701392a23a1d1c4133a5a926a593fbe..9e91f3ff4e2214738025091df3793a5ce1e19f6f 100644 (file)
@@ -26,6 +26,8 @@
 #include <GeomAPI_Vertex.h>
 #include <GeomAPI_Curve.h>
 
+#include <ModelAPI_Tools.h>
+
 #include <Events_InfoMessage.h>
 
 #include <Graphic3d_ArrayOfSegments.hxx>
@@ -117,8 +119,11 @@ std::map<const char*, Handle(Image_AlienPixMap)> SketcherPrs_SymbolPrs::myIconsM
 
 
 SketcherPrs_SymbolPrs::SketcherPrs_SymbolPrs(ModelAPI_Feature* theConstraint,
+                                             ModelAPI_CompositeFeature* theSketcher,
                                              const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : AIS_InteractiveObject(), myConstraint(theConstraint), myPlane(thePlane), myIsCustomColor(false)
+ : AIS_InteractiveObject(), myConstraint(theConstraint),
+   myPlane(thePlane), myIsCustomColor(false),
+   mySketcher(theSketcher)
 {
   SetAutoHilight(Standard_False);
 }
@@ -412,4 +417,3 @@ void SketcherPrs_SymbolPrs::BoundingBox(Bnd_Box& theBndBox)
   theBndBox.Update (aTmpBox.CornerMin().x(), aTmpBox.CornerMin().y(), aTmpBox.CornerMin().z(),
                     aTmpBox.CornerMax().x(), aTmpBox.CornerMax().y(), aTmpBox.CornerMax().z());
 }
-
index a8b64d21e52d847f65ed413b512ef2be1c82e2b5..5d28c1dd1a408e7ca059954a817ce4d30ab9753c 100644 (file)
@@ -24,6 +24,7 @@
 #include "SketcherPrs_SensitivePoint.h"
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_CompositeFeature.h>
 
 #include <AIS_InteractiveObject.hxx>
 #include <GeomAPI_Ax3.h>
@@ -55,6 +56,7 @@ public:
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_SymbolPrs(ModelAPI_Feature* theConstraint,
+                        ModelAPI_CompositeFeature* theSketcher,
                         const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   virtual ~SketcherPrs_SymbolPrs();
@@ -76,6 +78,9 @@ public:
   /// Returns feature object
   Standard_EXPORT ModelAPI_Feature* feature() const { return myConstraint; }
 
+  /// Returns Sketcher object (owner of the constraint)
+  Standard_EXPORT ModelAPI_CompositeFeature* sketcher() const { return mySketcher; }
+
   /// Return array of points where symbols will be placed
   const Handle(Graphic3d_ArrayOfPoints)& pointsArray() const { return myPntArray; }
 
@@ -143,6 +148,9 @@ protected:
   /// Constraint feature
   ModelAPI_Feature* myConstraint;
 
+  /// Sketcher feature
+  ModelAPI_CompositeFeature* mySketcher;
+
   /// Plane of the current sketcher
   std::shared_ptr<GeomAPI_Ax3> myPlane;
 
index 5a7d2a538e4a613c23111f57c1d417837ace3ae8..ae29e259da80d4175cfdb3547031d242b6350048 100644 (file)
@@ -23,6 +23,8 @@
 #include "SketcherPrs_PositionMgr.h"
 
 #include <GeomAPI_Curve.h>
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Lin.h>
 
 #include <SketchPlugin_Constraint.h>
 
@@ -37,8 +39,9 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Tangent, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Tangent::SketcherPrs_Tangent(ModelAPI_Feature* theConstraint,
+                                         ModelAPI_CompositeFeature* theSketcher,
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane)
 {
 }
 
@@ -68,13 +71,50 @@ bool SketcherPrs_Tangent::updateIfReadyToDisplay(double theStep, bool withColor)
   ObjectPtr aObj2 =
     SketcherPrs_Tools::getResult(myConstraint, SketchPlugin_Constraint::ENTITY_B());
 
+  GeomShapePtr aShp1 = SketcherPrs_Tools::getShape(aObj1);
+  GeomShapePtr aShp2 = SketcherPrs_Tools::getShape(aObj2);
+
+  GeomCurvePtr aCurv1 = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp1));
+  GeomCurvePtr aCurv2 = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp2));
+
+  GeomCurvePtr aLine;
+  GeomCirclePtr aCircle;
+  double aFirst, aLast;
+  if (aCurv1->isLine()) {
+    aLine = aCurv1;
+    aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurv2));
+    aFirst = aCurv2->startParam();
+    aLast = aCurv2->endParam();
+  } else {
+    aLine = aCurv2;
+    aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurv1));
+    aFirst = aCurv1->startParam();
+    aLast = aCurv1->endParam();
+  }
+
+  GeomPointPtr aPnt1 = aLine->getPoint(aLine->startParam());
+  GeomPointPtr aPnt2 = aLine->getPoint(aLine->endParam());
+  double aParam;
+  GeomPointPtr aPnt;
+  if (aCircle->parameter(aPnt1, 1.e-4, aParam) && (aParam >= aFirst) && (aParam <= aLast))
+    aPnt = aPnt1;
+  else if (aCircle->parameter(aPnt2, 1.e-4, aParam) && (aParam >= aFirst) && (aParam <= aLast))
+    aPnt = aPnt2;
+
   // Compute points coordinates
-  SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
-  gp_Pnt aP1 = aMgr->getPosition(aObj1, this, theStep);
-  gp_Pnt aP2 = aMgr->getPosition(aObj2, this, theStep);
-  myPntArray = new Graphic3d_ArrayOfPoints(2, withColor);
-  myPntArray->AddVertex(aP1);
-  myPntArray->AddVertex(aP2);
+  if (aPnt.get()) {
+    SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
+    gp_Pnt aP1 = aMgr->getPosition(aObj1, this, theStep, aPnt);
+    myPntArray = new Graphic3d_ArrayOfPoints(1, withColor);
+    myPntArray->AddVertex(aP1);
+  } else {
+    SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
+    gp_Pnt aP1 = aMgr->getPosition(aObj1, this, theStep);
+    gp_Pnt aP2 = aMgr->getPosition(aObj2, this, theStep);
+    myPntArray = new Graphic3d_ArrayOfPoints(2, withColor);
+    myPntArray->AddVertex(aP1);
+    myPntArray->AddVertex(aP2);
+  }
   return true;
 }
 
index be320a54df98c420bfa0af980229684e6ab1dd7f..6da05ce52b96fa70e1451808ef1f47a61524b170 100644 (file)
@@ -37,8 +37,10 @@ class SketcherPrs_Tangent: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   Standard_EXPORT SketcherPrs_Tangent(ModelAPI_Feature* theConstraint,
+                                      ModelAPI_CompositeFeature* theSketcher,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   DEFINE_STANDARD_RTTIEXT(SketcherPrs_Tangent, SketcherPrs_SymbolPrs)
index a409bcc94c770dfae15d8f4c1a4e211cf2db7a33..ed54c12582773a634fd0d83483bef1657238d25d 100644 (file)
@@ -42,9 +42,10 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Transformation, SketcherPrs_SymbolPrs);
 static Handle(Image_AlienPixMap) MyPixMap;
 
 SketcherPrs_Transformation::SketcherPrs_Transformation(ModelAPI_Feature* theConstraint,
+                                           ModelAPI_CompositeFeature* theSketcher,
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                            bool isTranslation)
- : SketcherPrs_SymbolPrs(theConstraint, thePlane), myIsTranslation(isTranslation)
+ : SketcherPrs_SymbolPrs(theConstraint, theSketcher, thePlane), myIsTranslation(isTranslation)
 {
 }
 
index ed733b0bee37dd0d5b5f4cc2cf2bba0326ba80d6..e68397ff443dbfc2747ee873d1507f67168725b2 100644 (file)
@@ -37,9 +37,11 @@ class SketcherPrs_Transformation: public SketcherPrs_SymbolPrs
 public:
   /// Constructor
   /// \param theConstraint a constraint feature
+  /// \param theSketcher a sketcher object
   /// \param thePlane a coordinate plane of current sketch
   /// \param isTranslation a flag is it translation or rotation
   Standard_EXPORT SketcherPrs_Transformation(ModelAPI_Feature* theConstraint,
+                                            ModelAPI_CompositeFeature* theSketcher,
                                          const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                          bool isTranslation);
 
index e22a952e244ceb7183b17139a3c239845ba8687a..d0ee1667c6196630a1f434424ef9febada2dfc60 100644 (file)
@@ -724,7 +724,7 @@ void XGUI_ContextMenuMgr::addFeatures(QMenu* theMenu) const
   bool aIsRoot = false;
   foreach(QModelIndex aIdx, aSelectedIndexes) {
     // Process only first column
-    if (aIdx.column() == 0) {
+    if (aIdx.column() == 1) {
       aIsRoot = !aIdx.parent().isValid();
       // Exit if the selected index belongs to non active document
       if (aIsRoot && (aActiveDoc != aMgr->moduleDocument()))
index 30cf4e574342ab50ac1d7090115d3cf5c5f71b15..e2f8246554d1f9dd9f01336222c75af6c7c68698 100644 (file)
@@ -19,6 +19,9 @@
 //
 
 #include "XGUI_DataModel.h"
+#include "XGUI_Workshop.h"
+#include "XGUI_ObjectsBrowser.h"
+#include "XGUI_Displayer.h"
 
 #include <ModuleBase_IconFactory.h>
 
@@ -81,6 +84,9 @@ ModelAPI_Document* getSubDocument(void* theObj)
 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//,
   //myIsEventsProcessingBlocked(false)
 {
+  XGUI_ObjectsBrowser* aOB = qobject_cast<XGUI_ObjectsBrowser*>(theParent);
+  myWorkshop = aOB->workshop();
+
   Events_Loop* aLoop = Events_Loop::loop();
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
@@ -142,7 +148,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
         }
       } else {
         // Object created in sub-document
-        QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
+        QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get(), 0);
         if (aDocRoot.isValid()) {
           // Check that new folders could appear
           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
@@ -227,7 +233,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
         }
       } else {
         // Remove row for sub-document
-        QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
+        QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get(), 0);
         if (aDocRoot.isValid()) {
           int aRow = aDoc->size(aGroup);
           int aNbSubFolders = foldersCount(aDoc.get());
@@ -276,10 +282,10 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
           && (aFeature->firstResult()->groupName() == ModelAPI_ResultField::group())) {
             ResultFieldPtr aResult =
               std::dynamic_pointer_cast<ModelAPI_ResultField>(aFeature->firstResult());
-            QModelIndex aIndex = objectIndex(aResult);
+            QModelIndex aIndex = objectIndex(aResult, 0);
             removeRows(0, aResult->stepsSize(), aIndex);
         } else {
-          QModelIndex aIndex = objectIndex(aObject);
+          QModelIndex aIndex = objectIndex(aObject, 0);
           if (aIndex.isValid()) {
             emit dataChanged(aIndex, aIndex);
           }
@@ -308,7 +314,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
         // Update a sub-document
         if (aGroup == myXMLReader->subType()) {
           // Update sub-document root
-          aParent = findDocumentRootIndex(aDoc.get());
+          aParent = findDocumentRootIndex(aDoc.get(), 0);
           aStartId = foldersCount(aDoc.get());
         } else
           // update folder in sub-document
@@ -322,7 +328,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
     DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
     if (aDoc != aRootDoc) {
-      QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
+      QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get(), 0);
       if (aDocRoot.isValid())
         emit dataChanged(aDocRoot, aDocRoot);
       else
@@ -363,7 +369,7 @@ ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
 }
 
 //******************************************************
-QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
+QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject, int theColumn) const
 {
   std::string aType = theObject->groupName();
   DocumentPtr aDoc = theObject->document();
@@ -398,7 +404,7 @@ QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
     if (aRow == -1)
       return QModelIndex();
     else
-      return createIndex(aRow, 0, theObject.get());
+      return createIndex(aRow, theColumn, theObject.get());
   }
   SessionPtr aSession = ModelAPI_Session::get();
   DocumentPtr aRootDoc = aSession->moduleDocument();
@@ -409,7 +415,7 @@ QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
     // The object from sub document
     aRow += foldersCount(aDoc.get());
   }
-  return createIndex(aRow, 0, theObject.get());
+  return createIndex(aRow, theColumn, theObject.get());
 }
 
 //******************************************************
@@ -420,10 +426,26 @@ QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
   int aNbFolders = foldersCount();
   int theIndexRow = theIndex.row();
 
-  if ((theRole == Qt::DecorationRole) && (theIndex == lastHistoryIndex()))
-    return QIcon(":pictures/arrow.png");
+  if (theRole == Qt::DecorationRole) {
+    if (theIndex == lastHistoryIndex())
+      return QIcon(":pictures/arrow.png");
+    else if (theIndex.column() == 0) {
+      VisibilityState aState = getVisibilityState(theIndex);
+      switch (aState) {
+      case NoneState:
+        return QIcon();
+      case Visible:
+        return QIcon(":pictures/eyeopen.png");
+      case SemiVisible:
+        return QIcon(":pictures/eyemiclosed.png");
+      case Hidden:
+        return QIcon(":pictures/eyeclosed.png");
+      }
+    }
+  }
 
-  if (theIndex.column() == 1)
+  //if (theIndex.column() == 1)
+  if (theIndex.column() != 1)
     return QVariant();
 
   quintptr aParentId = theIndex.internalId();
@@ -596,7 +618,7 @@ int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
 //******************************************************
 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
 {
-  return 2;
+  return 3;
 }
 
 //******************************************************
@@ -616,7 +638,7 @@ QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &
       int aObjId = theRow - aNbFolders;
       if (aObjId < aRootDoc->size(aType)) {
         ObjectPtr aObj = aRootDoc->object(aType, aObjId);
-        aIndex = objectIndex(aObj);
+        aIndex = objectIndex(aObj, theColumn);
       }
     }
   } else {
@@ -626,7 +648,7 @@ QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &
       std::string aType = myXMLReader->rootFolderType(aParentPos);
       if (theRow < aRootDoc->size(aType)) {
         ObjectPtr aObj = aRootDoc->object(aType, theRow);
-        aIndex = objectIndex(aObj);
+        aIndex = objectIndex(aObj, theColumn);
       }
     } else {
       // It is an object which could have children
@@ -641,7 +663,7 @@ QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &
           std::string aType = myXMLReader->subFolderType(aParentRow);
           if (theRow < aDoc->size(aType)) {
             ObjectPtr aObj = aDoc->object(aType, theRow);
-            aIndex = objectIndex(aObj);
+            aIndex = objectIndex(aObj, theColumn);
           }
         }
       } else {
@@ -659,24 +681,24 @@ QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &
             // this is an object under sub document root
             std::string aType = myXMLReader->subType();
             ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
-            aIndex = objectIndex(aObj);
+            aIndex = objectIndex(aObj, theColumn);
           }
         } else {
           // Check for composite object
           ModelAPI_CompositeFeature* aCompFeature =
             dynamic_cast<ModelAPI_CompositeFeature*>(aParentObj);
           if (aCompFeature) {
-            aIndex = objectIndex(aCompFeature->subFeature(theRow));
+            aIndex = objectIndex(aCompFeature->subFeature(theRow), theColumn);
           } else {
             ModelAPI_ResultCompSolid* aCompRes =
               dynamic_cast<ModelAPI_ResultCompSolid*>(aParentObj);
             if (aCompRes)
-              aIndex = objectIndex(aCompRes->subResult(theRow));
+              aIndex = objectIndex(aCompRes->subResult(theRow), theColumn);
             else {
               ModelAPI_ResultField* aFieldRes =
                 dynamic_cast<ModelAPI_ResultField*>(aParentObj);
               if (aFieldRes) {
-                aIndex = createIndex(theRow, 0, aFieldRes->step(theRow));
+                aIndex = createIndex(theRow, theColumn, aFieldRes->step(theRow));
               }
             }
           }
@@ -684,8 +706,6 @@ QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &
       }
     }
   }
-  if (theColumn != 0)
-    return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
   return aIndex;
 }
 
@@ -754,7 +774,7 @@ QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
         // return first level of folder index
         int aFolderId = myXMLReader->rootFolderId(aType);
         // Items in a one row must have the same parent
-        return createIndex(aFolderId, 0, (void*)Q_NULLPTR);
+        return createIndex(aFolderId, 1, (void*)Q_NULLPTR);
       }
     } else {
       if (aType == myXMLReader->subType())
@@ -763,7 +783,7 @@ QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
         // return first level of folder index
         int aFolderId = folderId(aType, aSubDoc.get());
         // Items in a one row must have the same parent
-        return createIndex(aFolderId, 0, aSubDoc.get());
+        return createIndex(aFolderId, 1, aSubDoc.get());
       }
     }
   }
@@ -821,15 +841,15 @@ Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
   if (aObj) {
     // An object
     if (aObj->isDisabled())
-      return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
+      return theIndex.column() == 2? Qt::ItemIsSelectable : aNullFlag;
 
     if (aSession->moduleDocument() != aObj->document())
       if (aActiveDoc != aObj->document())
-        return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
+        return theIndex.column() == 2? Qt::ItemIsSelectable : aNullFlag;
 
     bool isCompositeSub = false;
-    // An object which is sub-object of a composite object can not be accessible in column 1
-    if (theIndex.column() == 1) {
+    // An object which is sub-object of a composite object can not be accessible in column 2
+    if (theIndex.column() == 2) {
       ObjectPtr aObjPtr = aObj->data()->owner();
       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObjPtr);
       if (aFeature.get()) {
@@ -866,7 +886,8 @@ Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
 }
 
 //******************************************************
-QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
+QModelIndex
+  XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc, int aColumn) const
 {
   SessionPtr aSession = ModelAPI_Session::get();
   DocumentPtr aRootDoc = aSession->moduleDocument();
@@ -882,7 +903,7 @@ QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDo
         if (myXMLReader->rootType() == ModelAPI_Feature::group()) {
           aRow += foldersCount();
         }
-        return createIndex(aRow, 0, aObj.get());
+        return createIndex(aRow, aColumn, aObj.get());
       }
     }
   } else { // If document is attached to feature
@@ -896,7 +917,7 @@ QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDo
         int aRow = i;
         if (myXMLReader->rootType() == ModelAPI_Feature::group())
           aRow += foldersCount();
-        return createIndex(aRow, 0, aObj.get());
+        return createIndex(aRow, aColumn, aObj.get());
       }
     }
   }
@@ -904,14 +925,14 @@ QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDo
 }
 
 //******************************************************
-QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
+QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc, int theColumn) const
 {
   SessionPtr aSession = ModelAPI_Session::get();
   DocumentPtr aRootDoc = aSession->moduleDocument();
   if (theDoc == aRootDoc)
     return QModelIndex();
   else
-    return findDocumentRootIndex(theDoc.get());
+    return findDocumentRootIndex(theDoc.get(), theColumn);
 }
 
 //******************************************************
@@ -994,12 +1015,12 @@ QModelIndex XGUI_DataModel::lastHistoryIndex() const
   FeaturePtr aFeature = aCurDoc->currentFeature(true);
   if (aFeature.get()) {
     QModelIndex aInd = objectIndex(aFeature);
-    return createIndex(aInd.row(), 1, aInd.internalPointer());
+    return createIndex(aInd.row(), 2, aInd.internalPointer());
   } else {
     if (aCurDoc == aSession->moduleDocument())
-      return createIndex(foldersCount() - 1, 1, -1);
+      return createIndex(foldersCount() - 1, 2, -1);
     else
-      return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
+      return createIndex(foldersCount(aCurDoc.get()) - 1, 2, aCurDoc.get());
   }
 }
 
@@ -1052,3 +1073,42 @@ void XGUI_DataModel::rebuildBranch(int theRow, int theCount, const QModelIndex&
 //  myIsEventsProcessingBlocked = theState;
 //  return aPreviousState;
 //}
+
+//******************************************************
+XGUI_DataModel::VisibilityState
+  XGUI_DataModel::getVisibilityState(const QModelIndex& theIndex) const
+{
+  Qt::ItemFlags aFlags = theIndex.flags();
+  if (aFlags == Qt::ItemFlags())
+    return NoneState;
+
+  ObjectPtr aObj = object(theIndex);
+  if (aObj.get()) {
+    ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+    if (aResObj.get()) {
+      XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+      ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResObj);
+      if (aCompRes.get()) {
+        VisibilityState aState = aCompRes->numberOfSubs(true) == 0 ?
+          (aDisplayer->isVisible(aCompRes)? Visible : Hidden) : NoneState;
+        for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
+          ResultPtr aSubRes = aCompRes->subResult(i, true);
+          VisibilityState aS = aDisplayer->isVisible(aSubRes)? Visible : Hidden;
+          if (aState == NoneState)
+            aState = aS;
+          else if (aState != aS) {
+            aState = SemiVisible;
+            break;
+          }
+        }
+        return aState;
+      } else {
+        if (aDisplayer->isVisible(aResObj))
+          return Visible;
+        else
+          return Hidden;
+      }
+    }
+  }
+  return NoneState;
+}
index 39cbd3dc44589e748707fc5eb197bfb9e2d9e784..cbcb030daf645f294010ebc9c893ed1b9e48fc30 100644 (file)
@@ -30,6 +30,7 @@
 #include <QAbstractItemModel>
 
 class Config_DataModelReader;
+class XGUI_Workshop;
 
 /**\class XGUI_DataModel
  * \ingroup GUI
@@ -63,7 +64,7 @@ public:
 
   //! Returns index of the object
   //! \param theObject object to find
-  virtual QModelIndex objectIndex(const ObjectPtr theObject) const;
+  virtual QModelIndex objectIndex(const ObjectPtr theObject, int theColumn = 1) const;
 
   //! Clear internal data
   virtual void clear();
@@ -130,7 +131,7 @@ public:
 
   /// Returns an index which is root of the given document
   /// \param theDoc a document
-  QModelIndex documentRootIndex(DocumentPtr theDoc) const;
+  QModelIndex documentRootIndex(DocumentPtr theDoc, int theColumn = 1) const;
 
   /// Returns last history object index
   virtual QModelIndex lastHistoryIndex() const;
@@ -146,9 +147,15 @@ signals:
   void treeRebuilt();
 
 private:
+  enum VisibilityState {
+    NoneState,
+    Visible,
+    SemiVisible,
+    Hidden };
+
   /// Find a root index which contains objects of the given document
   /// \param theDoc the document object
-  QModelIndex findDocumentRootIndex(const ModelAPI_Document* theDoc) const;
+  QModelIndex findDocumentRootIndex(const ModelAPI_Document* theDoc, int aColumn = 1) const;
 
   /// Returns number of folders in document.
   /// Considered folders which has to be shown only if they are not empty.
@@ -171,13 +178,15 @@ private:
   /// \param theParent - index of parent folder
   void rebuildBranch(int theRow, int theCount, const QModelIndex& theParent = QModelIndex());
 
-
   /// Returns list of folders types which can not be shown empty
   /// \param fromRoot - root document flag
   QStringList listOfShowNotEmptyFolders(bool fromRoot = true) const;
 
+  VisibilityState getVisibilityState(const QModelIndex& theIndex) const;
+
   Config_DataModelReader* myXMLReader;
 
+  XGUI_Workshop* myWorkshop;
   //bool myIsEventsProcessingBlocked;
 };
 
index 101ab27fb1c1385cbc503134db093daab314ea61..eda25f837032b3830713a6fb4b4ef37f9c6a4657 100644 (file)
 #include <QStyledItemDelegate>
 #include <QMessageBox>
 
+#ifdef DEBUG_INDXES
+#include <QToolTip>
+#endif
 
 /// Width of second column (minimum acceptable = 27)
+#define FIRST_COL_WIDTH 20
 #define SECOND_COL_WIDTH 30
 
 
@@ -81,11 +85,12 @@ XGUI_DataTree::XGUI_DataTree(QWidget* theParent)
     : QTreeView(theParent)
 {
   setHeaderHidden(true);
+  setTreePosition(1);
   setEditTriggers(QAbstractItemView::NoEditTriggers);
   setSelectionBehavior(QAbstractItemView::SelectRows);
   setSelectionMode(QAbstractItemView::ExtendedSelection);
 
-  setItemDelegateForColumn(0, new XGUI_TreeViewItemDelegate(this));
+  setItemDelegateForColumn(1, new XGUI_TreeViewItemDelegate(this));
 
   connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
     SLOT(onDoubleClick(const QModelIndex&)));
@@ -141,15 +146,46 @@ void XGUI_DataTree::resizeEvent(QResizeEvent* theEvent)
   QTreeView::resizeEvent(theEvent);
   QSize aSize = theEvent->size();
   if (aSize.isValid()) {
-    setColumnWidth(0, aSize.width() - SECOND_COL_WIDTH - 7);
-    setColumnWidth(1, SECOND_COL_WIDTH);
+    setColumnWidth(0, FIRST_COL_WIDTH);
+    setColumnWidth(1, aSize.width() - SECOND_COL_WIDTH - FIRST_COL_WIDTH - 10);
+    setColumnWidth(2, SECOND_COL_WIDTH);
   }
 }
 
-void XGUI_DataTree::onDoubleClick(const QModelIndex& theIndex)
+#ifdef DEBUG_INDXES
+void XGUI_DataTree::mousePressEvent(QMouseEvent* theEvent)
 {
-  if (theIndex.column() != 1)
+  QTreeView::mousePressEvent(theEvent);
+  if (theEvent->button() != Qt::MidButton)
     return;
+  QModelIndex aInd = indexAt(theEvent->pos());
+  QString aTxt =
+    QString("r=%1 c=%2 p=%3").arg(aInd.row()).arg(aInd.column()).arg((long)aInd.internalPointer());
+
+  QModelIndex aPar = aInd.parent();
+  QString aTxt1 =
+    QString("r=%1 c=%2 p=%3").arg(aPar.row()).arg(aPar.column()).arg((long)aPar.internalPointer());
+  QToolTip::showText(theEvent->globalPos(), aTxt + '\n' + aTxt1);
+}
+#endif
+
+void XGUI_DataTree::mouseReleaseEvent(QMouseEvent* theEvent)
+{
+  QTreeView::mouseReleaseEvent(theEvent);
+#ifdef DEBUG_INDXES
+  if (theEvent->button() != Qt::MidButton)
+    return;
+  QToolTip::hideText();
+#endif
+  if (theEvent->button() == Qt::LeftButton) {
+    QModelIndex aInd = indexAt(theEvent->pos());
+    if (aInd.column() == 0)
+      processEyeClick(aInd);
+  }
+}
+
+void XGUI_DataTree::processHistoryChange(const QModelIndex& theIndex)
+{
   SessionPtr aMgr = ModelAPI_Session::get();
   // When operation is opened then we can not change history
   if (aMgr->isOperation())
@@ -187,6 +223,36 @@ void XGUI_DataTree::onDoubleClick(const QModelIndex& theIndex)
   for (int i = 0; i < aSize; i++) {
     update(aModel->index(i, 0, aParent));
     update(aModel->index(i, 1, aParent));
+    update(aModel->index(i, 2, aParent));
+  }
+}
+
+void XGUI_DataTree::processEyeClick(const QModelIndex& theIndex)
+{
+  XGUI_DataModel* aModel = dataModel();
+  ObjectPtr aObj = aModel->object(theIndex);
+  if (aObj.get()) {
+    ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+    if (aResObj.get()) {
+      aResObj->setDisplayed(!aResObj->isDisplayed());
+      Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+      update(theIndex);
+    }
+    // Update list of selected objects because this event happens after
+    // selection event in object browser
+    XGUI_ObjectsBrowser* aObjBrowser = qobject_cast<XGUI_ObjectsBrowser*>(parent());
+    if (aObjBrowser) {
+      aObjBrowser->onSelectionChanged();
+    }
+  }
+}
+
+void XGUI_DataTree::onDoubleClick(const QModelIndex& theIndex)
+{
+  switch (theIndex.column()) {
+  case 2:
+    processHistoryChange(theIndex);
+    break;
   }
 }
 
@@ -289,8 +355,8 @@ void XGUI_ActiveDocLbl::unselect()
 //********************************************************************
 //********************************************************************
 //********************************************************************
-XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent)
-    : QWidget(theParent), myDocModel(0)
+XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent, XGUI_Workshop* theWorkshop)
+    : QWidget(theParent), myDocModel(0), myWorkshop(theWorkshop)
 {
   QVBoxLayout* aLayout = new QVBoxLayout(this);
   ModuleBase_Tools::zeroMargins(aLayout);
@@ -473,12 +539,20 @@ void XGUI_ObjectsBrowser::clearContent()
   myTreeView->clear();
 }
 
+//***************************************************
 void XGUI_ObjectsBrowser::onSelectionChanged(const QItemSelection& theSelected,
                                        const QItemSelection& theDeselected)
+{
+  onSelectionChanged();
+}
+
+//***************************************************
+void XGUI_ObjectsBrowser::onSelectionChanged()
 {
   emit selectionChanged();
 }
 
+//***************************************************
 QObjectPtrList XGUI_ObjectsBrowser::selectedObjects(QModelIndexList* theIndexes) const
 {
   QObjectPtrList aList;
@@ -486,7 +560,7 @@ QObjectPtrList XGUI_ObjectsBrowser::selectedObjects(QModelIndexList* theIndexes)
   XGUI_DataModel* aModel = dataModel();
   QModelIndexList::const_iterator aIt;
   for (aIt = aIndexes.constBegin(); aIt != aIndexes.constEnd(); ++aIt) {
-    if ((*aIt).column() == 0) {
+    if ((*aIt).column() == 1) {
       ObjectPtr aObject = aModel->object(*aIt);
       if (aObject) {
         aList.append(aObject);
@@ -517,7 +591,7 @@ std::list<bool> XGUI_ObjectsBrowser::getStateForDoc(DocumentPtr theDoc) const
   QModelIndex aRootIdx = aModel->documentRootIndex(theDoc);
   int aNbChild = aModel->rowCount(aRootIdx);
   for (int i = 0; i < aNbChild; i++) {
-    QModelIndex aIdx = aModel->index(i, 0, aRootIdx);
+    QModelIndex aIdx = aModel->index(i, 1, aRootIdx);
     aStates.push_back(myTreeView->isExpanded(aIdx));
   }
   return aStates;
index c1a9527bde13639ade41a9f18c05dfb6f2e4ca60..fd522c61a8dd253aaafc940fec2aadac2b942018 100644 (file)
@@ -34,6 +34,9 @@
 class ModuleBase_IDocumentDataModel;
 class XGUI_DataModel;
 class Config_DataModelReader;
+class XGUI_Workshop;
+
+//#define DEBUG_INDXES
 
 /**
 * \ingroup GUI
@@ -118,6 +121,22 @@ public slots:
 
    /// Redefinition of virtual method
   virtual void resizeEvent(QResizeEvent* theEvent);
+
+   /// Redefinition of virtual method
+  virtual void mouseReleaseEvent(QMouseEvent* theEvent);
+
+#ifdef DEBUG_INDXES
+  virtual void mousePressEvent(QMouseEvent* theEvent);
+#endif
+
+private:
+  /// Process a history change request
+  /// \param theIndex a clicked data index
+  void processHistoryChange(const QModelIndex& theIndex);
+
+  /// Process a visibility change request
+  /// \param theIndex a clicked data index
+  void processEyeClick(const QModelIndex& theIndex);
 };
 
 /**\class XGUI_ObjectsBrowser
@@ -130,7 +149,7 @@ Q_OBJECT
  public:
    /// Constructor
    /// \param theParent a parent widget
-  XGUI_ObjectsBrowser(QWidget* theParent);
+  XGUI_ObjectsBrowser(QWidget* theParent, XGUI_Workshop* theWorkshop);
   virtual ~XGUI_ObjectsBrowser();
 
   //! Returns Model which provides access to data objects
@@ -182,6 +201,12 @@ Q_OBJECT
   /// \param theStates list of booleans with state expanded or not
   void setStateForDoc(DocumentPtr theDoc, const std::list<bool>& theStates);
 
+  /// Returns current workshop
+  XGUI_Workshop* workshop() const { return myWorkshop; }
+
+  void onSelectionChanged();
+
+
 public slots:
   //! Called on Edit command request
   void onEditItem();
@@ -219,6 +244,7 @@ signals:
   XGUI_DataModel* myDocModel;
   XGUI_ActiveDocLbl* myActiveDocLbl;
   XGUI_DataTree* myTreeView;
+  XGUI_Workshop* myWorkshop;
 
   /// A field to store expanded items before model reset
   QModelIndexList myExpandedItems;
index ca2a26fb8d7c6b89f67e5c5664a68f0ff82a0420..0ab1b602c030fa1f7308db8e4bdd260aee1a2311 100755 (executable)
@@ -1234,7 +1234,7 @@ QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
   aObjDock->setWindowTitle(tr("Object browser"));
   aObjDock->setStyleSheet(
       "::title { position: relative; padding-left: 5px; text-align: left center }");
-  myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock);
+  myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock, this);
   myObjectBrowser->setXMLReader(myDataModelXMLReader);
   myModule->customizeObjectBrowser(myObjectBrowser);
   aObjDock->setWidget(myObjectBrowser);
@@ -1427,6 +1427,9 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
         #endif
         aParameters.Append(MyVCallBack);
 
+        MyTCommunicator->RegisterPlugin("TKDFBrowser");
+        MyTCommunicator->RegisterPlugin("TKShapeView");
+        MyTCommunicator->RegisterPlugin("TKVInspector");
         MyTCommunicator->RegisterPlugin("SMBrowser"); // custom plugin to view ModelAPI
 
         MyTCommunicator->Init(aParameters);
index 86cc1b28f73014dfab36d55da5bb68f971abe8d3..222dfd208af47fb5b1cf90f762e6f12026980708 100644 (file)
@@ -56,5 +56,9 @@
      <file>pictures/wire.png</file>
      <file>pictures/result.png</file>
      <file>pictures/find_result.png</file>
+
+     <file>pictures/eyeclosed.png</file>
+     <file>pictures/eyemiclosed.png</file>
+     <file>pictures/eyeopen.png</file>
  </qresource>
  </RCC>
diff --git a/src/XGUI/pictures/eyeclosed.png b/src/XGUI/pictures/eyeclosed.png
new file mode 100644 (file)
index 0000000..df57123
Binary files /dev/null and b/src/XGUI/pictures/eyeclosed.png differ
diff --git a/src/XGUI/pictures/eyemiclosed.png b/src/XGUI/pictures/eyemiclosed.png
new file mode 100644 (file)
index 0000000..e05e411
Binary files /dev/null and b/src/XGUI/pictures/eyemiclosed.png differ
diff --git a/src/XGUI/pictures/eyeopen.png b/src/XGUI/pictures/eyeopen.png
new file mode 100644 (file)
index 0000000..e578fe6
Binary files /dev/null and b/src/XGUI/pictures/eyeopen.png differ