Salome HOME
Preparations for Split operation. It includes:
authornds <nds@opencascade.com>
Fri, 22 Jul 2016 18:39:43 +0000 (21:39 +0300)
committernds <nds@opencascade.com>
Fri, 22 Jul 2016 18:39:43 +0000 (21:39 +0300)
1. restart operation for tangent arc (do not use send of signal, do it linear)
2. MouseProcessor interface for mouseMove/mouseRelease sketch controls
3. ModelWidget::setFeature - do not store value if the attribute is initialized(reentrant operation, tangent arc)
4. initial split

48 files changed:
CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/ModelAPI/ModelAPI_Tools.cpp
src/ModelAPI/ModelAPI_Tools.h
src/ModelGeomAlgo/CMakeLists.txt [new file with mode: 0755]
src/ModelGeomAlgo/ModelGeomAlgo.h [new file with mode: 0755]
src/ModelGeomAlgo/ModelGeomAlgo.i [new file with mode: 0755]
src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp [new file with mode: 0755]
src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h [new file with mode: 0755]
src/ModelGeomAlgo/ModelGeomAlgo_swig.h [new file with mode: 0755]
src/ModelGeomAlgo/Test/TestPoint2D.py [new file with mode: 0755]
src/ModuleBase/ModuleBase_IModule.cpp
src/ModuleBase/ModuleBase_IModule.h
src/ModuleBase/ModuleBase_IWorkshop.h
src/ModuleBase/ModuleBase_ModelWidget.cpp
src/ModuleBase/ModuleBase_Tools.cpp
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_MouseProcessor.h [new file with mode: 0755]
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherReetntrantMgr.cpp
src/PartSet/PartSet_SketcherReetntrantMgr.h
src/PartSet/PartSet_WidgetPoint2d.cpp
src/PartSet/PartSet_WidgetPoint2d.h
src/PartSet/PartSet_WidgetPoint2dDistance.cpp
src/PartSet/PartSet_WidgetPoint2dDistance.h
src/PartSet/PartSet_WidgetSketchCreator.cpp
src/PartSet/PartSet_WidgetSubShapeSelector.cpp [new file with mode: 0755]
src/PartSet/PartSet_WidgetSubShapeSelector.h [new file with mode: 0644]
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Arc.cpp
src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp [new file with mode: 0755]
src/SketchPlugin/SketchPlugin_ConstraintSplit.h [new file with mode: 0755]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/SketchPlugin_msg_en.ts
src/SketchPlugin/plugin-Sketch.xml
src/SketcherPrs/CMakeLists.txt
src/SketcherPrs/SketcherPrs_Tools.cpp
src/XGUI/XGUI_ModuleConnector.cpp
src/XGUI/XGUI_ModuleConnector.h
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_OperationMgr.h
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_Workshop.h

index b24566bcb43c9e442d11299ec41ec8d3c6c412e0..cdc22d0712ab897a1581fa74d75d20c7a510acc5 100644 (file)
@@ -86,6 +86,7 @@ ADD_SUBDIRECTORY (src/Model)
 ADD_SUBDIRECTORY (src/XAO)
 ADD_SUBDIRECTORY (src/GeomAPI)
 ADD_SUBDIRECTORY (src/ModelAPI)
+ADD_SUBDIRECTORY (src/ModelGeomAlgo)
 ADD_SUBDIRECTORY (src/GeomAlgoAPI)
 ADD_SUBDIRECTORY (src/GeomAlgoImpl)
 ADD_SUBDIRECTORY (src/GeomData)
index a40aff14e34b60c4ceae641285ee1753fab8c3cd..6fa8f4b3167757d7731e7ecfa05c87175d513841 100644 (file)
 #include <TopoDS_Vertex.hxx>
 #include <TopoDS.hxx>
 #include <TopExp_Explorer.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+
+#include <BOPAlgo_Builder.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <TopoDS_Edge.hxx>
 
 //==================================================================================================
 double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
@@ -663,3 +668,34 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theE
   BRepExtrema_ExtCF anExt(anEdge, aFace);
   return anExt.IsParallel() == Standard_True;
 }
+
+//==================================================================================================
+void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
+                                        const std::set<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
+                                        std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
+{
+  // General Fuse to split edge by vertices
+  BOPAlgo_Builder aBOP;
+  const TopoDS_Edge& aBaseEdge = theBaseShape->impl<TopoDS_Edge>();
+  aBOP.AddArgument(aBaseEdge);
+
+  std::set<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPtIt = thePoints.begin();
+  for (; aPtIt != thePoints.end(); ++aPtIt) {
+    std::shared_ptr<GeomAPI_Pnt> aPnt = *aPtIt;
+    TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z()));
+    aBOP.AddArgument(aV);
+  }
+
+  aBOP.Perform();
+  if (aBOP.ErrorStatus())
+    return;
+  
+  // Collect splits
+  const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge);
+  TopTools_ListIteratorOfListOfShape anIt(aSplits);
+  for (; anIt.More(); anIt.Next()) {
+    std::shared_ptr<GeomAPI_Shape> anEdge(new GeomAPI_Shape);
+    anEdge->setImpl(new TopoDS_Shape(anIt.Value()));
+    theShapes.insert(anEdge);
+  }
+}
index 95a97f0bbaef960234118ff5a60af6565a3a5a08..6a1da0e237e0b928c7c83359714a935b12c6cdab 100644 (file)
@@ -12,6 +12,8 @@
 #include <GeomAPI_Shape.h>
 #include <GeomAPI_Vertex.h>
 
+#include <set>
+
 class GeomAPI_Edge;
 class GeomAPI_Dir;
 class GeomAPI_Face;
@@ -102,6 +104,13 @@ public:
   /// \return true if edge is parallel to face.
   GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
                                             const std::shared_ptr<GeomAPI_Face> theFace);
+  /// \brief Performs the split of the shape by points.
+  /// \param[in] theBaseShape shape that should be splitted.
+  /// \param[in] thePoints container of points to split
+  /// \param[out] theShapes container of shapes after split
+  GEOMALGOAPI_EXPORT static void splitShape(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
+                                            const std::set<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
+                                            std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes);
 };
 
 #endif
index 7a7bbecb7f9ada529aadb71326638d8593217f46..74a33d36641923cb211dbfe1bb116a83d0768daf 100755 (executable)
@@ -89,6 +89,20 @@ std::shared_ptr<GeomAPI_Shape> shape(const ResultPtr& theResult)
   return theResult->shape();
 }
 
+void shapesOfType(const FeaturePtr& theFeature,
+                  const GeomAPI_Shape::ShapeType& theType,
+                  std::set<GeomShapePtr>& theShapes)
+{
+  std::list<ResultPtr> aResults = theFeature->results();
+  std::list<ResultPtr>::const_iterator aRIter = aResults.cbegin();
+  for (; aRIter != aResults.cend(); aRIter++) {
+    ResultPtr aResult = *aRIter;
+    GeomShapePtr aShape = aResult->shape();
+    if (aShape.get() && aShape->shapeType() == theType)
+      theShapes.insert(aShape);
+  }
+}
+
 const char* toString(ModelAPI_ExecState theExecState) 
 {
 #define TO_STRING(__NAME__) case __NAME__: return #__NAME__;
index 00f6cd4fd570611ac0d997cd911bbdf913e5a273..14f0288237bfd319ef1a1a36bdac5b41d7e83843 100755 (executable)
@@ -26,6 +26,14 @@ namespace ModelAPI_Tools {
 /// Returns shape from the given Result object
 MODELAPI_EXPORT std::shared_ptr<GeomAPI_Shape> shape(const ResultPtr& theResult);
 
+/// Creates a container of shape of the feature results satisfied the given shape type
+/// \param theFeature a source feature
+/// \param theType shape type
+/// \param an output container for shapes
+MODELAPI_EXPORT void shapesOfType(const FeaturePtr& theFeature,
+                                  const GeomAPI_Shape::ShapeType& theType,
+                                  std::set<GeomShapePtr>& theShapes);
+
 /*! Returns the feature error generated according to feature error and exec state
  * \param theFeature a feature
  * \return error value or empty string
diff --git a/src/ModelGeomAlgo/CMakeLists.txt b/src/ModelGeomAlgo/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..3d4a480
--- /dev/null
@@ -0,0 +1,68 @@
+## Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+FIND_PACKAGE(SWIG REQUIRED)
+INCLUDE(${SWIG_USE_FILE})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+INCLUDE(UnitTest)
+
+SET(PROJECT_HEADERS
+    ModelGeomAlgo.h
+    ModelGeomAlgo_Point2D.h
+)
+
+SET(PROJECT_SOURCES
+    ModelGeomAlgo_Point2D.cpp
+)
+
+SET(PROJECT_LIBRARIES
+    Config
+    GeomAPI
+    GeomDataAPI
+    GeomAlgoAPI
+    ModelAPI
+)
+
+SET(CMAKE_SWIG_FLAGS -threads -Wall)
+ADD_DEFINITIONS(-DMODELGEOMALGO_EXPORTS)
+
+ADD_LIBRARY(ModelGeomAlgo SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
+SET_TARGET_PROPERTIES(ModelGeomAlgo PROPERTIES LINKER_LANGUAGE CXX)
+TARGET_LINK_LIBRARIES(ModelGeomAlgo ${PROJECT_LIBRARIES})
+
+INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Config
+                    ${PROJECT_SOURCE_DIR}/src/Events
+                    ${PROJECT_SOURCE_DIR}/src/GeomAPI
+                    ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
+                    ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
+                    ${PROJECT_SOURCE_DIR}/src/ModelAPI
+)
+
+
+SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgo.i PROPERTIES CPLUSPLUS ON)
+# "-includeall" is not needed: it starts to follow the standard inludes (like "string") without success
+# SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgo.i PROPERTIES SWIG_FLAGS)
+SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgo.i PROPERTIES SWIG_DEFINITIONS "-shadow")
+#SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgoPYTHON_wrap.cxx PROPERTIES COMPILE_FLAGS "-D_WIN32")
+
+SET(SWIG_SCRIPTS
+  ${CMAKE_CURRENT_BINARY_DIR}/ModelGeomAlgo.py
+)
+
+SET(SWIG_LINK_LIBRARIES
+  ModelGeomAlgo
+  GeomAPI
+  ${PYTHON_LIBRARIES}
+)
+
+SWIG_ADD_MODULE(ModelGeomAlgo python ModelGeomAlgo.i ${PROJECT_HEADERS})
+SWIG_LINK_LIBRARIES(ModelGeomAlgo ${SWIG_LINK_LIBRARIES})
+
+IF(WIN32)
+  SET_TARGET_PROPERTIES(_ModelGeomAlgo PROPERTIES DEBUG_OUTPUT_NAME _ModelGeomAlgo_d)
+ENDIF(WIN32)
+
+INSTALL(TARGETS _ModelGeomAlgo DESTINATION ${SHAPER_INSTALL_SWIG})
+INSTALL(TARGETS ModelGeomAlgo DESTINATION ${SHAPER_INSTALL_BIN})
+INSTALL(FILES ${SWIG_SCRIPTS} DESTINATION ${SHAPER_INSTALL_SWIG})
+
+ADD_UNIT_TESTS(TestPoint2D.py)
diff --git a/src/ModelGeomAlgo/ModelGeomAlgo.h b/src/ModelGeomAlgo/ModelGeomAlgo.h
new file mode 100755 (executable)
index 0000000..4121ef7
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+#ifndef MODELGEOMALGO_H
+#define MODELGEOMALGO_H
+
+#if defined MODELGEOMALGO_EXPORTS
+#if defined WIN32
+#define MODELGEOMALGO_EXPORT              __declspec( dllexport )
+#else
+#define MODELGEOMALGO_EXPORT
+#endif
+#else
+#if defined WIN32
+#define MODELGEOMALGO_EXPORT              __declspec( dllimport )
+#else
+#define MODELGEOMALGO_EXPORT
+#endif
+#endif
+
+#endif
diff --git a/src/ModelGeomAlgo/ModelGeomAlgo.i b/src/ModelGeomAlgo/ModelGeomAlgo.i
new file mode 100755 (executable)
index 0000000..93438c9
--- /dev/null
@@ -0,0 +1,37 @@
+/* ModelAPI.i */
+%module(directors="1") ModelGeomAlgo
+%feature("director:except") {
+    if ($error != NULL) {
+      PyErr_Print();
+      std::cerr << std::endl;
+      throw Swig::DirectorMethodException();
+    }
+}
+
+%{
+  #include "ModelGeomAlgo_swig.h"
+%}
+
+// import other modules
+%import "GeomAPI.i"
+%import "GeomDataAPI.i"
+%import "ModelAPI.i"
+
+
+// to avoid error on this
+#define MODELGEOMALGO_EXPORT
+
+// standard definitions
+%include "typemaps.i"
+%include "std_string.i"
+%include "std_list.i"
+%include "std_shared_ptr.i"
+%include "std_set.i"
+
+// shared pointers
+// For Point2D.method()
+%shared_ptr(ModelAPI_Point2D)
+
+// all supported interfaces
+%include "ModelGeomAlgo_Point2D.h"
+
diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp
new file mode 100755 (executable)
index 0000000..adaf459
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        ModelAPI_Tools.cpp
+// Created:     20 Jul 2016
+// Author:      Natalia ERMOLAEVA
+
+#include "ModelGeomAlgo_Point2D.h"
+
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_AttributeRefAttr.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Vertex.h>
+#include <GeomAPI_Dir.h>
+
+namespace ModelGeomAlgo_Point2D {
+  std::shared_ptr<GeomDataAPI_Point2D> getPointOfRefAttr(ModelAPI_Feature* theFeature,
+                                                         const std::string& theAttribute,
+                                                         const std::string& theObjectFeatureKind,
+                                                         const std::string& theObjectFeatureAttribute)
+  {
+    std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
+
+    /// essential check as it is called in openGl thread
+    if (!theFeature || !theFeature->data().get() || !theFeature->data()->isValid())
+      return std::shared_ptr<GeomDataAPI_Point2D>();
+
+    FeaturePtr aFeature;
+    std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
+        ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
+    if(!anAttr.get()) {
+      return std::shared_ptr<GeomDataAPI_Point2D>();
+    }
+    aFeature = ModelAPI_Feature::feature(anAttr->object());
+
+    bool aFeatureOfObjectKind = !theObjectFeatureKind.empty() &&
+                                !theObjectFeatureAttribute.empty() &&
+                                aFeature->getKind() == theObjectFeatureKind;
+    if (aFeature.get() && aFeatureOfObjectKind)
+        aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                aFeature->data()->attribute(theObjectFeatureAttribute));
+    else if (anAttr->attr())
+      aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+
+    return aPointAttr;
+  }
+
+  void getPointsOfReference(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                            const std::string& theReferenceFeatureKind,
+                            std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
+                            const std::string& theObjectFeatureKind,
+                            const std::string& theObjectFeatureAttribute)
+  {
+    const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
+    std::set<AttributePtr>::const_iterator aIt;
+    for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
+      std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
+      FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+      if (aRefFeature->getKind() == theReferenceFeatureKind) {
+        std::list<AttributePtr> anAttributes =
+                         theFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+        std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+        // it searches the first point of AttributeRefAtt
+        std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
+        for(; anIter != anAttributes.end() && !aPointAttr.get(); anIter++) {
+          AttributeRefAttrPtr aRefAttribute =
+            std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+          if (aRefAttribute.get())
+            aPointAttr = getPointOfRefAttr(aRefFeature.get(), aRefAttribute->id(),
+                                           theObjectFeatureKind, theObjectFeatureAttribute);
+        }
+        if (aPointAttr.get()) {
+          theAttributes.insert(aPointAttr);
+        }
+      }
+    }
+  }
+
+  void getPointsInsideShape(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
+                            const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
+                            const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
+                            const std::shared_ptr<GeomAPI_Dir>& theDirX,
+                            const std::shared_ptr<GeomAPI_Dir>& theDirY,
+                            std::set<std::shared_ptr<GeomAPI_Pnt> >& thePoints)
+  {
+    std::set<std::shared_ptr<GeomDataAPI_Point2D> >::const_iterator anIt = theAttributes.begin(),
+                                                            aLast = theAttributes.end();
+    for (; anIt != aLast; anIt++) {
+      std::shared_ptr<GeomDataAPI_Point2D> anAttribute = *anIt;
+      std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = anAttribute->pnt();
+      std::shared_ptr<GeomAPI_Pnt> aPnt = aPnt2d->to3D(theOrigin, theDirX, theDirY);
+      std::shared_ptr<GeomAPI_Vertex> aVertexShape(new GeomAPI_Vertex(aPnt->x(), aPnt->y(), aPnt->z()));
+      if (GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aVertexShape, theBaseShape))
+        thePoints.insert(aPnt);
+    }
+  }
+
+
+} // namespace ModelGeomAlgo_Point2D
diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h
new file mode 100755 (executable)
index 0000000..b79aaff
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        ModelGeomAlgo_Point2D.h
+// Created:     20 Jul 2016
+// Author:      Natalia ERMOLAEVA
+
+#ifndef ModelGeomAlgo_Point2D_H
+#define ModelGeomAlgo_Point2D_H
+
+#include "ModelGeomAlgo.h"
+
+class ModelAPI_Feature;
+class GeomAPI_Shape;
+class GeomAPI_Pnt;
+class GeomAPI_Dir;
+
+class GeomDataAPI_Point2D;
+
+#include <memory>
+#include <set>
+
+
+namespace ModelGeomAlgo_Point2D {
+
+  /// Searches Point2D attribute of reference of the attribute of given feature
+  /// \param theFeature a feature to obtain AttributeRefAttr
+  /// \param theAttribute a name of AttributeRefAttr on the given feature
+  /// \param theObjectFeatureKind a feature kind in object of attribute that satisfies the search
+  /// \param theObjectFeatureAttribute a feature attribute in object that satisfies the search
+  /// \returns found point attribute or NULL
+  MODELGEOMALGO_EXPORT std::shared_ptr<GeomDataAPI_Point2D> getPointOfRefAttr(
+                                                ModelAPI_Feature* theFeature,
+                                                const std::string& theAttribute,
+                                                const std::string& theObjectFeatureKind = "",
+                                                const std::string& theObjectFeatureAttribute = "");
+
+  /// Fills container of point 2D attributes, which refer to the feature through the references
+  /// features with the given kind
+  /// \param theFeature a feature where references should be searched (e.g. a sketch line)
+  /// \param theReferenceFeatureKind a kind of the feature to be processed (e.g. coincidence constraint)
+  /// \param theAttributes a container of found point 2D attributes
+  /// \param theObjectFeatureKind a feature kind in object of attribute that satisfies the search
+  /// \param theObjectFeatureAttribute a feature attribute in object that satisfies the search
+  /// \returns found point attribute or NULL
+  MODELGEOMALGO_EXPORT void getPointsOfReference(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                          const std::string& theReferenceFeatureKind,
+                                          std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
+                                          const std::string& theObjectFeatureKind = "",
+                                          const std::string& theObjectFeatureAttribute = "");
+
+  /// Removes attributes which points are out of the base shape
+  /// \param theBaseShape a shape of check
+  /// \param theAttributes a container of point 2D attributes
+  /// \param theOrigin origin of a plane to generate 3D point by 2D attribute point
+  /// \param theDirX plane X direction to generate 3D point by 2D attribute point
+  /// \param theDirY plane X direction to generate 3D point by 2D attribute point
+  /// \param thePoints a container of 3D points belong to the shape
+  MODELGEOMALGO_EXPORT void getPointsInsideShape(
+                              const std::shared_ptr<GeomAPI_Shape> theBaseShape,
+                              const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
+                              const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
+                              const std::shared_ptr<GeomAPI_Dir>& theDirX,
+                              const std::shared_ptr<GeomAPI_Dir>& theDirY,
+                              std::set<std::shared_ptr<GeomAPI_Pnt> >& thePoints);
+}
+
+#endif
diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_swig.h b/src/ModelGeomAlgo/ModelGeomAlgo_swig.h
new file mode 100755 (executable)
index 0000000..c5522dc
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    ModelAPI_swig.h
+// Created: Jul 20, 2016
+// Author:  Natalia ERMOLAEVA
+
+#ifndef SRC_MODELGEOMALGO_MODELGEOMALGO_SWIG_H_
+#define SRC_MODELGEOMALGO_MODELGEOMALGO_SWIG_H_
+
+  #include <GeomAPI_swig.h>
+  #include <ModelAPI_swig.h>
+  #include <GeomDataAPI_swig.h>
+
+  #include "ModelGeomAlgo.h"
+  #include "ModelGeomAlgo_Point2D.h"
+
+  #include <memory>
+  #include <string>
+
+#endif /* SRC_MODELGEOMALGO_MODELGEOMALGO_SWIG_H_ */
diff --git a/src/ModelGeomAlgo/Test/TestPoint2D.py b/src/ModelGeomAlgo/Test/TestPoint2D.py
new file mode 100755 (executable)
index 0000000..c0344ea
--- /dev/null
@@ -0,0 +1,17 @@
+"""
+      TestPoint2D.py
+      Unit test for testing the Point2D algorithms
+
+"""
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from ModelAPI import *
+from GeomDataAPI import *
+from GeomAlgoAPI import *
+from GeomAPI import *
+from ModelGeomAlgo import *
+
+__updated__ = "2016-07-20"
+
+aSession = ModelAPI_Session.get()
index a41824958fb45b5735dd4146ce14a2de924df9ac..424260dcb89d5921991948e06550a0c22b040d30 100644 (file)
@@ -69,8 +69,7 @@ void ModuleBase_IModule::launchModal(const QString& theCmdId)
 }
 
 
-void ModuleBase_IModule::launchOperation(const QString& theCmdId,
-                                         const bool isUpdatePropertyPanel)
+void ModuleBase_IModule::launchOperation(const QString& theCmdId)
 {
   if (!myWorkshop->canStartOperation(theCmdId))
     return;
@@ -81,17 +80,10 @@ void ModuleBase_IModule::launchOperation(const QString& theCmdId,
     ModuleBase_ISelection* aSelection = myWorkshop->selection();
     // Initialise operation with preliminary selection
     aFOperation->initSelection(aSelection, myWorkshop->viewer());
-    sendOperation(aFOperation, isUpdatePropertyPanel);
+    workshop()->processLaunchOperation(aFOperation);
   }
 }
 
-
-void ModuleBase_IModule::sendOperation(ModuleBase_Operation* theOperation,
-                                       const bool isUpdatePropertyPanel)
-{
-  workshop()->processLaunchOperation(theOperation, isUpdatePropertyPanel);
-}
-
 Handle(AIS_InteractiveObject) ModuleBase_IModule::createPresentation(const ResultPtr& theResult)
 {
   return Handle(AIS_InteractiveObject)();
@@ -225,7 +217,7 @@ void ModuleBase_IModule::editFeature(FeaturePtr theFeature)
                                                          (createOperation(aFeatureId));
   if (aFOperation) {
     aFOperation->setFeature(theFeature);
-    sendOperation(aFOperation);
+    workshop()->processLaunchOperation(aFOperation);
   }
 }
 
index ad8132e4ac212d4367dc8fdab50f80e94df4f7ea..e0937f09e21e600298048c02dfd1cd71fe38d697 100755 (executable)
@@ -82,8 +82,7 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
 \r
   /// Creates an operation and send it to loop\r
   /// \param theCmdId the operation name\r
-  /// \param isUpdatePropertyPanel if false, the property panel filling might be postponed\r
-  virtual void launchOperation(const QString& theCmdId, const bool isUpdatePropertyPanel = true);\r
+  virtual void launchOperation(const QString& theCmdId);\r
 \r
   /// Executes feature as a modal dialog box\r
   /// \param theCmdId the operation name\r
@@ -239,11 +238,6 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
   /// \param theCmdId the operation name\r
   virtual ModuleBase_Operation* createOperation(const std::string& theCmdId);\r
 \r
-  /// Sends the operation for launching\r
-  /// \param theOperation the operation\r
-  /// \param isUpdatePropertyPanel if false, the property panel filling might be postponed\r
-  virtual void sendOperation(ModuleBase_Operation* theOperation, const bool isUpdatePropertyPanel = true);\r
-\r
   /// Create specific for the module presentation\r
   /// \param theResult an object for presentation\r
   /// \return created presentation or NULL(default value)\r
@@ -292,10 +286,6 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
   /// \param thePreviousAttributeID an index of the previous active attribute\r
   virtual bool processEnter(const std::string& thePreviousAttributeID) { return false; };\r
 \r
-  /// Performs some GUI actions after an operation transaction is opened\r
-  /// Default realization is empty\r
-  virtual void beforeOperationStarted(ModuleBase_Operation* theOperation) {};\r
-\r
   /// Performs some GUI actions before an operation transaction is stopped\r
   /// Default realization is empty\r
   virtual void beforeOperationStopped(ModuleBase_Operation* theOperation) {};\r
index 432b5accd1227e9d015adcbfafd46c94ed86e946..5588ef63c044a4847b1549242a94f97bbebd6349 100644 (file)
@@ -78,7 +78,7 @@ Q_OBJECT
 
   //! Performs the operation launch
   //! \param theOperation an operation to be launched
-  virtual void processLaunchOperation(ModuleBase_Operation* theOperation, const bool isUpdatePropertyPanel) = 0;
+  virtual void processLaunchOperation(ModuleBase_Operation* theOperation) = 0;
 
   //! Returns started operation by the operation identifier
   //! \param theId an operation id
index 4420aff9a2e0e307c93798f40347a159d14db341..77d58959b1bd322e45e6c5b51ae41e5309c3e09a 100644 (file)
@@ -209,8 +209,13 @@ void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool
   /// after debug, it may be corrected
   myFlushUpdateBlocked = !isUpdateFlushed;
   myFeature = theFeature;
-  if (theToStoreValue)
-    storeValue();
+  if (theToStoreValue) {
+    /// it is possible that the attribute is filled before the operation is started,
+    /// e.g. by reentrant operation case some attributes are filled by values of
+    /// feature of previous operation, we should not lost them here
+    if (!theFeature->data()->attribute(attributeID())->isInitialized())
+      storeValue();
+  }
   myFlushUpdateBlocked = false;
 }
 
index 8f184df155f3ba01f7675709bc66f802ddfae800..305d2dfd1a8c5af1f3996482a4c2b4ac81494b27 100755 (executable)
 #include <sstream>
 #include <string>
 
+#ifdef WIN32
+#pragma warning(disable : 4996) // for getenv
+#endif
+
 const double tolerance = 1e-7;
 const double DEFAULT_DEVIATION_COEFFICIENT = 1.e-4;
 
index e0d363f525e93cbb8a565912d5d24b134cddad6e..f237ce295b7ab9a749444b6f97881e6c25713cde 100644 (file)
@@ -10,6 +10,7 @@ SET(PROJECT_HEADERS
        PartSet_CustomPrs.h
        PartSet_ExternalObjectsMgr.h
        PartSet_Module.h
+       PartSet_MouseProcessor.h
        PartSet_OperationPrs.h
         PartSet_OverconstraintListener.h
         PartSet_PreviewPlanes.h
@@ -32,6 +33,7 @@ SET(PROJECT_HEADERS
        PartSet_WidgetSketchCreator.h
        PartSet_IconFactory.h
        PartSet_WidgetChoice.h
+       PartSet_WidgetSubShapeSelector.h
 )
 
 SET(PROJECT_SOURCES
@@ -59,6 +61,7 @@ SET(PROJECT_SOURCES
        PartSet_MenuMgr.cpp
        PartSet_WidgetSketchCreator.cpp
        PartSet_IconFactory.cpp
+       PartSet_WidgetSubShapeSelector.cpp
 )
 
 SET(PROJECT_RESOURCES
@@ -71,10 +74,11 @@ SET(PROJECT_RESOURCES
 
 SET(PROJECT_LIBRARIES
     ModuleBase
+    ModelGeomAlgo
     Config
     GeomAPI
     GeomDataAPI
-       SketcherPrs
+    SketcherPrs
     ${QT_LIBRARIES}
     ${CAS_KERNEL}
     ${CAS_SHAPE}
@@ -102,6 +106,7 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/XGUI
                     ${PROJECT_SOURCE_DIR}/src/Events
                     ${PROJECT_SOURCE_DIR}/src/ModuleBase
                     ${PROJECT_SOURCE_DIR}/src/ModelAPI
+                    ${PROJECT_SOURCE_DIR}/src/ModelGeomAlgo
                     ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
                     ${PROJECT_SOURCE_DIR}/src/SketchPlugin
index 7f8367528bca7d198a240a322e25a06e8536e304..6ca6ad71378299313ef088e60b603845bb97b583 100755 (executable)
@@ -283,97 +283,98 @@ void PartSet_Module::operationAborted(ModuleBase_Operation* theOperation)
 
 void PartSet_Module::operationStarted(ModuleBase_Operation* theOperation)
 {
-  ModuleBase_IWorkshop* anIWorkshop = workshop();
-  if (!theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
-    anIWorkshop->updateCommandStatus();
-  }
-  else {
-    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                                                 (theOperation);
-    if (aFOperation) {
-      XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(anIWorkshop);
-      XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
-      ModuleBase_ModelWidget* aFilledWidget = 0;
-      bool aPostonedWidgetActivation = false;
-      FeaturePtr aFeature = aFOperation->feature();
-
-      std::string aGreedAttributeId = ModuleBase_Tools::findGreedAttribute(anIWorkshop, aFeature);
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                                (theOperation);
+  if (aFOperation) {
+    XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(workshop());
+    XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
+
+    ModuleBase_ModelWidget* aFilledWidget = 0;
+    bool aPostonedWidgetActivation = false;
+
+    FeaturePtr aFeature = aFOperation->feature();
+    /// Restart sketcher operations automatically
+    /// it is important to call method of sketch reentrant manager before filling of PP
+    /// because it fills some created feature attributes, these new values should be used
+    /// to fill the property panel
+    mySketchReentrantMgr->operationStarted(theOperation);
+
+    aWorkshop->fillPropertyPanel(aFOperation);
+    // filling the operation values by the current selection
+    // if the operation can be committed after the controls filling, the method perform should
+    // be stopped. Otherwise unnecessary presentations can be shown(e.g. operation prs in sketch)
+    bool isOperationCommitted = false;
+    if (!aFOperation->isEditOperation()) {
+      std::string aGreedAttributeId = ModuleBase_Tools::findGreedAttribute(workshop(), aFeature);
       // if there is a greed attribute, automatic commit by preselection for this feature is prohibited
-      aWorkshop->setPropertyPanel(aFOperation);
-
-      // filling the operation values by the current selection
-      // if the operation can be committed after the controls filling, the method perform should
-      // be stopped. Otherwise unnecessary presentations can be shown(e.g. operation prs in sketch)
-      bool isOperationCommitted = false;
-      if (!aFOperation->isEditOperation()) {
-        aFilledWidget = aFOperation->activateByPreselection(aGreedAttributeId);
-        if (currentOperation() != aFOperation)
-          isOperationCommitted = true;
-        else {
-          if (aGreedAttributeId.empty()) {
-            // a signal should be emitted before the next widget activation
-            // because, the activation of the next widget will give a focus to the widget. As a result
-            // the value of the widget is initialized. And commit may happens until the value is entered.
-            if (aFilledWidget) {
-              if (mySketchReentrantMgr->canBeCommittedByPreselection())
-                isOperationCommitted = mySketchMgr->operationActivatedByPreselection();
-              // activate the next obligatory widget
-              if (!isOperationCommitted)
-                aPropertyPanel->activateNextWidget(aFilledWidget);
-            }
+      aFilledWidget = aFOperation->activateByPreselection(aGreedAttributeId);
+      if (currentOperation() != aFOperation)
+        isOperationCommitted = true;
+      else {
+        if (aGreedAttributeId.empty()) {
+          // a signal should be emitted before the next widget activation
+          // because, the activation of the next widget will give a focus to the widget. As a result
+          // the value of the widget is initialized. And commit may happens until the value is entered.
+          if (aFilledWidget) {
+            if (mySketchReentrantMgr->canBeCommittedByPreselection())
+              isOperationCommitted = mySketchMgr->operationActivatedByPreselection();
+            // activate the next obligatory widget
+            if (!isOperationCommitted)
+              aPropertyPanel->activateNextWidget(aFilledWidget);
           }
-          else { // there is a greed widget
-            const QList<ModuleBase_ModelWidget*>& aWidgets = aPropertyPanel->modelWidgets();
-            std::string aFirstAttributeId = aWidgets.front()->attributeID();
-            // activate next widget after greeded if it is the first widget in the panel
-            // else the first panel widget is already activated by operation start
-            if (aFirstAttributeId == aGreedAttributeId)
-              aPostonedWidgetActivation = true;
-          }
-        }
-      } if (!isOperationCommitted) {
-        anIWorkshop->updateCommandStatus();
-        aWorkshop->connectToPropertyPanel(true);
-        operationStartedInternal(aFOperation);
-
-        // the objects of the current operation should be deactivated
-        QObjectPtrList anObjects;
-        anObjects.append(aFeature);
-        std::list<ResultPtr> aResults;
-        ModelAPI_Tools::allResults(aFeature, aResults);
-        std::list<ResultPtr>::const_iterator aIt;
-        for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
-          anObjects.append(*aIt);
         }
-        QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
-        for (; anIt != aLast; anIt++)
-          aWorkshop->deactivateActiveObject(*anIt, false);
-        if (anObjects.size() > 0) {
-          XGUI_Displayer* aDisplayer = aWorkshop->displayer();
-          aDisplayer->updateViewer();
+        else { // there is a greed widget
+          const QList<ModuleBase_ModelWidget*>& aWidgets = aPropertyPanel->modelWidgets();
+          std::string aFirstAttributeId = aWidgets.front()->attributeID();
+          // activate next widget after greeded if it is the first widget in the panel
+          // else the first panel widget is already activated by operation start
+          if (aFirstAttributeId == aGreedAttributeId)
+            aPostonedWidgetActivation = true;
         }
       }
-      if (aPostonedWidgetActivation) {
-        // if the widget is an empty in the chain of activated widgets, the current operation
-        // is restarted. It should be performed after functionality of the operation starting
-        aPropertyPanel->activateNextWidget(aFilledWidget);
+    } if (!isOperationCommitted) {
+      workshop()->updateCommandStatus();
+      aWorkshop->connectToPropertyPanel(true);
+      updateSketcherOnStart(aFOperation);
+      updatePresentationsOnStart(aFOperation);
+
+      // the objects of the current operation should be deactivated
+      QObjectPtrList anObjects;
+      anObjects.append(aFeature);
+      std::list<ResultPtr> aResults;
+      ModelAPI_Tools::allResults(aFeature, aResults);
+      std::list<ResultPtr>::const_iterator aIt;
+      for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
+        anObjects.append(*aIt);
       }
+      QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
+      for (; anIt != aLast; anIt++)
+        aWorkshop->deactivateActiveObject(*anIt, false);
+      if (anObjects.size() > 0) {
+        XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+        aDisplayer->updateViewer();
+      }
+    }
+    if (aPostonedWidgetActivation) {
+      // if the widget is an empty in the chain of activated widgets, the current operation
+      // is restarted. It should be performed after functionality of the operation starting
+      aPropertyPanel->activateNextWidget(aFilledWidget);
     }
   }
 }
 
-void PartSet_Module::operationStartedInternal(ModuleBase_Operation* theOperation)
+void PartSet_Module::updateSketcherOnStart(ModuleBase_Operation* theOperation)
 {
-  /// Restart sketcher operations automatically
-  mySketchReentrantMgr->operationStarted(theOperation);
-
   if (PartSet_SketcherMgr::isSketchOperation(theOperation)) {
     mySketchMgr->startSketch(theOperation);
   }
   else if (PartSet_SketcherMgr::isNestedSketchOperation(theOperation)) {
     mySketchMgr->startNestedSketch(theOperation);
   }
+}
 
+void PartSet_Module::updatePresentationsOnStart(ModuleBase_Operation* theOperation)
+{
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
   if (aFOperation) {
     myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeArguments, true);
@@ -854,14 +855,13 @@ bool PartSet_Module::canCommitOperation() const
   return true;
 }
 
-void PartSet_Module::launchOperation(const QString& theCmdId,
-                                     const bool isUpdatePropertyPanel)
+void PartSet_Module::launchOperation(const QString& theCmdId)
 {
   myIsOperationIsLaunched = true;
   storeConstraintsState(theCmdId.toStdString());
   updateConstraintsState(theCmdId.toStdString());
 
-  ModuleBase_IModule::launchOperation(theCmdId, isUpdatePropertyPanel);
+  ModuleBase_IModule::launchOperation(theCmdId);
 
   myIsOperationIsLaunched = false;
 }
@@ -1299,11 +1299,6 @@ bool PartSet_Module::processEnter(const std::string& thePreviousAttributeID)
   return mySketchReentrantMgr->processEnter(thePreviousAttributeID);
 }
 
-//******************************************************
-void PartSet_Module::beforeOperationStarted(ModuleBase_Operation* theOperation)
-{
-}
-
 //******************************************************
 void PartSet_Module::beforeOperationStopped(ModuleBase_Operation* theOperation)
 {
index 0ad602e0c62a9786fd6a2146584a14817bd12455..014790aa4d016eeebf2086739735c62c82436172 100755 (executable)
@@ -102,8 +102,7 @@ public:
 
   /// Creates an operation and send it to loop
   /// \param theCmdId the operation name
-  /// \param isUpdatePropertyPanel if false, the property panel filling might be postponed
-  virtual void launchOperation(const QString& theCmdId, const bool isUpdatePropertyPanel = true);
+  virtual void launchOperation(const QString& theCmdId);
 
   /// Realizes some functionality by an operation start
   /// Displays all sketcher sub-Objects, hides sketcher result, appends selection filters
@@ -303,10 +302,6 @@ public:
   /// \param thePreviousAttributeID an index of the previous active attribute
   virtual bool processEnter(const std::string& thePreviousAttributeID);
 
-  /// Performs some GUI actions after an operation transaction is opened
-  /// Default realization is empty
-  virtual void beforeOperationStarted(ModuleBase_Operation* theOperation);
-
   /// Performs some GUI actions before an operation transaction is stopped
   /// Default realization is empty
   virtual void beforeOperationStopped(ModuleBase_Operation* theOperation);
@@ -385,11 +380,13 @@ protected:
   /// \param isToConnect a boolean value whether connect or disconnect
   virtual void connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect);
 
-  /// Realizes some functionality by an operation start
-  /// Displays all sketcher sub-Objects, hides sketcher result, appends selection filters
-  /// Activate the operation presentation
-  /// \param theOperation a started operation
-  virtual void operationStartedInternal(ModuleBase_Operation* theOperation);
+  /// Updates reentrant manager state or sketcher operations for the started operation
+  /// \param theOperation the started operation
+  void updateSketcherOnStart(ModuleBase_Operation* theOperation);
+
+  /// Updates presetnations of results and arguments by operation start
+  /// \param theOperation the started operation
+  void updatePresentationsOnStart(ModuleBase_Operation* theOperation);
 
  private slots:
    void onTreeViewDoubleClick(const QModelIndex&);
diff --git a/src/PartSet/PartSet_MouseProcessor.h b/src/PartSet/PartSet_MouseProcessor.h
new file mode 100755 (executable)
index 0000000..08f9eed
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_MouseProcessor.hxx
+// Created:     21 Jul 2016
+// Author:      Natalia ERMOLAEVA
+
+#ifndef PartSet_MouseProcessor_H
+#define PartSet_MouseProcessor_H
+
+#include "PartSet.h"
+
+class ModuleBase_IViewWindow;
+class QMouseEvent;
+
+/**
+ * This is an interface to allow processing of mouse events. Implementation of necessary methods
+* should be done in a child.
+*/
+class PartSet_MouseProcessor
+{
+public:
+  /// Processing the mouse move event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  PARTSET_EXPORT virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {}
+  /// Processing the mouse press event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  PARTSET_EXPORT virtual void mousePressed(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {}
+  /// Processing the mouse release event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  PARTSET_EXPORT virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {}
+  /// Processing the mouse double click event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  PARTSET_EXPORT virtual void mouseDoubleClick(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {}
+};
+
+#endif
index 29a428ed1ccc30d97572ff80572df44d93e5da78..0974ef4b635d6baccb58899b49cc534c3d3de96c 100755 (executable)
@@ -7,8 +7,7 @@
 #include "PartSet_SketcherMgr.h"
 #include "PartSet_SketcherReetntrantMgr.h"
 #include "PartSet_Module.h"
-#include "PartSet_WidgetPoint2d.h"
-#include "PartSet_WidgetPoint2dDistance.h"
+#include "PartSet_MouseProcessor.h"
 #include "PartSet_Tools.h"
 #include "PartSet_WidgetSketchLabel.h"
 #include "PartSet_WidgetEditor.h"
@@ -476,6 +475,11 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse
 
   aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
   myIsDragging = false;
+
+  ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
+  PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
+  if (aProcessor)
+    aProcessor->mouseReleased(theWnd, theEvent);
 }
 
 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
@@ -483,31 +487,27 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
     return;
 
-  if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
-    myIsMouseOverViewProcessed = true;
+  if (isNestedCreateOperation(getCurrentOperation())) {
     // 1. perform the widget mouse move functionality and display the presentation
     // the mouse move should be processed in the widget, if it can in order to visualize correct
     // presentation. These widgets correct the feature attribute according to the mouse position
     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
-    PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWidget);
-    if (aPoint2DWdg) {
-      aPoint2DWdg->onMouseMove(theWnd, theEvent);
-    }
-    PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast<PartSet_WidgetPoint2dDistance*>
-                                                                (anActiveWidget);
-    if (aDistanceWdg) {
-      aDistanceWdg->onMouseMove(theWnd, theEvent);
-    }
-    // the feature is to be erased here, but it is correct to call canDisplayObject because
-    // there can be additional check (e.g. editor widget in distance constraint)
-    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                                             (getCurrentOperation());
-    if (aFOperation) {
-      FeaturePtr aFeature = aFOperation->feature();
-      visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
+    PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
+    if (aProcessor)
+      aProcessor->mouseMoved(theWnd, theEvent);
+    if (!myIsMouseOverViewProcessed) {
+      myIsMouseOverViewProcessed = true;
+
+      // the feature is to be erased here, but it is correct to call canDisplayObject because
+      // there can be additional check (e.g. editor widget in distance constraint)
+      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                               (getCurrentOperation());
+      if (aFOperation) {
+        FeaturePtr aFeature = aFOperation->feature();
+        visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
+      }
     }
   }
-
   //myClickedPoint.clear();
 
   if (myIsDragging) {
@@ -1048,7 +1048,7 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
   /// improvement to deselect automatically all eventual selected objects, when
   // returning to the neutral point of the Sketcher
   // if the operation is restarted, the previous selection is used to initialize started operation
-  if (myModule->isSketchNeutralPointActivated())
+  if (!myModule->sketchReentranceMgr()->isInternalEditStarted())
     workshop()->selector()->clearSelection();
 }
 
@@ -1233,11 +1233,9 @@ bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,
   bool aSwitchedOn = true;
 
   const QStringList& aConstrIds = constraintsIdList();
-  const QStringList& aReplicationIds = replicationsIdList();
 
   std::string aKind = theFeature->getKind();
-  if (aConstrIds.contains(aKind.c_str()) ||
-      aReplicationIds.contains(aKind.c_str())) {
+  if (aConstrIds.contains(QString(aKind.c_str()))) {
     bool isTypedConstraint = false;
 
     switch (theState) {
index 7f92c9646270063521c997db83a4579c6d2a3da7..e11f6d61cece49b8a2898a10908d55a3abf388f1 100755 (executable)
@@ -108,6 +108,12 @@ void PartSet_SketcherReetntrantMgr::operationStarted(ModuleBase_Operation* theOp
   if (!isActiveMgr())
     return;
 
+  if (myPreviousFeature.get() && myRestartingMode == RM_LastFeatureUsed) {
+    ModuleBase_OperationFeature* aCurrentOperation = dynamic_cast<ModuleBase_OperationFeature*>(
+                                                                myWorkshop->currentOperation());
+    CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
+    copyReetntrantAttributes(myPreviousFeature, aCurrentOperation->feature(), aSketch);
+  }
   resetFlags();
 }
 
@@ -136,7 +142,6 @@ bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* /*
       ModuleBase_IPropertyPanel* aPanel = myWorkshop->currentOperation()->propertyPanel();
       bool aWidgetIsFilled = false;
 
-      //bool aCanBeActivatedByMove = false;
       FeaturePtr aCurrentFeature = aFOperation->feature();
       bool isLineFeature = false, isArcFeature = false;
       if (aCurrentFeature->getKind() == SketchPlugin_Line::ID())
@@ -146,34 +151,15 @@ bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* /*
 
       bool aCanBeActivatedByMove = isLineFeature || isArcFeature;
       if (aCanBeActivatedByMove) {
+        myPreviousFeature = aFOperation->feature();
         restartOperation();
+        myPreviousFeature = FeaturePtr();
 
         anActiveWidget = module()->activeWidget();
         aCurrentFeature = anActiveWidget->feature();
         aProcessed = true;
-        if (isLineFeature) {
-          PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWidget);
-          if (aPoint2DWdg) { // line, start point should be equal last point of the last feature line
-            QList<ModuleBase_ViewerPrsPtr> aSelection;
-            aSelection.append(std::shared_ptr<ModuleBase_ViewerPrs>(
-               new ModuleBase_ViewerPrs(aLastFeature, GeomShapePtr(), NULL)));
-            aWidgetIsFilled = aPoint2DWdg->setSelection(aSelection, true);
-          }
-        }
-        else if (isArcFeature) { // arc, start point should be equal last point of the last feature arc
-          if (aCurrentFeature->getKind() == SketchPlugin_Arc::ID()) {
-            // get the last point of the previuos arc feature(geom point 2d)
-            std::shared_ptr<ModelAPI_Data> aData = aLastFeature->data();
-            std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = 
-                std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                           aData->attribute(SketchPlugin_Arc::END_ID()));
-            // get point attribute on the current feature
-            AttributeRefAttrPtr aTangentPointAttr = aCurrentFeature->data()->refattr(
-                                                         SketchPlugin_Arc::TANGENT_POINT_ID());
-            aTangentPointAttr->setAttr(aPointAttr);
-            aWidgetIsFilled = true;
-          }
-        }
+        if (isLineFeature || isArcFeature)
+          aWidgetIsFilled = true;
       }
       if (aWidgetIsFilled)
         aPanel->activateNextWidget(anActiveWidget);
@@ -209,7 +195,11 @@ bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow*
       // onMouseRelease happens, which correct the point position
       ModuleBase_Tools::blockUpdateViewer(true);
 
+      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                           (myWorkshop->currentOperation());
+      myPreviousFeature = aFOperation->feature();
       restartOperation();
+      myPreviousFeature = FeaturePtr();
       aProcessed = true;
 
       // fill the first widget by the mouse event point
@@ -218,7 +208,7 @@ bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow*
       PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
       ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget();
       if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) {
-        aPoint2DWdg->onMouseRelease(theWnd, theEvent);
+        aPoint2DWdg->mouseReleased(theWnd, theEvent);
       }
       // unblock viewer update
       ModuleBase_Tools::blockUpdateViewer(false);
@@ -458,16 +448,7 @@ void PartSet_SketcherReetntrantMgr::restartOperation()
       myIsFlagsBlocked = true;
       FeaturePtr aPrevFeature = aFOperation->feature();
       aFOperation->commit();
-      module()->launchOperation(aFOperation->id(), false);
-      // allow the same attribute values in restarted operation
-      ModuleBase_OperationFeature* aCurrentOperation = dynamic_cast<ModuleBase_OperationFeature*>(
-                                                                  myWorkshop->currentOperation());
-      copyReetntrantAttributes(aPrevFeature, aCurrentOperation->feature());
-
-      // update property panel: it should be done because in launchOperation, the 'false' is given
-      workshop()->propertyPanel()->updateContentWidget(aCurrentOperation->feature());
-      workshop()->propertyPanel()->createContentPanel(aCurrentOperation->feature());
-
+      module()->launchOperation(aFOperation->id());
       myIsFlagsBlocked = false;
       resetFlags();
       // we should avoid processing of the signal about no more widgets attributes and 
@@ -493,7 +474,8 @@ void PartSet_SketcherReetntrantMgr::createInternalFeature()
     CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
     myInternalFeature = aSketch->addFeature(anOperationFeature->getKind());
 
-    bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature);
+    bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature,
+                                                     aSketch, false);
     XGUI_PropertyPanel* aPropertyPanel = dynamic_cast<XGUI_PropertyPanel*>
                                                   (aFOperation->propertyPanel());
 
@@ -538,6 +520,7 @@ void PartSet_SketcherReetntrantMgr::deleteInternalFeature()
   QObjectPtrList anObjects;
   anObjects.append(myInternalFeature);
   workshop()->deleteFeatures(anObjects);
+  myInternalFeature = FeaturePtr();
 }
 
 void PartSet_SketcherReetntrantMgr::resetFlags()
@@ -550,21 +533,66 @@ void PartSet_SketcherReetntrantMgr::resetFlags()
 }
 
 bool PartSet_SketcherReetntrantMgr::copyReetntrantAttributes(const FeaturePtr& theSourceFeature,
-                                                             const FeaturePtr& theNewFeature)
+                                                             const FeaturePtr& theNewFeature,
+                                                             const CompositeFeaturePtr& theSketch,
+                                                             const bool isTemporary)
 {
   bool aChanged = false;
-  std::string aTypeAttributeId;
-  if (theSourceFeature->getKind() == SketchPlugin_Circle::ID()) {
-    aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE();
+  if (!theSourceFeature.get())
+    return aChanged;
+
+  std::string aFeatureKind = theSourceFeature->getKind();
+  if (aFeatureKind == SketchPlugin_Line::ID()) {
+    // Initialize new line with first point equal to end of previous
+    std::shared_ptr<ModelAPI_Data> aSFData = theSourceFeature->data();
+    std::shared_ptr<GeomDataAPI_Point2D> aSPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                                 aSFData->attribute(SketchPlugin_Line::END_ID()));
+    std::shared_ptr<ModelAPI_Data> aNFData = theNewFeature->data();
+    std::shared_ptr<GeomDataAPI_Point2D> aNPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                                 aNFData->attribute(SketchPlugin_Line::START_ID()));
+    aNPoint->setValue(aSPoint->x(), aSPoint->y());
+    PartSet_Tools::createConstraint(theSketch, aSPoint, aNPoint);
+
+    aNPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                                 aSFData->attribute(SketchPlugin_Line::END_ID()));
+    aNPoint->setValue(aSPoint->x(), aSPoint->y());
   }
-  if (theSourceFeature->getKind() == SketchPlugin_Arc::ID()) {
-    aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE();
+  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+    // set circle type
+    std::string aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE();
+    AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
+    AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
+    aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
+    //ModuleBase_Tools::flushUpdated(theNewFeature);
+    aChanged = true;
   }
-  if (!aTypeAttributeId.empty()) {
+  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+    // set arc type
+    std::string aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE();
     AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
     AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
     aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
-    ModuleBase_Tools::flushUpdated(theNewFeature);
+
+    // if the arc is tangent, set coincidence to end point of the previous arc
+    std::string anArcType = aSourceFeatureTypeAttr->value();
+    if (anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT()) {
+      // get the last point of the previuos arc feature(geom point 2d)
+      std::shared_ptr<ModelAPI_Data> aSData = theSourceFeature->data();
+      std::shared_ptr<GeomDataAPI_Point2D> aSPointAttr = 
+                                      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                      aSData->attribute(SketchPlugin_Arc::END_ID()));
+      // get point attribute on the current feature
+      AttributeRefAttrPtr aTangentPointAttr = theNewFeature->data()->refattr(
+                                                    SketchPlugin_Arc::TANGENT_POINT_ID());
+      aTangentPointAttr->setAttr(aSPointAttr);
+
+      std::shared_ptr<GeomDataAPI_Point2D> aNPointAttr = 
+                                    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                    theNewFeature->data()->attribute(SketchPlugin_Arc::END_ID()));
+      aNPointAttr->setValue(aSPointAttr->x(), aSPointAttr->y());
+
+    }
+    //ModuleBase_Tools::flushUpdated(theNewFeature);
     aChanged = true;
   }
   return aChanged;
index 74e8bd92b49eaa997976531bc291c82bd95e304a..72921d803030cd10462df0fcab36ed946138f077 100755 (executable)
@@ -16,6 +16,8 @@ class ModuleBase_Operation;
 class ModuleBase_ModelWidget;
 class ModuleBase_IViewWindow;
 
+class ModelAPI_CompositeFeature;
+
 class QMouseEvent;
 
 class XGUI_Workshop;
@@ -150,9 +152,13 @@ private:
   /// This is type for Circle and Arc features
   /// \param theSourceFeature a source feature
   /// \param theNewFeature a new feature
+  /// \param theSketch an active sketch
+  /// \param isTemporary is used to do not create additional features(e.g. coicidence for line)
   /// \return true is something is copied
   static bool copyReetntrantAttributes(const FeaturePtr& theSourceFeature,
-                                       const FeaturePtr& theNewFeature);
+                                      const FeaturePtr& theNewFeature,
+                                      const std::shared_ptr<ModelAPI_CompositeFeature>& theSketch,
+                                      const bool isTemporary = false);
 
   static bool isTangentArc(ModuleBase_Operation* theOperation);
 
@@ -172,6 +178,7 @@ private:
   bool myIsFlagsBlocked; /// true when reset of flags should not be perfromed
   bool myIsInternalEditOperation; /// true when the 'internal' edit is started
 
+  FeaturePtr myPreviousFeature; /// feature of the previous operation, which is restarted
   FeaturePtr myInternalFeature;
   QWidget* myInternalWidget;
   ModuleBase_ModelWidget* myInternalActiveWidget;
index 4cfede1e2ad6482a0d45742304ebdf88b88d9e63..e0e577163d758db999fb8c3ddf92b82bd82e55cb 100644 (file)
@@ -225,24 +225,6 @@ bool PartSet_WidgetPoint2D::setSelection(QList<ModuleBase_ViewerPrsPtr>& theValu
       PartSet_Tools::setConstraints(mySketch, feature(), attributeID(), aX, aY);
     }
   }
-  else if (canBeActivatedByMove()) {
-    if (feature()->getKind() == SketchPlugin_Line::ID()) {
-      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aValue->object());
-      // Initialize new line with first point equal to end of previous
-      if (aFeature.get()) {
-        std::shared_ptr<ModelAPI_Data> aData = aFeature->data();
-        std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-                                       aData->attribute(SketchPlugin_Line::END_ID()));
-        if (aPoint) {
-          setPoint(aPoint->x(), aPoint->y());
-          PartSet_Tools::setConstraints(mySketch, feature(), attributeID(), aPoint->x(),
-                                        aPoint->y());
-          isDone = true;
-        }
-      }
-    }
-  }
   return isDone;
 }
 
@@ -378,12 +360,6 @@ QList<QWidget*> PartSet_WidgetPoint2D::getControls() const
 
 void PartSet_WidgetPoint2D::activateCustom()
 {
-  ModuleBase_IViewer* aViewer = myWorkshop->viewer();
-  connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), 
-          this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
-  connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
-          this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
-
   QIntList aModes;
   aModes << TopAbs_VERTEX;
   aModes << TopAbs_EDGE;
@@ -396,16 +372,6 @@ void PartSet_WidgetPoint2D::activateCustom()
   }
 }
 
-bool PartSet_WidgetPoint2D::canBeActivatedByMove()
-{
-  bool aCanBeActivated = false;
-  if (feature()->getKind() == SketchPlugin_Line::ID() &&
-      attributeID() == SketchPlugin_Line::START_ID())
-    aCanBeActivated = true;
-
-  return aCanBeActivated;
-}
-
 void PartSet_WidgetPoint2D::deactivate()
 {
   // the value of the control should be stored to model if it was not
@@ -417,12 +383,6 @@ void PartSet_WidgetPoint2D::deactivate()
     storeValue();
 
   ModuleBase_ModelWidget::deactivate();
-  ModuleBase_IViewer* aViewer = myWorkshop->viewer();
-  disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
-             this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
-  disconnect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
-             this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
-
   myWorkshop->deactivateSubShapesSelection();
 }
 
@@ -484,14 +444,14 @@ bool PartSet_WidgetPoint2D::setConstraintWith(const ObjectPtr& theObject)
   return true;
 }
 
-void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
+void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
 {
   // the contex menu release by the right button should not be processed by this widget
   if (theEvent->button() != Qt::LeftButton)
     return;
 
   ModuleBase_ISelection* aSelection = myWorkshop->selection();
-  Handle(V3d_View) aView = theWnd->v3dView();
+  Handle(V3d_View) aView = theWindow->v3dView();
 
   QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
   ModuleBase_ViewerPrsPtr aFirstValue = aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
@@ -569,7 +529,7 @@ void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMous
         }
         else if (aShape.ShapeType() == TopAbs_EDGE) {
           if (!setConstraintWith(aObject)) {
-            gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView());
+            gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
             PartSet_Tools::convertTo2D(aPoint, mySketch, aView, aX, aY);
             setPoint(aX, aY);
           }
@@ -592,7 +552,7 @@ void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMous
   // End of Bug dependent fragment
   else {
     // A case when point is taken from mouse event
-    gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView());
+    gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
     double aX, anY;
     PartSet_Tools::convertTo2D(aPoint, mySketch, aView, aX, anY);
 
@@ -620,15 +580,15 @@ void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMous
 }
 
 
-void PartSet_WidgetPoint2D::onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
+void PartSet_WidgetPoint2D::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
 {
   if (isEditingMode())
     return;
 
-  gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView());
+  gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
 
   double aX, anY;
-  PartSet_Tools::convertTo2D(aPoint, mySketch, theWnd->v3dView(), aX, anY);
+  PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, anY);
   if (myState != ModifiedInViewer)
     storeCurentValue();
   // we need to block the value state change 
index 6992569bac26f75f47eff989b7f27362d5a85fad..a65a51c08a75ab6e1aeb0f22767d65af3c696adf 100755 (executable)
@@ -8,6 +8,8 @@
 #define PartSet_WidgetPoint2D_H
 
 #include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
 #include <ModelAPI_CompositeFeature.h>
 #include <ModuleBase_ModelWidget.h>
 
@@ -34,7 +36,8 @@ class QMouseEvent;
  * <sketch-2dpoint_selector id="CircleCenter" title="Center" tooltip="Center coordinates"/>
  * \endcode
  */
-class PARTSET_EXPORT PartSet_WidgetPoint2D : public ModuleBase_ModelWidget
+class PARTSET_EXPORT PartSet_WidgetPoint2D : public ModuleBase_ModelWidget,
+                                             public PartSet_MouseProcessor
 {
 Q_OBJECT
  public:
@@ -68,10 +71,6 @@ Q_OBJECT
 
   //bool initFromPrevious(ObjectPtr theObject);
 
-  /// Defines if the widget can be activated by mouse move.
-  /// By default it returns false
-  virtual bool canBeActivatedByMove();
-
   /// The methiod called when widget is deactivated
   virtual void deactivate();
 
@@ -100,20 +99,19 @@ Q_OBJECT
   /// and creating a coincidence constraint to them. This control use them.
   virtual bool useSelectedShapes() const;
 
-signals:
-  /// Signal about selection of an existing vertex from an object
-  void vertexSelected();
-
-public slots:
-  /// Process mouse move event
-  /// \param theWnd a view window
+  /// Processing the mouse move event in the viewer
+  /// \param theWindow a view window
   /// \param theEvent a mouse event
-  void onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+  virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
 
-  /// Process mouse release event
-  /// \param theWnd a view window
+  /// Processing the mouse release event in the viewer
+  /// \param theWindow a view window
   /// \param theEvent a mouse event
-  void onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+  virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+signals:
+  /// Signal about selection of an existing vertex from an object
+  void vertexSelected();
 
 protected:
   /// Saves the internal parameters to the given feature
index 427efc273fe8dd552c6718d67ffc9d69317a31ed..2c7daebdedc25ba8f850d6e3ed8010bf3b012ddf 100644 (file)
@@ -91,26 +91,7 @@ double PartSet_WidgetPoint2dDistance::computeValue(const std::shared_ptr<GeomAPI
   return theCurrentPnt->distance(theFirstPnt);
 }
 
-void PartSet_WidgetPoint2dDistance::activateCustom()
-{
-  ModuleBase_IViewer* aViewer = myWorkshop->viewer();
-  connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
-          this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
-  connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
-          this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
-}
-
-void PartSet_WidgetPoint2dDistance::deactivate()
-{
-  ModuleBase_ModelWidget::deactivate();
-  ModuleBase_IViewer* aViewer = myWorkshop->viewer();
-  disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), 
-             this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
-  disconnect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
-             this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
-}
-
-void PartSet_WidgetPoint2dDistance::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
+void PartSet_WidgetPoint2dDistance::mouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
   // the contex menu release by the right button should not be processed by this widget
   if (theEvent->button() != Qt::LeftButton)
@@ -132,7 +113,7 @@ void PartSet_WidgetPoint2dDistance::onMouseRelease(ModuleBase_IViewWindow* theWn
     emit focusOutWidget(this);
 }
 
-void PartSet_WidgetPoint2dDistance::onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
+void PartSet_WidgetPoint2dDistance::mouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
   if (isEditingMode())
     return;
index 1c4e05b2a6d1f806fb9c282147600fc5963160e8..0836b20b1a22a84197fc7490dcf993e1362d8bc0 100644 (file)
@@ -8,6 +8,8 @@
 #define PartSet_WidgetPoint2dDistance_H
 
 #include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
 #include <ModuleBase_WidgetDoubleValue.h>
 
 #include <ModelAPI_CompositeFeature.h>
@@ -34,7 +36,8 @@ class QMouseEvent;
 * </point2ddistance>
 * \endcode
 */ 
-class PARTSET_EXPORT PartSet_WidgetPoint2dDistance : public ModuleBase_WidgetDoubleValue
+class PARTSET_EXPORT PartSet_WidgetPoint2dDistance : public ModuleBase_WidgetDoubleValue,
+                                                     public PartSet_MouseProcessor
 {
 Q_OBJECT
  public:
@@ -52,9 +55,6 @@ Q_OBJECT
   /// \return a boolean value
   virtual bool isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
 
-  /// The methiod called when widget is deactivated
-  virtual void deactivate();
-
   /// \returns the sketch instance
   CompositeFeaturePtr sketch() const { return mySketch; }
 
@@ -64,17 +64,15 @@ Q_OBJECT
   /// Returns true if the event is processed.
   virtual bool processEnter();
 
-public slots:
-   /// Process of mouse move
-   /// \param theWnd a pointer to a window
-   /// \param theEvent a mouse event
-  void onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+  /// Processing the mouse move event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
 
-  protected slots:
-   /// Process of mouse release
-   /// \param theWnd a pointer to a window
-   /// \param theEvent a mouse event
-  void onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+  /// Processing the mouse release event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
 
 protected:
   /// Store current value in cashed value
@@ -88,9 +86,6 @@ protected:
   /// \return true if the widget current value is reset
   virtual bool resetCustom();
 
-  /// The methiod called when widget is activated
-  virtual void activateCustom();
-
   /// Set the second point which defines a value in the widget as a distance with a first point defined by feature
   void setPoint(FeaturePtr theFeature, const std::shared_ptr<GeomAPI_Pnt2d>& thePnt);
 
index c4035cc22e1a565b98e92ed14dd95a1190c8f7dd..394756ca5affe473441f8f46e3f2c554b9c78ba3 100644 (file)
@@ -335,7 +335,7 @@ bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_Vi
   aValues.push_back(aValue);
   aFOperation->setPreselection(aValues);
 
-  myModule->sendOperation(aFOperation);
+  myWorkshop->processLaunchOperation(aFOperation);
 
   return aSketchStarted;
 }
diff --git a/src/PartSet/PartSet_WidgetSubShapeSelector.cpp b/src/PartSet/PartSet_WidgetSubShapeSelector.cpp
new file mode 100755 (executable)
index 0000000..21b0277
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_WidgetSubShapeSelector.cpp
+// Created:     21 Jul 2016
+// Author:      Natalia ERMOLAEVA
+
+#include "PartSet_WidgetSubShapeSelector.h"
+#include "PartSet_Tools.h"
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_ViewerPrs.h>
+
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_Tools.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomDataAPI_Point.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <ModelGeomAlgo_Point2D.h>
+
+#include <ModelGeomAlgo_Point2D.h>
+
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_Point.h>
+
+#include <ModuleBase_IViewWindow.h>
+#include <ModuleBase_IWorkshop.h>
+#include <ModuleBase_IModule.h>
+
+#include <Config_WidgetAPI.h>
+
+#include <QWidget>
+#include <QMouseEvent>
+
+PartSet_WidgetSubShapeSelector::PartSet_WidgetSubShapeSelector(QWidget* theParent,
+                                                         ModuleBase_IWorkshop* theWorkshop,
+                                                         const Config_WidgetAPI* theData)
+: PartSet_WidgetShapeSelector(theParent, theWorkshop, theData)
+{
+  //myUseSketchPlane = theData->getBooleanAttribute("use_sketch_plane", true);
+  //myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"), true);
+}
+
+PartSet_WidgetSubShapeSelector::~PartSet_WidgetSubShapeSelector()
+{
+}
+
+//********************************************************************
+void PartSet_WidgetSubShapeSelector::mouseMoved(ModuleBase_IViewWindow* theWindow,
+                                                QMouseEvent* theEvent)
+{
+  ModuleBase_ISelection* aSelect = myWorkshop->selection();
+  QList<ModuleBase_ViewerPrsPtr> aHighlighted = aSelect->getHighlighted();
+
+  if (aHighlighted.empty()) {
+    ModuleBase_ViewerPrsPtr aPrs = aHighlighted.first();
+    if (aPrs.get() && aPrs->object().get()) {
+      ObjectPtr anObject = aPrs->object();
+      if (myCashedShapes.find(anObject) == myCashedShapes.end())
+        fillObjectShapes(anObject);
+      const std::set<GeomShapePtr>& aShapes = myCashedShapes[anObject];
+      if (!aShapes.empty()) {
+        gp_Pnt aPnt = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+        std::shared_ptr<GeomAPI_Vertex> aVertexShape(new GeomAPI_Vertex(aPnt.X(), aPnt.Y(), aPnt.Z()));
+
+        std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
+        for (; anIt != aLast; anIt++) {
+          GeomShapePtr aBaseShape = *anIt;
+          if (GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aVertexShape, aBaseShape)) {
+            myCurrentSubShape->setObject(anObject);
+            myCurrentSubShape->setShape(aBaseShape);
+            break;
+          }
+        }
+      }
+    }
+  }
+  myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects,
+                                        true);
+}
+
+//********************************************************************
+void PartSet_WidgetSubShapeSelector::getHighlighted(
+                           QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues)
+{
+  if (myCurrentSubShape.get() && myCurrentSubShape->object().get())
+    theValues.append(myCurrentSubShape);
+}
+
+//********************************************************************
+void PartSet_WidgetSubShapeSelector::fillObjectShapes(const ObjectPtr& theObject)
+{
+  std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
+
+  // current feature
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  std::set<GeomShapePtr> anEdgeShapes;
+  // edges on feature
+  ModelAPI_Tools::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
+  if (!anEdgeShapes.empty()) {
+    GeomShapePtr aFeatureShape = *anEdgeShapes.begin();
+
+    // coincidences to the feature
+    std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
+    ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
+                         aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+    // layed on feature coincidences to divide it on several shapes
+    FeaturePtr aSketch = sketch();
+    std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
+    std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+        aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+    std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+        aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
+    std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
+    std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
+    std::set<std::shared_ptr<GeomAPI_Pnt> > aPoints;
+    ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
+                                                aX->dir(), aY, aPoints);
+
+    GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes);
+  }
+  myCashedShapes[theObject] = aShapes;
+}
+
+//********************************************************************
+/*bool PartSet_WidgetSubShapeSelector::activateSelectionAndFilters(bool toActivate)
+{
+  bool aHasSelectionFilter = ModuleBase_WidgetShapeSelector::activateSelectionAndFilters
+                                                                           (toActivate);
+  if (!myUseSketchPlane) {
+    XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+    PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(aWorkshop->module());
+    bool isUsePlaneFilterOnly = !toActivate;
+    aModule->sketchMgr()->activatePlaneFilter(isUsePlaneFilterOnly);
+  }
+  return aHasSelectionFilter;
+}
+
+//********************************************************************
+bool PartSet_WidgetSubShapeSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
+{
+  bool aValid = ModuleBase_WidgetShapeSelector::isValidSelectionCustom(thePrs);
+  if (aValid) {
+    ObjectPtr anObject = myWorkshop->selection()->getResult(thePrs);
+    aValid = myExternalObjectMgr->isValidObject(anObject);
+  }
+  return aValid;
+}
+
+void PartSet_WidgetSubShapeSelector::getGeomSelection(const ModuleBase_ViewerPrsPtr& thePrs,
+                                                   ObjectPtr& theObject,
+                                                   GeomShapePtr& theShape)
+{
+  ModuleBase_WidgetShapeSelector::getGeomSelection(thePrs, theObject, theShape);
+
+  FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(theObject);
+  std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
+          std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
+  // there is no a sketch feature is selected, but the shape exists, try to create an exernal object
+  // TODO: unite with the same functionality in PartSet_WidgetSubShapeSelector
+  if (aSPFeature.get() == NULL) {
+    ObjectPtr anExternalObject = ObjectPtr();
+    if (myExternalObjectMgr->useExternal()) {
+      GeomShapePtr aShape = theShape;
+      if (!aShape.get()) {
+        ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
+        if (aResult.get())
+          aShape = aResult->shape();
+      }
+      if (aShape.get() != NULL && !aShape->isNull())
+        anExternalObject = myExternalObjectMgr->externalObject(theObject, aShape, sketch(), myIsInValidate);
+    }
+    /// the object is null if the selected feature is "external"(not sketch entity feature of the
+    /// current sketch) and it is not created by object manager
+    theObject = anExternalObject;
+  }
+}
+
+//********************************************************************
+void PartSet_WidgetSubShapeSelector::restoreAttributeValue(const AttributePtr& theAttribute,
+                                                        const bool theValid)
+{
+  ModuleBase_WidgetShapeSelector::restoreAttributeValue(theAttribute, theValid);
+  myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
+}
+*/
diff --git a/src/PartSet/PartSet_WidgetSubShapeSelector.h b/src/PartSet/PartSet_WidgetSubShapeSelector.h
new file mode 100644 (file)
index 0000000..4c09457
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_WidgetSubShapeSelector.h
+// Created:     21 Jul 2016
+// Author:      Natalia ERMOLAEVA
+
+
+#ifndef PartSet_WidgetSubShapeSelector_H
+#define PartSet_WidgetSubShapeSelector_H
+
+#include "PartSet.h"
+
+#include <PartSet_WidgetShapeSelector.h>
+#include <PartSet_MouseProcessor.h>
+
+#include <QObject>
+
+#include <set>
+#include <map>
+
+class ModuleBase_IWorkshop;
+class Config_WidgetAPI;
+class ModuleBase_IViewWindow;
+class ModuleBase_ViewerPrs;
+
+class QWidget;
+class QMouseEvent;
+
+/**
+* \ingroup Modules
+* Customosation of PartSet_WidgetSubShapeSelector in order to visualize sub-shape 
+* by mouse move over shape in the viewer. Split of the object is performed by
+* coincident points to the object. Segment between nearest coincidence is highlighted
+*/
+class PARTSET_EXPORT PartSet_WidgetSubShapeSelector: public PartSet_WidgetShapeSelector,
+                                                     public PartSet_MouseProcessor
+{
+Q_OBJECT
+ public:
+  /// Constructor
+  /// \param theParent the parent object
+  /// \param theWorkshop instance of workshop interface
+  /// \param theData the widget configuation. The attribute of the model widget is obtained from
+  PartSet_WidgetSubShapeSelector(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+                                 const Config_WidgetAPI* theData);
+
+  virtual ~PartSet_WidgetSubShapeSelector();
+
+  /// Processing the mouse move event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+  /// Returns values which should be highlighted when the whidget is active
+  /// \param theValues a list of presentations
+  virtual void getHighlighted(QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues);
+
+protected:
+  /// Checks the widget validity. By default, it returns true.
+  /// \param thePrs a selected presentation in the view
+  /// \return a boolean value
+  //virtual bool isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+
+  /// Return an object and geom shape by the viewer presentation
+  /// \param thePrs a selection
+  /// \param theObject an output object
+  /// \param theShape a shape of the selection
+  //virtual void getGeomSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs,
+  //                              ObjectPtr& theObject,
+  //                              GeomShapePtr& theShape);
+  void fillObjectShapes(const ObjectPtr& theObject);
+
+protected:
+  std::shared_ptr<ModuleBase_ViewerPrs> myCurrentSubShape;
+  std::map<ObjectPtr, std::set<GeomShapePtr> > myCashedShapes;
+};
+
+#endif
\ No newline at end of file
index d4d4dfc3e7e1f3c25a31dfba94b424967f4b34a0..9016965a711ecce2d44d93df076b1bde69cde62f 100644 (file)
@@ -5,75 +5,77 @@ INCLUDE(UnitTest)
 
 SET(PROJECT_HEADERS
     SketchPlugin.h
-    SketchPlugin_Feature.h
-    SketchPlugin_Plugin.h
-    SketchPlugin_Sketch.h
-    SketchPlugin_SketchEntity.h
-    SketchPlugin_Line.h
-    SketchPlugin_Point.h
-    SketchPlugin_IntersectionPoint.h
-    SketchPlugin_Circle.h
     SketchPlugin_Arc.h
+    SketchPlugin_Circle.h
     SketchPlugin_Constraint.h
+    SketchPlugin_ConstraintAngle.h
     SketchPlugin_ConstraintBase.h
     SketchPlugin_ConstraintCoincidence.h
     SketchPlugin_ConstraintCollinear.h
     SketchPlugin_ConstraintDistance.h
+    SketchPlugin_ConstraintEqual.h
+    SketchPlugin_ConstraintFillet.h
+    SketchPlugin_ConstraintHorizontal.h
     SketchPlugin_ConstraintLength.h
     SketchPlugin_ConstraintMiddle.h
+    SketchPlugin_ConstraintMirror.h
     SketchPlugin_ConstraintParallel.h
     SketchPlugin_ConstraintPerpendicular.h
     SketchPlugin_ConstraintRadius.h
     SketchPlugin_ConstraintRigid.h
-    SketchPlugin_ConstraintHorizontal.h
-    SketchPlugin_ConstraintVertical.h
-    SketchPlugin_ConstraintEqual.h
+    SketchPlugin_ConstraintSplit.h
     SketchPlugin_ConstraintTangent.h
-    SketchPlugin_ConstraintMirror.h
-    SketchPlugin_ConstraintFillet.h
-    SketchPlugin_ConstraintAngle.h
+    SketchPlugin_ConstraintVertical.h
+    SketchPlugin_ExternalValidator.h
+    SketchPlugin_Feature.h
+    SketchPlugin_IntersectionPoint.h
+    SketchPlugin_Line.h
     SketchPlugin_MultiRotation.h
     SketchPlugin_MultiTranslation.h
-    SketchPlugin_ExternalValidator.h
-    SketchPlugin_Validators.h
-    SketchPlugin_Tools.h
+    SketchPlugin_Plugin.h
+    SketchPlugin_Point.h
     SketchPlugin_Projection.h
+    SketchPlugin_Sketch.h
+    SketchPlugin_SketchEntity.h
+    SketchPlugin_Tools.h
+    SketchPlugin_Validators.h
 )
 
 SET(PROJECT_SOURCES
-    SketchPlugin_Feature.cpp
-    SketchPlugin_Plugin.cpp
-    SketchPlugin_Sketch.cpp
-    SketchPlugin_SketchEntity.cpp
-    SketchPlugin_Line.cpp
-    SketchPlugin_Point.cpp
-    SketchPlugin_IntersectionPoint.cpp
-    SketchPlugin_Circle.cpp
     SketchPlugin_Arc.cpp
+    SketchPlugin_Circle.cpp
     SketchPlugin_Constraint.cpp
+    SketchPlugin_ConstraintAngle.cpp
     SketchPlugin_ConstraintBase.cpp
     SketchPlugin_ConstraintCoincidence.cpp
     SketchPlugin_ConstraintCollinear.cpp
     SketchPlugin_ConstraintDistance.cpp
+    SketchPlugin_ConstraintEqual.cpp
+    SketchPlugin_ConstraintFillet.cpp
+    SketchPlugin_ConstraintHorizontal.cpp
     SketchPlugin_ConstraintLength.cpp
     SketchPlugin_ConstraintMiddle.cpp
+    SketchPlugin_ConstraintMirror.cpp
     SketchPlugin_ConstraintParallel.cpp
     SketchPlugin_ConstraintPerpendicular.cpp
     SketchPlugin_ConstraintRadius.cpp
     SketchPlugin_ConstraintRigid.cpp
-    SketchPlugin_ConstraintHorizontal.cpp
-    SketchPlugin_ConstraintVertical.cpp
-    SketchPlugin_ConstraintEqual.cpp
+    SketchPlugin_ConstraintSplit.cpp
     SketchPlugin_ConstraintTangent.cpp
-    SketchPlugin_ConstraintMirror.cpp
-    SketchPlugin_ConstraintFillet.cpp
-    SketchPlugin_ConstraintAngle.cpp
+    SketchPlugin_ConstraintVertical.cpp
+    SketchPlugin_ExternalValidator.cpp
+    SketchPlugin_Feature.cpp
+    SketchPlugin_IntersectionPoint.cpp
+    SketchPlugin_Line.cpp
     SketchPlugin_MultiRotation.cpp
     SketchPlugin_MultiTranslation.cpp
-    SketchPlugin_ExternalValidator.cpp
-    SketchPlugin_Validators.cpp
-    SketchPlugin_Tools.cpp
+    SketchPlugin_Plugin.cpp
+    SketchPlugin_Point.cpp
     SketchPlugin_Projection.cpp
+    SketchPlugin_Sketch.cpp
+    SketchPlugin_SketchEntity.cpp
+    SketchPlugin_Tools.cpp
+    SketchPlugin_Validators.cpp
 )
 
 SET(PROJECT_LIBRARIES
@@ -81,6 +83,7 @@ SET(PROJECT_LIBRARIES
     GeomAPI
     GeomAlgoAPI
     ModelAPI
+    ModelGeomAlgo
     SketcherPrs
     GeomDataAPI
 )
@@ -103,6 +106,7 @@ INCLUDE_DIRECTORIES(
   ../Config
   ../Events
   ../ModelAPI
+  ../ModelGeomAlgo
   ../GeomAPI
   ../GeomAlgoAPI
   ../GeomDataAPI
index be3f9e56862aa325020ff6555f2c14fa222178bc..5ba8163ea1618e85e1d821d47da324ec60e15d3b 100644 (file)
@@ -370,6 +370,8 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
       std::shared_ptr<GeomDataAPI_Point2D> aTangentPoint =
           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangPtAttr->attr());
       std::shared_ptr<GeomAPI_Pnt2d> aTangPnt2d = aTangentPoint->pnt();
+      if (aTangPnt2d->isEqual(anEndAttr->pnt()))
+        return;
       FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPoint->owner());
       std::shared_ptr<GeomAPI_Edge> aTangEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
           aTangFeature->lastResult()->shape());
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp
new file mode 100755 (executable)
index 0000000..b029f63
--- /dev/null
@@ -0,0 +1,1087 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_ConstraintSplit.cpp
+// Created: 17 Jul 2016
+// Author:  Natalia ERMOLAEVA
+
+#include "SketchPlugin_ConstraintSplit.h"
+
+//#include <GeomAPI_Circ2d.h>
+//#include <GeomAPI_Dir2d.h>
+//#include <GeomAPI_Lin2d.h>
+//#include <GeomAPI_Pnt2d.h>
+//#include <GeomAPI_XY.h>
+//#include <GeomDataAPI_Point2D.h>
+//#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeSelection.h>
+//#include <ModelAPI_AttributeRefList.h>
+//#include <ModelAPI_AttributeRefAttrList.h>
+//#include <ModelAPI_Data.h>
+//#include <ModelAPI_Events.h>
+//#include <ModelAPI_Session.h>
+//#include <ModelAPI_Validator.h>
+//
+//#include <SketchPlugin_Arc.h>
+//#include <SketchPlugin_Line.h>
+//#include <SketchPlugin_Point.h>
+//#include <SketchPlugin_Sketch.h>
+//#include <SketchPlugin_ConstraintCoincidence.h>
+//#include <SketchPlugin_ConstraintTangent.h>
+//#include <SketchPlugin_ConstraintRadius.h>
+//#include <SketchPlugin_Tools.h>
+//
+//#include <Events_Loop.h>
+//
+//#include <math.h>
+//
+//const double tolerance = 1.e-7;
+//const double paramTolerance = 1.e-4;
+
+///// \brief Attract specified point on theNewArc to the attribute of theFeature
+//static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
+//  FeaturePtr theFeature, const std::string& theFeatureAttribute);
+//
+///// \brief Calculates center of fillet arc and coordinates of tangency points
+//static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
+//                                  double theRadius, bool theNotInversed[2],
+//                                  std::shared_ptr<GeomAPI_XY>& theCenter,
+//                                  std::shared_ptr<GeomAPI_XY>& theTangentA,
+//                                  std::shared_ptr<GeomAPI_XY>& theTangentB);
+//
+///// Get point on 1/3 length of edge from fillet point
+//static void getPointOnEdge(const FeaturePtr theFeature,
+//                           const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
+//                           std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+//
+///// Get distance from point to feature
+//static double getProjectionDistance(const FeaturePtr theFeature,
+//                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint);
+//
+///// Get coincide edges for fillet
+//static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
+
+SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
+//: myListOfPointsChangedInCode(false),
+//  myRadiusChangedByUser(false),
+//  myRadiusChangedInCode(false),
+//  myRadiusInitialized(false)
+{
+}
+
+void SketchPlugin_ConstraintSplit::initAttributes()
+{
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeSelection::typeId());
+
+  //data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+  //data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttrList::typeId());
+}
+
+void SketchPlugin_ConstraintSplit::execute()
+{
+/*  std::shared_ptr<ModelAPI_Data> aData = data();
+
+  // Check the base objects are initialized.
+  AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(
+    aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  if(!aPointsRefList->isInitialized()) {
+    setError("Error: List of points is not initialized.");
+    return;
+  }
+
+  // Get fillet radius.
+  double aFilletRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+    aData->attribute(SketchPlugin_Constraint::VALUE()))->value();
+
+  // Wait all constraints being created, then send update events
+  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+  if (isUpdateFlushed)
+    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+
+  for(std::set<AttributePtr>::iterator aPointsIter = myNewPoints.begin();
+      aPointsIter != myNewPoints.end();
+      ++aPointsIter) {
+    AttributePtr aPointAttr = *aPointsIter;
+    std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2d = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr);
+    if(!aFilletPoint2d.get()) {
+      setError("Error: One of the selected points is empty.");
+      return;
+    }
+    std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2d->pnt();
+
+    // Obtain base lines for fillet.
+    bool anIsNeedNewObjects = true;
+    FilletFeatures aFilletFeatures;
+    std::map<AttributePtr, FilletFeatures>::iterator aPrevPointsIter = myPointFeaturesMap.find(aPointAttr);
+    if(aPrevPointsIter != myPointFeaturesMap.end()) {
+      anIsNeedNewObjects = false;
+      aFilletFeatures = aPrevPointsIter->second;
+    }
+    FeaturePtr aBaseEdgeA, aBaseEdgeB;
+    if(!anIsNeedNewObjects) {
+      aBaseEdgeA = aFilletFeatures.baseEdgesState.front().first;
+      aBaseEdgeB = aFilletFeatures.baseEdgesState.back().first;
+    } else {
+      // Obtain constraint coincidence for the fillet point.
+      FeaturePtr aConstraintCoincidence;
+      const std::set<AttributePtr>& aRefsList = aFilletPoint2d->owner()->data()->refsToMe();
+      for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
+        std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+        FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+        if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+          AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
+          AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
+          if(anAttrRefA.get() && !anAttrRefA->isObject()) {
+            AttributePtr anAttrA = anAttrRefA->attr();
+            if(aFilletPoint2d == anAttrA) {
+              aConstraintCoincidence = aConstrFeature;
+              break;
+            }
+          }
+          if(anAttrRefB.get() && !anAttrRefB->isObject()) {
+            AttributePtr anAttrB = anAttrRefB->attr();
+            if(aFilletPoint2d == anAttrB) {
+              aConstraintCoincidence = aConstrFeature;
+              break;
+            }
+          }
+        }
+      }
+
+      if(!aConstraintCoincidence.get()) {
+        setError("Error: No coincident edges at one of the selected points.");
+        return;
+      }
+
+      // Get coincide edges.
+      std::set<FeaturePtr> aCoincides = getCoincides(aConstraintCoincidence);
+      if(aCoincides.size() != 2) {
+        setError("Error: One of the selected points does not have two suitable edges for fillet.");
+        return;
+      }
+
+      std::set<FeaturePtr>::iterator aLinesIt = aCoincides.begin();
+      aBaseEdgeA = *aLinesIt++;
+      aBaseEdgeB = *aLinesIt;
+
+      std::pair<FeaturePtr, bool> aBasePairA = std::make_pair(aBaseEdgeA, aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
+      std::pair<FeaturePtr, bool> aBasePairB = std::make_pair(aBaseEdgeB, aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
+      aFilletFeatures.baseEdgesState.push_back(aBasePairA);
+      aFilletFeatures.baseEdgesState.push_back(aBasePairB);
+    }
+
+    if(!aBaseEdgeA.get() || !aBaseEdgeB.get()) {
+      setError("Error: One of the base edges is empty.");
+      return;
+    }
+
+    // Create new edges and arc if needed.
+    FeaturePtr aResultEdgeA, aResultEdgeB, aResultArc;
+    if(!anIsNeedNewObjects) {
+      // Obtain features from the list.
+      std::list<FeaturePtr>::iterator aResultEdgesIt = aFilletFeatures.resultEdges.begin();
+      aResultEdgeA = *aResultEdgesIt++;
+      aResultEdgeB = *aResultEdgesIt++;
+      aResultArc = *aResultEdgesIt;
+    } else {
+      // Copy edges and create arc.
+      aResultEdgeA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeA, sketch());
+      aResultEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false);
+      aResultEdgeB = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeB, sketch());
+      aResultEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false);
+      aResultArc = sketch()->addFeature(SketchPlugin_Arc::ID());
+
+      aFilletFeatures.resultEdges.push_back(aResultEdgeA);
+      aFilletFeatures.resultEdges.push_back(aResultEdgeB);
+      aFilletFeatures.resultEdges.push_back(aResultArc);
+    }
+
+    // Calculate arc attributes
+    static const int aNbFeatures = 2;
+    FeaturePtr aBaseFeatures[aNbFeatures] = {aBaseEdgeA, aBaseEdgeB};
+    FeaturePtr aResultFeatures[aNbFeatures] = {aResultEdgeA, aResultEdgeB};
+    std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures]; // tangent directions of the features in coincident point
+    bool isStart[aNbFeatures]; // indicates which point the features share
+    std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2]; // first pair of points relate to first feature, second pair -  to second
+    std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features
+    for (int i = 0; i < aNbFeatures; i++) {
+      std::string aStartAttr, aEndAttr;
+      if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
+        aStartAttr = SketchPlugin_Line::START_ID();
+        aEndAttr = SketchPlugin_Line::END_ID();
+      } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
+        aStartAttr = SketchPlugin_Arc::START_ID();
+        aEndAttr = SketchPlugin_Arc::END_ID();
+      } else { // wrong argument
+        setError("Error: One of the points has wrong coincide feature");
+        return;
+      }
+      aFeatAttributes[2*i] = aStartAttr;
+      aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aBaseFeatures[i]->attribute(aStartAttr))->pnt();
+      aFeatAttributes[2*i+1] = aEndAttr;
+      aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aBaseFeatures[i]->attribute(aEndAttr))->pnt();
+    }
+    for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
+      for (int j = 0; j < 2; j++) // loop on start-end of each feature
+        if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
+          isStart[aFeatInd] = (j==0);
+          break;
+        }
+    }
+    // tangent directions of the features
+    for (int i = 0; i < aNbFeatures; i++) {
+      std::shared_ptr<GeomAPI_XY> aDir;
+      if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
+        aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
+        if (!isStart[i])
+          aDir = aDir->multiplied(-1.0);
+      } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
+        std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aResultFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+        aDir = isStart[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
+        aDir = aDir->decreased(aCenterPoint->xy());
+
+        double x = aDir->x();
+        double y = aDir->y();
+        aDir->setX(-y);
+        aDir->setY(x);
+        if (isStart[i] == std::dynamic_pointer_cast<SketchPlugin_Arc>(aBaseFeatures[i])->isReversed())
+          aDir = aDir->multiplied(-1.0);
+      }
+      aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
+    }
+
+    // By default, the start point of fillet arc is connected to FeatureA,
+    // and the end point - to FeatureB. But when the angle between TangentDirA and
+    // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
+    double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), where A and B - angles between corresponding tanget direction and the X axis
+    bool isReversed = cosBA > 0.0;
+
+    // Calculate fillet arc parameters
+    std::shared_ptr<GeomAPI_XY> aCenter, aTangentPntA, aTangentPntB;
+    calculateFilletCenter(aBaseEdgeA, aBaseEdgeB, aFilletRadius, isStart, aCenter, aTangentPntA, aTangentPntB);
+    if(!aCenter.get() || !aTangentPntA.get() || !aTangentPntB.get()) {
+      setError("Can not create fillet with the specified parameters.");
+      return;
+    }
+    // update features
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->setValue(aTangentPntA->x(), aTangentPntA->y());
+    aResultEdgeA->execute();
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aResultEdgeB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))->setValue(aTangentPntB->x(), aTangentPntB->y());
+    aResultEdgeB->execute();
+    // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
+    // by arc; moreover, it may cause cyclicity in hte mechanism of updater
+    aResultArc->data()->blockSendAttributeUpdated(true);
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y());
+    if(isReversed) {
+      std::shared_ptr<GeomAPI_XY> aTmp = aTangentPntA;
+      aTangentPntA = aTangentPntB;
+      aTangentPntB = aTmp;
+    }
+    std::shared_ptr<GeomDataAPI_Point2D> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aResultArc->attribute(SketchPlugin_Arc::START_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aResultArc->attribute(SketchPlugin_Arc::END_ID()));
+    if(aStartPoint->isInitialized() && aEndPoint->isInitialized() &&
+      (aStartPoint->pnt()->xy()->distance(aTangentPntA) > tolerance ||
+       aEndPoint->pnt()->xy()->distance(aTangentPntB) > tolerance)) {
+      std::dynamic_pointer_cast<SketchPlugin_Arc>(aResultArc)->setReversed(false);
+    }
+    aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y());
+    aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y());
+    aResultArc->data()->blockSendAttributeUpdated(false);
+    aResultArc->execute();
+
+    if(anIsNeedNewObjects) {
+      // Create list of additional constraints:
+      // 1. Coincidence of boundary points of features (copied lines/arcs) and fillet arc
+      // 1.1. coincidence
+      FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+      aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID()));
+      aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+      int aFeatInd = isReversed ? 1 : 0;
+      int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1);
+      aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
+      recalculateAttributes(aResultArc, SketchPlugin_Arc::START_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]);
+      aConstraint->execute();
+      aFilletFeatures.resultConstraints.push_back(aConstraint);
+      ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+      // 1.2. coincidence
+      aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+      aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+      aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID()));
+      aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+      aFeatInd = isReversed ? 0 : 1;
+      anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1);
+      aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
+      recalculateAttributes(aResultArc, SketchPlugin_Arc::END_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]);
+      aConstraint->execute();
+      aFilletFeatures.resultConstraints.push_back(aConstraint);
+      ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+      // 2. Fillet arc radius
+      //aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID());
+      //aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      //    aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+      //aRefAttr->setObject(aNewArc->lastResult());
+      //std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+      //    aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius);
+      //std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      //    aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue(
+      //    isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]);
+      //aConstraint->execute();
+      //myProducedFeatures.push_back(aConstraint);
+      //ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+      // 3. Tangency of fillet arc and features
+      for (int i = 0; i < aNbFeatures; i++) {
+        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+        aRefAttr->setObject(aResultArc->lastResult());
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+        bool isArc = aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID();
+        aRefAttr->setObject(isArc ? aResultFeatures[i]->lastResult() : aResultFeatures[i]->firstResult());
+        aConstraint->execute();
+        aFilletFeatures.resultConstraints.push_back(aConstraint);
+        ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+      }
+      // 4. Coincidence of free boundaries of base and copied features
+      for (int i = 0; i < aNbFeatures; i++) {
+        anAttrInd = 2*i + (isStart[i] ? 1 : 0);
+        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+        aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+        aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
+        aFilletFeatures.resultConstraints.push_back(aConstraint);
+      }
+      // 4.1. Additional tangency constraints when the fillet is based on arcs.
+      //      It is used to verify the created arc will be placed on a source.
+      for (int i = 0; i < aNbFeatures; ++i) {
+        if (aResultFeatures[i]->getKind() != SketchPlugin_Arc::ID())
+          continue;
+        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+        aRefAttr->setObject(aBaseFeatures[i]->lastResult());
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+        aRefAttr->setObject(aResultFeatures[i]->lastResult());
+        aConstraint->execute();
+        aFilletFeatures.resultConstraints.push_back(aConstraint);
+        ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+      }
+      // 5. Tangent points should be placed on the base features
+      for (int i = 0; i < aNbFeatures; i++) {
+        anAttrInd = 2*i + (isStart[i] ? 0 : 1);
+        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+        aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
+        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+        aRefAttr->setObject(aBaseFeatures[i]->lastResult());
+        aFilletFeatures.resultConstraints.push_back(aConstraint);
+      }
+      // make base features auxiliary
+      aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+      aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+
+      // exchange the naming IDs of newly created and old line that become auxiliary
+      sketch()->exchangeIDs(aBaseEdgeA, aResultEdgeA);
+      sketch()->exchangeIDs(aBaseEdgeB, aResultEdgeB);
+
+      // store point and features in the map.
+      myPointFeaturesMap[aPointAttr] = aFilletFeatures;
+    } else {
+      // Update radius value
+      int aNbSubs = sketch()->numberOfSubs();
+      FeaturePtr aSubFeature;
+      for (int aSub = 0; aSub < aNbSubs; aSub++) {
+        aSubFeature = sketch()->subFeature(aSub);
+        if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID())
+          continue;
+        AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
+        if (!aRefAttr || !aRefAttr->isObject())
+          continue;
+        FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+        if (aFeature == aResultArc) {
+          AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+            aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
+          aRadius->setValue(aFilletRadius);
+          break;
+        }
+      }
+    }
+  }
+
+  // Send events to update the sub-features by the solver.
+  if(isUpdateFlushed) {
+    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+  }
+*/
+}
+
+void SketchPlugin_ConstraintSplit::attributeChanged(const std::string& theID)
+{
+/*  if(theID == SketchPlugin_Constraint::ENTITY_A()) {
+    if(myListOfPointsChangedInCode) {
+      return;
+    }
+
+    // Clear results.
+    clearResults();
+
+    // Clear list of new points.
+    myNewPoints.clear();
+
+    // Get list of points for fillets and current radius.
+    AttributeRefAttrListPtr aRefListOfFilletPoints = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(
+      data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
+    AttributeDoublePtr aRadiusAttribute = real(VALUE());
+    int aListSize = aRefListOfFilletPoints->size();
+    if(aListSize == 0 && !myRadiusChangedByUser) {
+      // If list is empty reset radius to zero (if it was not changed by user).
+      myRadiusChangedInCode = true;
+      aRadiusAttribute->setValue(0);
+      myRadiusChangedInCode = false;
+      return;
+    }
+
+    // Iterate over points to get base lines an calculate radius for fillets.
+    double aMinimumRadius = 0;
+    std::list<std::pair<ObjectPtr, AttributePtr>> aSelectedPointsList = aRefListOfFilletPoints->list();
+    std::list<std::pair<ObjectPtr, AttributePtr>>::iterator anIter = aSelectedPointsList.begin();
+    std::set<AttributePtr> aPointsToSkeep;
+    for(int anIndex = 0; anIndex < aListSize; anIndex++, anIter++) {
+      AttributePtr aFilletPointAttr = (*anIter).second;
+      std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFilletPointAttr);
+      if(!aFilletPoint2D.get()) {
+        myNewPoints.clear();
+        setError("Error: One of the selected points is invalid.");
+        return;
+      }
+
+      // If point or coincident point is already in list remove it from attribute.
+      if(aPointsToSkeep.find(aFilletPointAttr) != aPointsToSkeep.end()) {
+        myListOfPointsChangedInCode = true;
+        aRefListOfFilletPoints->remove(aFilletPointAttr);
+        myListOfPointsChangedInCode = false;
+        continue;
+      }
+
+      // Obtain constraint coincidence for the fillet point.
+      FeaturePtr aConstraintCoincidence;
+      const std::set<AttributePtr>& aRefsList = aFilletPointAttr->owner()->data()->refsToMe();
+      for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
+        std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+        FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+        if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+          AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
+          AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
+          if(anAttrRefA.get()) {
+            AttributePtr anAttrA = anAttrRefA->attr();
+            if(aFilletPointAttr == anAttrA) {
+              aConstraintCoincidence = aConstrFeature;
+              break;
+            }
+          }
+          if(anAttrRefB.get()) {
+            AttributePtr anAttrB = anAttrRefB->attr();
+            if(aFilletPointAttr == anAttrB) {
+              aConstraintCoincidence = aConstrFeature;
+              break;
+            }
+          }
+        }
+      }
+
+      if(!aConstraintCoincidence.get()) {
+        myNewPoints.clear();
+        setError("Error: No coincident edges at one of the selected points.");
+        return;
+      }
+
+      // Get coincides from constraint.
+      std::set<FeaturePtr> aCoincides;
+
+
+      SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
+                                           SketchPlugin_ConstraintCoincidence::ENTITY_A(),
+                                           aCoincides);
+      SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
+                                           SketchPlugin_ConstraintCoincidence::ENTITY_B(),
+                                           aCoincides);
+
+      // Remove points from set of coincides. Also get all attributes which is equal to this point to exclude it.
+      std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
+      std::set<FeaturePtr> aNewSetOfCoincides;
+      for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+        std::string aFeatureKind = (*anIt)->getKind();
+        if(aFeatureKind == SketchPlugin_Point::ID()) {
+          AttributePtr anAttr = (*anIt)->attribute(SketchPlugin_Point::COORD_ID());
+          std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+          if(aPoint2D.get() && aFilletPnt2d->isEqual(aPoint2D->pnt())) {
+            aPointsToSkeep.insert(anAttr);
+          }
+        } else if(aFeatureKind == SketchPlugin_Line::ID()) {
+          AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Line::START_ID());
+          std::shared_ptr<GeomDataAPI_Point2D> aPointStart2D =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStart);
+          if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) {
+            aPointsToSkeep.insert(anAttrStart);
+          }
+          AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Line::END_ID());
+          std::shared_ptr<GeomDataAPI_Point2D> aPointEnd2D =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrEnd);
+          if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) {
+            aPointsToSkeep.insert(anAttrEnd);
+          }
+          aNewSetOfCoincides.insert(*anIt);
+        } else if(aFeatureKind == SketchPlugin_Arc::ID() ) {
+          AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
+          std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
+          if(aPointCenter2D.get() && aFilletPnt2d->isEqual(aPointCenter2D->pnt())) {
+            aPointsToSkeep.insert(anAttrCenter);
+            continue;
+          }
+          AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Arc::START_ID());
+          std::shared_ptr<GeomDataAPI_Point2D> aPointStart2D =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStart);
+          if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) {
+            aPointsToSkeep.insert(anAttrStart);
+          }
+          AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Arc::END_ID());
+          std::shared_ptr<GeomDataAPI_Point2D> aPointEnd2D =
+            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrEnd);
+          if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) {
+            aPointsToSkeep.insert(anAttrEnd);
+          }
+          aNewSetOfCoincides.insert(*anIt);
+        }
+      }
+      aCoincides = aNewSetOfCoincides;
+
+      // If we still have more than two coincides remove auxilary entities from set of coincides.
+      if(aCoincides.size() > 2) {
+        aNewSetOfCoincides.clear();
+        for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+          if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
+            aNewSetOfCoincides.insert(*anIt);
+          }
+        }
+        aCoincides = aNewSetOfCoincides;
+      }
+
+      if(aCoincides.size() != 2) {
+        myNewPoints.clear();
+        setError("Error: One of the selected points does not have two suitable edges for fillet.");
+        return;
+      }
+
+      // Store base point for fillet.
+      aPointsToSkeep.insert(aFilletPointAttr);
+      myNewPoints.insert(aFilletPointAttr);
+
+      // Get base lines for fillet.
+      FeaturePtr anOldFeatureA, anOldFeatureB;
+      std::set<FeaturePtr>::iterator aLinesIt = aCoincides.begin();
+      anOldFeatureA = *aLinesIt++;
+      anOldFeatureB = *aLinesIt;
+
+      // Getting radius value if it was not changed by user.
+      if(!myRadiusChangedByUser) {
+        // Getting points located at 1/3 of edge length from fillet point.
+        std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
+        std::shared_ptr<GeomAPI_Pnt2d> aPntA, aPntB;
+        getPointOnEdge(anOldFeatureA, aFilletPnt2d, aPntA);
+        getPointOnEdge(anOldFeatureB, aFilletPnt2d, aPntB);
+
+        /// Getting distances.
+        double aDistanceA = getProjectionDistance(anOldFeatureB, aPntA);
+        double aDistanceB = getProjectionDistance(anOldFeatureA, aPntB);
+        double aRadius = aDistanceA < aDistanceB ? aDistanceA / 2.0 : aDistanceB / 2.0;
+        aMinimumRadius = aMinimumRadius == 0 ? aRadius : aRadius < aMinimumRadius ? aRadius : aMinimumRadius;
+      }
+    }
+
+    // Set new default radius if it was not changed by user.
+    if(!myRadiusChangedByUser) {
+      myRadiusChangedInCode = true;
+      aRadiusAttribute->setValue(aMinimumRadius);
+      myRadiusChangedInCode = false;
+    }
+
+  } else if(theID == SketchPlugin_Constraint::VALUE()) {
+    if(myRadiusInitialized && !myRadiusChangedInCode) {
+      myRadiusChangedByUser = true;
+    }
+    if(!myRadiusInitialized) {
+      myRadiusInitialized = true;
+    }
+  }
+*/
+}
+
+//AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
+//{
+//  if (!sketch())
+//    return thePrevious;
+//
+//  AISObjectPtr anAIS = thePrevious;
+//  /// TODO: Equal constraint presentation should be put here
+//  return anAIS;
+//}
+
+bool SketchPlugin_ConstraintSplit::isMacro() const
+{
+  return true;
+}
+
+//void SketchPlugin_ConstraintSplit::clearResults()
+//{
+///*  // Clear auxiliary flag on initial objects.
+//  for(std::map<AttributePtr, FilletFeatures>::iterator aPointsIter = myPointFeaturesMap.begin();
+//      aPointsIter != myPointFeaturesMap.end();) {
+//    const FilletFeatures& aFilletFeatures = aPointsIter->second;
+//    std::list<std::pair<FeaturePtr, bool>>::const_iterator aFeatureIt;
+//    for(aFeatureIt = aFilletFeatures.baseEdgesState.cbegin();
+//        aFeatureIt != aFilletFeatures.baseEdgesState.cend();
+//        ++aFeatureIt) {
+//      aFeatureIt->first->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(aFeatureIt->second);
+//    }
+//    ++aPointsIter;
+//  }
+//
+//  // And remove all produced features.
+//  DocumentPtr aDoc = sketch()->document();
+//  for(std::map<AttributePtr, FilletFeatures>::iterator aPointsIter = myPointFeaturesMap.begin();
+//      aPointsIter != myPointFeaturesMap.end();) {
+//    // Remove all produced constraints.
+//    const FilletFeatures& aFilletFeatures = aPointsIter->second;
+//    std::list<FeaturePtr>::const_iterator aFeatureIt;
+//    for(aFeatureIt = aFilletFeatures.resultConstraints.cbegin();
+//        aFeatureIt != aFilletFeatures.resultConstraints.cend();
+//        ++aFeatureIt) {
+//      aDoc->removeFeature(*aFeatureIt);
+//    }
+//
+//    // Remove all result edges.
+//    for(aFeatureIt = aFilletFeatures.resultEdges.cbegin();
+//        aFeatureIt != aFilletFeatures.resultEdges.cend();
+//        ++aFeatureIt) {
+//      aDoc->removeFeature(*aFeatureIt);
+//    }
+//
+//    // Remove point from map.
+//    myPointFeaturesMap.erase(aPointsIter++);
+//  }
+//*/
+//};
+//
+//
+//// =========   Auxiliary functions   =================
+//void recalculateAttributes(FeaturePtr theNewArc,  const std::string& theNewArcAttribute,
+//                           FeaturePtr theFeature, const std::string& theFeatureAttribute)
+//{
+//  std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//      theNewArc->attribute(theNewArcAttribute))->pnt();
+//  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//      theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
+//}
+
+/*/// \brief Find intersections of lines shifted along normal direction
+void possibleFilletCenterLineLine(
+    std::shared_ptr<GeomAPI_XY> thePointA, std::shared_ptr<GeomAPI_Dir2d> theDirA,
+    std::shared_ptr<GeomAPI_XY> thePointB, std::shared_ptr<GeomAPI_Dir2d> theDirB,
+    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+  std::shared_ptr<GeomAPI_Dir2d> aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x()));
+  std::shared_ptr<GeomAPI_Dir2d> aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x()));
+  std::shared_ptr<GeomAPI_XY> aPntA, aPntB;
+  double aDet = theDirA->cross(theDirB);
+  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
+    aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius));
+    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
+      aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius));
+      double aVX = aDirAT->xy()->dot(aPntA);
+      double aVY = aDirBT->xy()->dot(aPntB);
+      std::shared_ptr<GeomAPI_XY> aPoint(new GeomAPI_XY(
+          (theDirB->x() * aVX - theDirA->x() * aVY) / aDet,
+          (theDirB->y() * aVX - theDirA->y() * aVY) / aDet));
+      theCenters.push_back(aPoint);
+    }
+  }
+}
+
+/// \brief Find intersections of line shifted along normal direction in both sides
+///        and a circle with extended radius
+void possibleFilletCenterLineArc(
+    std::shared_ptr<GeomAPI_XY> theStartLine, std::shared_ptr<GeomAPI_Dir2d> theDirLine,
+    std::shared_ptr<GeomAPI_XY> theCenterArc, double theRadiusArc,
+    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+  std::shared_ptr<GeomAPI_Dir2d> aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x()));
+  std::shared_ptr<GeomAPI_XY> aPnt;
+  double aDirNorm2 = theDirLine->dot(theDirLine);
+  double aRad = 0.0;
+  double aDirX = theDirLine->x();
+  double aDirX2 = theDirLine->x() * theDirLine->x();
+  double aDirY2 = theDirLine->y() * theDirLine->y();
+  double aDirXY = theDirLine->x() * theDirLine->y();
+  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
+    aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius));
+    double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc));
+    double aCoeff2 = aCoeff * aCoeff;
+    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
+      aRad = theRadiusArc + aStepB * theRadius;
+      double aD = aRad * aRad * aDirNorm2 - aCoeff2;
+      if (aD < 0.0)
+        continue;
+      double aDs = sqrt(aD);
+      double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2;
+      double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2;
+      double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
+          aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2;
+      double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
+          aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2;
+
+      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
+      theCenters.push_back(aPoint1);
+      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
+      theCenters.push_back(aPoint2);
+    }
+  }
+}
+
+/// \brief Find intersections of two circles with extended radii
+void possibleFilletCenterArcArc(
+    std::shared_ptr<GeomAPI_XY> theCenterA, double theRadiusA,
+    std::shared_ptr<GeomAPI_XY> theCenterB, double theRadiusB,
+    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+  std::shared_ptr<GeomAPI_XY> aCenterDir = theCenterB->decreased(theCenterA);
+  double aCenterDist2 = aCenterDir->dot(aCenterDir);
+  double aCenterDist = sqrt(aCenterDist2);
+
+  double aRadA, aRadB;
+  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
+    aRadA = theRadiusA + aStepA * theRadius;
+    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
+      aRadB = theRadiusB + aStepB * theRadius;
+      if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist)
+        continue; // there is no intersections
+
+      double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist);
+      double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist);
+
+      double x1 = theCenterA->x() + (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist;
+      double y1 = theCenterA->y() + (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist;
+
+      double x2 = theCenterA->x() + (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist;
+      double y2 = theCenterA->y() + (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist;
+
+      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
+      theCenters.push_back(aPoint1);
+      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
+      theCenters.push_back(aPoint2);
+    }
+  }
+}
+
+void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
+                           double theRadius, bool theNotInversed[2],
+                           std::shared_ptr<GeomAPI_XY>& theCenter,
+                           std::shared_ptr<GeomAPI_XY>& theTangentA,
+                           std::shared_ptr<GeomAPI_XY>& theTangentB)
+{
+  static const int aNbFeatures = 2;
+  FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB};
+  std::shared_ptr<GeomAPI_XY> aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures];
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, aEndPoint;
+
+  for (int i = 0; i < aNbFeatures; i++) {
+    if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
+      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Line::START_ID()));
+      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Line::END_ID()));
+    } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
+      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Arc::START_ID()));
+      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Arc::END_ID()));
+      aCenter[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy();
+    } else
+      return;
+    aStart[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
+        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) :
+        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()));
+    aEnd[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
+        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) :
+        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()));
+  }
+
+  if (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Dir2d> aDir[2];
+    std::shared_ptr<GeomAPI_Dir2d> aDirT[2];
+    for (int i = 0; i < aNbFeatures; i++) {
+      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i])));
+      aDirT[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x()));
+    }
+
+    // get and filter possible centers
+    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+    possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], theRadius, aSuspectCenters);
+    double aDot = 0.0;
+    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+    for (; anIt != aSuspectCenters.end(); anIt++) {
+      aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt));
+      theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot));
+      if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0)
+        continue; // incorrect position
+      aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt));
+      theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot));
+      if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0)
+        continue; // incorrect position
+      // the center is found, stop searching
+      theCenter = *anIt;
+      return;
+    }
+  } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Line::ID()) || 
+      (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Arc::ID())) {
+    int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1;
+    double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]);
+    std::shared_ptr<GeomAPI_Dir2d> aDirLine = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd])));
+    std::shared_ptr<GeomAPI_Dir2d> aDirT = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x()));
+
+    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd])));
+    std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd])));
+    double anArcAngle = aEndArcDir->angle(aStartArcDir);
+
+    // get possible centers and filter them
+    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+    possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd], anArcRadius, theRadius, aSuspectCenters);
+    double aDot = 0.0;
+    // the line is forward into the arc
+    double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy());
+    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
+    // The possible centers are ranged by their positions.
+    // If the point is not satisfy one of criteria, the weight is decreased with penalty.
+    int aBestWeight = 0;
+    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+    for (; anIt != aSuspectCenters.end(); anIt++) {
+      int aWeight = 2;
+      aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt));
+      aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot));
+      // Check the point is placed on the correct arc (penalty if false)
+      if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc)
+        aWeight -= 1;
+      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd])));
+      double aCurAngle = aCurDir->angle(aStartArcDir);
+      if (anArcAngle < 0.0) aCurAngle *= -1.0;
+      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle))
+        continue;
+      if (aWeight > aBestWeight)
+        aBestWeight = aWeight;
+      else if (aWeight < aBestWeight ||
+               aStart[aLineInd]->distance(*anIt) >
+               aStart[aLineInd]->distance(theCenter)) // <-- take closer point
+        continue;
+      // the center is found, stop searching
+      theCenter = *anIt;
+      anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius));
+      if (theFeatureA->getKind() == SketchPlugin_Line::ID()) {
+        theTangentA = aLineTgPoint;
+        theTangentB = anArcTgPoint;
+      } else {
+        theTangentA = anArcTgPoint;
+        theTangentB = aLineTgPoint;
+      }
+      //return;
+    }
+  } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Arc::ID()) {
+    double anArcRadius[aNbFeatures];
+    double anArcAngle[aNbFeatures];
+    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir[aNbFeatures];
+    for (int i = 0; i < aNbFeatures; i++) {
+      anArcRadius[i] = aStart[i]->distance(aCenter[i]);
+      aStartArcDir[i] = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i])));
+      std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i])));
+      anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]);
+    }
+
+    // get and filter possible centers
+    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+    possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1], anArcRadius[1], theRadius, aSuspectCenters);
+    double aDot = 0.0;
+    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
+    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+    for (; anIt != aSuspectCenters.end(); anIt++) {
+      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0])));
+      double aCurAngle = aCurDir->angle(aStartArcDir[0]);
+      if (anArcAngle[0] < 0.0) aCurAngle *= -1.0;
+      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0]))
+        continue; // incorrect position
+      theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0]));
+
+      aCurDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1])));
+      aCurAngle = aCurDir->angle(aStartArcDir[1]);
+      if (anArcAngle[1] < 0.0) aCurAngle *= -1.0;
+      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1]))
+        continue; // incorrect position
+      theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1]));
+
+      // the center is found, stop searching
+      theCenter = *anIt;
+      return;
+    }
+  }
+}
+
+void getPointOnEdge(const FeaturePtr theFeature,
+                    const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
+                    std::shared_ptr<GeomAPI_Pnt2d>& thePoint) {
+  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+    if(aPntStart->distance(theFilletPoint) > 1.e-7) {
+      aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+      aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    }
+    thePoint.reset( new GeomAPI_Pnt2d(aPntStart->xy()->added( aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) );
+  } else {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntTemp;
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+    if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) {
+      aPntTemp = aPntStart;
+      aPntStart = aPntEnd;
+      aPntEnd = aPntTemp;
+    }
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
+    double aStartParameter(0), anEndParameter(0);
+    aCirc->parameter(aPntStart, paramTolerance, aStartParameter);
+    aCirc->parameter(aPntEnd, paramTolerance, anEndParameter);
+    if(aPntStart->distance(theFilletPoint) > tolerance) {
+      double aTmpParameter = aStartParameter;
+      aStartParameter = anEndParameter;
+      anEndParameter = aTmpParameter;
+    }
+    double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0;
+    aCirc->D0(aPntParameter, thePoint);
+  }
+}
+
+double getProjectionDistance(const FeaturePtr theFeature,
+                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint)
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aProjectPnt;
+  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Lin2d> aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd));
+    aProjectPnt = aLin->project(thePoint);
+  } else {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
+    aProjectPnt = aCirc->project(thePoint);
+  }
+  if(aProjectPnt.get()) {
+    return aProjectPnt->distance(thePoint);
+  }
+  return -1;
+}
+
+std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
+{
+  std::set<FeaturePtr> aCoincides;
+
+  std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt = SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence);
+
+  SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
+                                       SketchPlugin_ConstraintCoincidence::ENTITY_A(),
+                                       aCoincides);
+  SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
+                                       SketchPlugin_ConstraintCoincidence::ENTITY_B(),
+                                       aCoincides);
+
+  // Remove points from set of coincides.
+  std::set<FeaturePtr> aNewSetOfCoincides;
+  for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+    if((*anIt)->getKind() == SketchPlugin_Line::ID()) {
+      aNewSetOfCoincides.insert(*anIt);
+    } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
+      AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
+      std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
+      if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) {
+        continue;
+      }
+      aNewSetOfCoincides.insert(*anIt);
+    }
+  }
+  aCoincides = aNewSetOfCoincides;
+
+  // If we still have more than two coincides remove auxilary entities from set of coincides.
+  if(aCoincides.size() > 2) {
+    aNewSetOfCoincides.clear();
+    for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+      if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
+        aNewSetOfCoincides.insert(*anIt);
+      }
+    }
+    aCoincides = aNewSetOfCoincides;
+  }
+
+  return aCoincides;
+}
+*/
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.h b/src/SketchPlugin/SketchPlugin_ConstraintSplit.h
new file mode 100755 (executable)
index 0000000..d084b80
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_ConstraintSplit.h
+// Created: 19 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintSplit_H_
+#define SketchPlugin_ConstraintSplit_H_
+
+#include "SketchPlugin.h"
+#include <SketchPlugin_Sketch.h>
+#include "SketchPlugin_ConstraintBase.h"
+
+/** \class SketchPlugin_ConstraintSplit
+ *  \ingroup Plugins
+ *  \brief Feature for creation of a new constraint filleting two objects which have coincident point
+ *
+ *  This constraint has three attributes:
+ *  SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B() for the filleting objects;
+ *  SketchPlugin_Constraint::VALUE() contains radius of filleting circular arc
+ *
+ *  Also the constraint has attribute SketchPlugin_Constraint::ENTITY_C()
+ *  which contains created list objects forming the fillet
+ */
+class SketchPlugin_ConstraintSplit : public SketchPlugin_ConstraintBase
+{
+ public:
+   /*struct FilletFeatures {
+    std::list<std::pair<FeaturePtr, bool>> baseEdgesState; ///< list of objects the fillet is based and its states
+    std::list<FeaturePtr> resultEdges; ///< list of result edges
+    std::list<FeaturePtr> resultConstraints; ///< list of constraints provided by the fillet
+   };*/
+
+  /// Split constraint kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_CONSTRAINT_SPLIT_ID("SketchConstraintSplit");
+    return MY_CONSTRAINT_SPLIT_ID;
+  }
+  /// \brief Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_ConstraintSplit::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();
+
+  /// 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);
+
+  /// Returns the AIS preview
+  //SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const;
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintSplit();
+
+  /// \return map of base points and features;
+  //SKETCHPLUGIN_EXPORT const std::map<AttributePtr, FilletFeatures> pointsFeaturesMap() const {
+  //  return myPointFeaturesMap;
+  //};
+
+private:
+  /// \ Removes all produced features and restore base edges.
+  //void clearResults();
+
+private:
+  //std::set<AttributePtr> myNewPoints; ///< set of new points
+  //std::map<AttributePtr, FilletFeatures> myPointFeaturesMap; ///< map of point and features for fillet
+  //bool myListOfPointsChangedInCode; ///< flag to track that list of points changed in code
+  //bool myRadiusChangedByUser; ///< flag to track that radius changed by user
+  //bool myRadiusChangedInCode; ///< flag to track that radius changed in code
+  //bool myRadiusInitialized; /// < flag to track that radius initialized
+};
+
+#endif
index 635583b0c14011a42a5f6d631431eb8442655f2f..ebead598fd24845451913a8d99b8e364a0684f63 100644 (file)
@@ -14,6 +14,7 @@
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintSplit.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMiddle.h>
@@ -76,6 +77,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_SolverErrorValidator);
   aFactory->registerValidator("SketchPlugin_FilletVertexValidator",
                               new SketchPlugin_FilletVertexValidator);
+  aFactory->registerValidator("SketchPlugin_SplitValidator",
+                              new SketchPlugin_SplitValidator);
   aFactory->registerValidator("SketchPlugin_MiddlePointAttr",
                               new SketchPlugin_MiddlePointAttrValidator);
   aFactory->registerValidator("SketchPlugin_ArcTangentPoint",
@@ -161,6 +164,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(string theFeatureID)
     return FeaturePtr(new SketchPlugin_ConstraintMirror);
   } else if (theFeatureID == SketchPlugin_ConstraintFillet::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintFillet);
+  } else if (theFeatureID == SketchPlugin_ConstraintSplit::ID()) {
+    return FeaturePtr(new SketchPlugin_ConstraintSplit);
   } else if (theFeatureID == SketchPlugin_MultiTranslation::ID()) {
     return FeaturePtr(new SketchPlugin_MultiTranslation);
   } else if (theFeatureID == SketchPlugin_MultiRotation::ID()) {
@@ -224,6 +229,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_ConstraintMiddle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintMirror::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintFillet::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_ConstraintSplit::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintAngle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MultiRotation::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MultiTranslation::ID(), aHasSketchPlane);
index 9b3d82c828a5a0ef05aaaa6fb5d64d32c3dfc4d2..b488d4fa0d30a2c2569691fd49f3099e61ac3640 100755 (executable)
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
 #include <ModelAPI_ResultConstruction.h>
 
+#include <ModelGeomAlgo_Point2D.h>
+
 #include <GeomAPI_Circ.h>
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Edge.h>
@@ -847,6 +850,56 @@ bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribut
   return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
 }
 
+bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
+                                          const std::list<std::string>& theArguments,
+                                          Events_InfoMessage& theError) const
+{
+  bool aValid = false;
+
+  if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
+    theError = "The attribute with the %1 type is not processed";
+    theError.arg(theAttribute->attributeType());
+    return aValid;
+  }
+  AttributeSelectionPtr aFeatureAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+
+  ObjectPtr anAttrObject = aFeatureAttr->context();
+  FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
+  if (!anAttrFeature)
+    return aValid;
+
+  std::string aKind = anAttrFeature->getKind();
+  if (aKind == SketchPlugin_Line::ID() ||
+      aKind == SketchPlugin_Arc::ID() ||
+      aKind == SketchPlugin_Circle::ID()) {
+
+    std::set<GeomShapePtr> anEdgeShapes;
+    ModelAPI_Tools::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
+    if (anEdgeShapes.empty())
+      return aValid;
+
+    GeomShapePtr anAttrShape = *anEdgeShapes.begin();
+
+  //std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr(
+  //             anAttrFeature, theAttribute, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+
+    std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
+    //ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature.get(), SketchPlugin_ConstraintCoincidence::ID(),
+    //                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+
+    //ModelGeomAlgo_Point2D::filterPointsToBeInsideShape(anAttrShape, aRefAttributes, );
+
+    int aCoincidentToFeature = aRefAttributes.size();
+    if (aKind == SketchPlugin_Circle::ID())
+      aValid = aCoincidentToFeature > 2;
+    else
+      aValid = aCoincidentToFeature > 1;
+  }
+
+  return true;
+}
+
 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
                                                const std::list<std::string>& theArguments,
                                                Events_InfoMessage& theError) const
index 2ebb8ad76f0ee3a9e5548606b5629baa9adec827..70120d614a640331a6f65fc1800d725591c2d710 100644 (file)
@@ -218,6 +218,27 @@ class SketchPlugin_ArcTangentPointValidator : public ModelAPI_AttributeValidator
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_SplitValidator
+ * \ingroup Validators
+ * \brief Validator for the entity of the following type:
+ * - Linear segment with point(s) coinident to this line
+ * - Arc with point(s) coincident to the arc
+ * - Circle with at least 2 split-points on this circle
+ *
+ * Checks that there are coincident point on selected feature.
+ */
+class SketchPlugin_SplitValidator : public ModelAPI_AttributeValidator
+{
+ public:
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 /**\class SketchPlugin_IntersectionValidator
  * \ingroup Validators
  * \brief Validator for the attribute to be intersected with the sketch plane.
index 5a7e90e6eaff0fdaf4d5ff08416586019d5a9ff7..e3c2e600a95ca193283c305c1af20f9545230f40 100644 (file)
       <translation>Second object is not selected</translation>
     </message>
   </context>
-  
+
+  <context>
+    <name>SketchConstraintSplit</name>
+    <message>
+      <source>ConstraintEntityA - SketchPlugin_SplitValidator: The attribute with the %1 type is not processed</source>
+      <translation>Only attribute selection can be used for the sketch face, not %1</translation>
+    </message>
+  </context>
+
   <context>
     <name>SketchConstraintFillet</name>
     <message>
index 0d2eb9c05d5115cd62df5e95864cb1d78c2d707e..3f1db5400900acda00868b28f7c779b4c5781137 100644 (file)
@@ -5,7 +5,7 @@
     <group id="Linear geometry">
       <feature
         id="Sketch"
-        nested="SketchPoint SketchIntersectionPoint SketchLine SketchCircle SketchArc SketchRectangle SketchProjection SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
+        nested="SketchPoint SketchIntersectionPoint SketchLine SketchCircle SketchArc SketchRectangle SketchProjection SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintSplit SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
         when_nested="accept abort"
         title="Sketch"
         tooltip="Create sketch"
         </doublevalue>
         <validator id="PartSet_FilletSelection"/>
       </feature>
+      <!--  SketchConstraintSplit  -->
+      <feature id="SketchConstraintSplit" title="Split" tooltip="Create constraints defining split of linear segment, arc or circle" icon="icons/Sketch/split.png">
+        <sketch_shape_selector
+            id="ConstraintEntityA"
+            label="Split feature"
+            tooltip="Select feature for split"
+            shape_types="edge"
+            use_external="false">
+          <validator id="SketchPlugin_SplitValidator"/>
+        </sketch_shape_selector>
+      </feature>
     </group>
 
     <group id="Projection">
index 236833f241a3ba83a3905de2441bb4d18f1a9214..624b98cb6d0579c0ad284ba2d1444ff2282f9311 100644 (file)
@@ -55,6 +55,7 @@ SET(PROJECT_SOURCES
 SET(PROJECT_LIBRARIES
     Config
     ModelAPI
+    ModelGeomAlgo
     GeomAPI
     GeomDataAPI
     Events
@@ -96,6 +97,7 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/Config
   ${PROJECT_SOURCE_DIR}/src/Events
   ${PROJECT_SOURCE_DIR}/src/ModelAPI
+  ${PROJECT_SOURCE_DIR}/src/ModelGeomAlgo
   ${PROJECT_SOURCE_DIR}/src/GeomAPI
   ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
   ${PROJECT_SOURCE_DIR}/src/SketchPlugin
index 45f4eaaf976c88fc285aa22e8068e630539380a4..84d0878f66df2d68817c3f3f12620e322a5bd50b 100644 (file)
@@ -17,6 +17,8 @@
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_Events.h>
 
+#include <ModelGeomAlgo_Point2D.h>
+
 #include <Events_InfoMessage.h>
 
 #include <GeomDataAPI_Point2D.h>
@@ -77,27 +79,8 @@ std::shared_ptr<GeomAPI_Shape> getShape(ObjectPtr theObject)
 std::shared_ptr<GeomAPI_Pnt2d> getPoint(ModelAPI_Feature* theFeature,
                                         const std::string& theAttribute)
 {
-  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
-
-  /// essential check as it is called in openGl thread
-  if (!theFeature || !theFeature->data().get() || !theFeature->data()->isValid())
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-
-  FeaturePtr aFeature;
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
-  if(!anAttr.get()) {
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-  }
-  aFeature = ModelAPI_Feature::feature(anAttr->object());
-
-  if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
-    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
-
-  else if (anAttr->attr()) {
-    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
-  }
+  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr(
+               theFeature, theAttribute, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
   if (aPointAttr.get() != NULL)
     return aPointAttr->pnt();
   return std::shared_ptr<GeomAPI_Pnt2d>();
index 6312c827b50f478fd629da33c72f858007957e6e..c3b079f05cb0299fd275c40530863e55f15b66de 100644 (file)
@@ -130,18 +130,15 @@ bool XGUI_ModuleConnector::canStartOperation(QString theId)
   return myWorkshop->operationMgr()->canStartOperation(theId);
 }
 
-void XGUI_ModuleConnector::processLaunchOperation(ModuleBase_Operation* theOperation,
-                                                  const bool isUpdatePropertyPanel)
+void XGUI_ModuleConnector::processLaunchOperation(ModuleBase_Operation* theOperation)
 {
   XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr();
 
   if (anOperationMgr->startOperation(theOperation)) {
-    if (isUpdatePropertyPanel) {
-      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
-      if (aFOperation) {
-        workshop()->propertyPanel()->updateContentWidget(aFOperation->feature());
-        workshop()->propertyPanel()->createContentPanel(aFOperation->feature());
-      }
+    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
+    if (aFOperation) {
+      workshop()->propertyPanel()->updateContentWidget(aFOperation->feature());
+      workshop()->propertyPanel()->createContentPanel(aFOperation->feature());
     }
     if (!theOperation->getDescription()->hasXmlRepresentation()) {
       if (theOperation->commit())
index 423bcbdcdb83d4b3f5d4155b7f639031d15eb1ac..0a00cf57b370204d1a947fcd70ed94547e0e2d8c 100644 (file)
@@ -59,8 +59,7 @@ Q_OBJECT
 
   //! Performs the operation launch
   //! \param theOperation an operation to be launched
-  virtual void processLaunchOperation(ModuleBase_Operation* theOperation,
-                                      const bool isUpdatePropertyPanel);
+  virtual void processLaunchOperation(ModuleBase_Operation* theOperation);
 
   //! Returns started operation by the operation identifier. The operation manager is called.
   //! \param theId an operation id
index d975519a338c303e0dd4808f12c21f44de39a9c8..1fb45442d3784107e2e64a645d1d1d0930059844 100644 (file)
@@ -470,9 +470,6 @@ void XGUI_OperationMgr::onBeforeOperationStarted()
     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
 #endif
-  ModuleBase_IModule* aModule = myWorkshop->module();
-  if (aModule)
-    aModule->beforeOperationStarted(aFOperation);
   }
 }
 
@@ -480,7 +477,8 @@ void XGUI_OperationMgr::onOperationStarted()
 {
   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
   updateApplyOfOperations(aSenderOperation);
-  emit operationStarted(aSenderOperation);
+  XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
+  aWorkshop->operationStarted(aSenderOperation);
 }
 
 void XGUI_OperationMgr::onBeforeOperationAborted()
index 41d678c599678afa5c04ec0cff62395cd5539b6d..cca5bb926a37e9c32b903f1a7b36e28ceea54b3e 100755 (executable)
@@ -127,9 +127,6 @@ public slots:
   bool abortAllOperations();
 
 signals:
-  /// Signal about an operation is started. It is emitted after the start() of operation is done.
-  void operationStarted(ModuleBase_Operation* theOperation);
-
   /// Signal about an operation is stopped. It is emitted after the stop() of operation is done.
   /// \param theOperation a stopped operation
   void operationStopped(ModuleBase_Operation* theOperation);
index ca80dce9fd40037de9672b78acb23d1dd41bd911..fd3b111b61e1cc307b3822606074d6982a90db17 100755 (executable)
@@ -177,8 +177,6 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
 
   myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop);
 
-  connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), 
-          SLOT(onOperationStarted(ModuleBase_Operation*)));
   connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)),
           SLOT(onOperationResumed(ModuleBase_Operation*)));
   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
@@ -488,7 +486,7 @@ bool XGUI_Workshop::isFeatureOfNested(const FeaturePtr& theFeature)
   return aHasNested;
 }
 
-void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation)
+void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation)
 {
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
   if (!aFOperation)
@@ -583,20 +581,13 @@ void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect)
   }
 }
 
-//******************************************************
-void XGUI_Workshop::onOperationStarted(ModuleBase_Operation* theOperation)
-{
-  setGrantedFeatures(theOperation);
-  myModule->operationStarted(theOperation);
-}
-
 //******************************************************
 void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
 {
   setGrantedFeatures(theOperation);
 
   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
-    setPropertyPanel(theOperation);
+    fillPropertyPanel(theOperation);
     connectToPropertyPanel(true);
   }
   updateCommandStatus();
@@ -679,10 +670,7 @@ void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation)
   aFOperation->setGrantedOperationIds(aGrantedIds);
 }
 
-
-/*
- * Saves document with given name.
- */
+//******************************************************
 void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>& theFileNames)
 {
   QApplication::restoreOverrideCursor();
@@ -691,11 +679,24 @@ void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>&
   QApplication::restoreOverrideCursor();
 }
 
+//******************************************************
 bool XGUI_Workshop::abortAllOperations()
 {
   return myOperationMgr->abortAllOperations();
 }
 
+//******************************************************
+void XGUI_Workshop::operationStarted(ModuleBase_Operation* theOperation)
+{
+  setGrantedFeatures(theOperation);
+  if (!theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
+    updateCommandStatus();
+  }
+  else {
+    myModule->operationStarted(theOperation);
+  }
+}
+
 //******************************************************
 void XGUI_Workshop::onOpen()
 {
index fea7600a04992929202324f2de8801d765861425..1a90b4dc674b1cd43e77171e602f0f8d53c449af 100755 (executable)
@@ -246,6 +246,12 @@ Q_OBJECT
    */
   bool abortAllOperations();
 
+  /// Updates workshop state according to the started operation, e.g. visualizes the property panel
+  /// and connect to it.
+  /// \param theOpertion a started operation
+  void operationStarted(ModuleBase_Operation* theOperation);
+
+
   //! Delete features. Delete the referenced features. There can be a question with a list of
   //! referenced objects.
   //! \param theFeatures a list of objects to be deleted
@@ -277,7 +283,7 @@ Q_OBJECT
   /// Update the property panel content by the XML description of the operation and set the panel
   /// into the operation
   /// \param theOperation an operation
-  void setPropertyPanel(ModuleBase_Operation* theOperation);
+  void fillPropertyPanel(ModuleBase_Operation* theOperation);
 
   /// Connects or disconnects to the value changed signal of the property panel widgets
   /// \param isToConnect a boolean value whether connect or disconnect
@@ -405,7 +411,7 @@ private:
   /// SLOT, that is called after the operation is started. Update workshop state according to
   /// the started operation, e.g. visualizes the property panel and connect to it.
   /// \param theOpertion a started operation
-  void onOperationStarted(ModuleBase_Operation* theOperation);
+  // void onOperationStarted(ModuleBase_Operation* theOperation);
 
   /// SLOT, that is called after the operation is resumed. Update workshop state according to
   /// the started operation, e.g. visualizes the property panel and connect to it.