Salome HOME
Task #3231: Sketcher Offset of a curve
authorArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Fri, 26 Jun 2020 08:56:40 +0000 (11:56 +0300)
committerArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Fri, 26 Jun 2020 08:56:40 +0000 (11:56 +0300)
Redesign storing the offset entities.

16 files changed:
src/GeomAlgoAPI/GeomAlgoAPI.i
src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Offset.h
src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.h
src/SketchAPI/SketchAPI_Offset.cpp
src/SketchAPI/SketchAPI_Offset.h
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/SketchPlugin_Offset.cpp
src/SketchPlugin/SketchPlugin_Offset.h
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/SketchSolver_ConstraintOffset.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintOffset.h [new file with mode: 0644]

index f2076869f927d0f9ab971aaf053d2a104d36d0cd..fcca5e7d934b85cc4530b0dda0249b8e0fda4c84 100644 (file)
@@ -58,6 +58,7 @@
 %shared_ptr(GeomAlgoAPI_Copy)
 %shared_ptr(GeomAlgoAPI_Symmetry)
 %shared_ptr(GeomAlgoAPI_MapShapesAndAncestors)
+%shared_ptr(GeomAlgoAPI_WireBuilder)
 
 // all supported interfaces
 %include "GeomAlgoAPI_MakeShape.h"
index b86bb42bca48b431d64b72f36eb2faba3078a3ed..4b0bb4031f51d42b85e808be836b9e478a3e5956 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "GeomAlgoAPI_Offset.h"
 
+#include <GeomAPI_Pln.h>
+
 #include <BRepOffsetAPI_MakeOffsetShape.hxx>
 #include <BRepOffsetAPI_MakeOffset.hxx>
 
@@ -60,18 +62,10 @@ void GeomAlgoAPI_Offset::generated(const GeomShapePtr theOldShape,
   }
 }
 
-//GeomShapePtr GeomAlgoAPI_Offset::OffsetInPlane (const std::shared_ptr<GeomAPI_Pln>& thePlane,
-//                                                const ListOfShape& theEdgesAndWires,
-//                                                const double theOffsetValue)
-//{
-//}
-
-GeomShapePtr GeomAlgoAPI_Offset::OffsetInPlane (const std::shared_ptr<GeomAPI_Pln>& thePlane,
-                                                const GeomShapePtr& theEdgeOrWire,
-                                                const double theOffsetValue)
+GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomPlanePtr& thePlane,
+                                       const GeomShapePtr& theEdgeOrWire,
+                                       const double theOffsetValue)
 {
-  GeomShapePtr aResult;
-
   // 1. Make wire from edge, if need
   TopoDS_Wire aWire;
   TopoDS_Shape anEdgeOrWire = theEdgeOrWire->impl<TopoDS_Shape>();
@@ -87,21 +81,24 @@ GeomShapePtr GeomAlgoAPI_Offset::OffsetInPlane (const std::shared_ptr<GeomAPI_Pl
     }
   }
   if (aWire.IsNull())
-    return aResult;
+    return;
 
   // 2. Make invalid face to pass it in Offset algorithm
   BRepBuilderAPI_MakeFace aFaceBuilder (thePlane->impl<gp_Pln>(), aWire);
   const TopoDS_Face& aFace = aFaceBuilder.Face();
 
   // 3. Make Offset
-  BRepOffsetAPI_MakeOffset aParal;
-  aParal.Init(aFace, GeomAbs_Arc, Standard_True);
-  aParal.Perform(theOffsetValue, 0.);
-  if (aParal.IsDone()) {
-    TopoDS_Shape anOffset = aParal.Shape();
-    aResult.reset(new GeomAPI_Shape());
+  BRepOffsetAPI_MakeOffset* aParal = new BRepOffsetAPI_MakeOffset;
+  setImpl(aParal);
+  setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+  aParal->Init(aFace, GeomAbs_Arc, Standard_True);
+  aParal->Perform(theOffsetValue, 0.);
+  if (aParal->IsDone()) {
+    TopoDS_Shape anOffset = aParal->Shape();
+    GeomShapePtr aResult(new GeomAPI_Shape());
     aResult->setImpl(new TopoDS_Shape(anOffset));
+    setShape(aResult);
+    setDone(true);
   }
-
-  return aResult;
 }
index ee6d51062be446bc0171c595677ff6018dfd6fa2..608939d906ae63772a9faf895d59cbd52d6db990 100644 (file)
@@ -23,7 +23,7 @@
 #include <GeomAlgoAPI.h>
 #include <GeomAlgoAPI_MakeShape.h>
 
-#include <GeomAPI_Pln.h>
+class GeomAPI_Pln;
 
 /// \class GeomAlgoAPI_Offset
 /// \ingroup DataAlgo
@@ -35,22 +35,20 @@ public:
   GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
                                         const double theOffsetValue);
 
+  /// \brief Perform the offset algorithm on the plane
+  /// \param[in] thePlane base plane for all offsets
+  /// \param[in] theEdgesOrWire base shapes
+  /// \param[in] theOffsetValue offset distance, it can be negative
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const std::shared_ptr<GeomAPI_Pln>& thePlane,
+                                        const GeomShapePtr& theEdgeOrWire,
+                                        const double theOffsetValue);
+
   /// \return the list of shapes generated from the shape \a theShape.
   /// \param[in] theOldShape base shape.
   /// \param[out] theNewShapes shapes generated from \a theShape. Does not cleared!
   GEOMALGOAPI_EXPORT virtual void generated(const GeomShapePtr theOldShape,
                                             ListOfShape& theNewShapes);
 
-  /// \return a compound of offset wires
-  /// \param[in] thePlane base plane for all offsets
-  /// \param[in] theEdgesAndWires base shapes
-  /// \param[in] theOffsetValue offset distance, it can be negative
-  //GEOMALGOAPI_EXPORT static GeomShapePtr OffsetInPlane (const std::shared_ptr<GeomAPI_Pln>& thePlane,
-  //                                                      const ListOfShape& theEdgesAndWires,
-  //                                                      const double theOffsetValue);
-  GEOMALGOAPI_EXPORT static GeomShapePtr OffsetInPlane (const std::shared_ptr<GeomAPI_Pln>& thePlane,
-                                                        const GeomShapePtr& theEdgeOrWire,
-                                                        const double theOffsetValue);
 
 private:
   /// \brief Perform offset operation
index 00c1e79d1e91119604b75a4f495e7127820e7f4c..53bc674a4bfc4954add5d3e0e073eae2c76d6ff8 100644 (file)
 #include <GeomAPI_Vertex.h>
 #include <GeomAPI_ShapeExplorer.h>
 
+#include <BRep_Tool.hxx>
 #include <BRepBuilderAPI_MakeWire.hxx>
+#include <Geom_Curve.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Wire.hxx>
 #include <TopExp_Explorer.hxx>
 
-//=================================================================================================
-GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
+static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
+{
+  GeomShapePtr aResultShape(new GeomAPI_Shape());
+  aResultShape->setImpl(new TopoDS_Shape(theShape));
+  return aResultShape;
+}
+
+GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes)
 {
   TopTools_ListOfShape aListOfEdges;
 
   ListOfShape::const_iterator anIt = theShapes.cbegin();
-  for(; anIt != theShapes.cend(); ++anIt) {
+  for (; anIt != theShapes.cend(); ++anIt) {
     const TopoDS_Shape& aShape = (*anIt)->impl<TopoDS_Shape>();
-    switch(aShape.ShapeType()) {
-      case TopAbs_EDGE: {
-        aListOfEdges.Append(aShape);
-        break;
+    switch (aShape.ShapeType()) {
+    case TopAbs_EDGE: {
+      aListOfEdges.Append(aShape);
+      break;
+    }
+    case TopAbs_WIRE: {
+      for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+        aListOfEdges.Append(anExp.Current());
       }
-      case TopAbs_WIRE: {
-        for(TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
-          aListOfEdges.Append(anExp.Current());
+      break;
+    }
+    default:
+      break;
+    }
+  }
+
+  BRepBuilderAPI_MakeWire* aWireBuilder = new BRepBuilderAPI_MakeWire;
+  aWireBuilder->Add(aListOfEdges);
+  if (aWireBuilder->Error() == BRepBuilderAPI_WireDone) {
+    setImpl(aWireBuilder);
+    setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+    // store generated/modified shapes
+    TopoDS_Wire aWire = aWireBuilder->Wire();
+    for (TopTools_ListOfShape::Iterator aBaseIt(aListOfEdges); aBaseIt.More(); aBaseIt.Next()) {
+      TopoDS_Edge aBaseCurrent = TopoDS::Edge(aBaseIt.Value());
+      Standard_Real aFirst, aLast;
+      Handle(Geom_Curve) aBaseCurve = BRep_Tool::Curve(aBaseCurrent, aFirst, aLast);
+
+      for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+        TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
+        Handle(Geom_Curve) aNewCurve = BRep_Tool::Curve(aNewCurrent, aFirst, aLast);
+        if (aBaseCurve == aNewCurve) {
+          GeomShapePtr aBaseShape = fromTopoDS(aBaseCurrent);
+          GeomShapePtr aNewShape = fromTopoDS(aNewCurrent);
+          addGenerated(aBaseShape, aNewShape);
+          addModified(aBaseShape, aNewShape);
         }
-        break;
-      }
-      default: {
-        return GeomShapePtr();
       }
     }
-  }
 
-  BRepBuilderAPI_MakeWire aWireBuilder;
-  aWireBuilder.Add(aListOfEdges);
-  if(aWireBuilder.Error() != BRepBuilderAPI_WireDone) {
-    return GeomShapePtr();
+    setShape(fromTopoDS(aWire));
+    setDone(true);
   }
+}
 
-  GeomShapePtr aResultShape(new GeomAPI_Shape());
-  aResultShape->setImpl(new TopoDS_Shape(aWireBuilder.Wire()));
-  return aResultShape;
+//=================================================================================================
+GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
+{
+  return GeomAlgoAPI_WireBuilder(theShapes).shape();
 }
 
 //=================================================================================================
index 8de0888e6ef25b08cea25c0fa0570c6778ad200d..6824c155051018f51ed2ec881963f93f7db38232 100644 (file)
 #define GeomAlgoAPI_WireBuilder_H_
 
 #include "GeomAlgoAPI.h"
+#include "GeomAlgoAPI_MakeShapeCustom.h"
 
 #include <GeomAPI_Shape.h>
 
 /// \class GeomAlgoAPI_WireBuilder
 /// \ingroup DataAlgo
 /// \brief Allows to create wire-shapes by different parameters.
-class GeomAlgoAPI_WireBuilder
+class GeomAlgoAPI_WireBuilder : public GeomAlgoAPI_MakeShapeCustom
 {
  public:
+   /// \brief Creates a wire from edges and wires.
+   /// \param[in] theShapes list of shapes. Only edges and wires allowed.
+   /// The edges are not to be consecutive.
+   /// But they are to be all connected geometrically or topologically.
+   GEOMALGOAPI_EXPORT GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes);
+
    /// \brief Creates a wire from edges and wires.
    /// \param[in] theShapes list of shapes. Only edges and wires allowed.
    /// The edges are not to be consecutive.
index 6d4f24e4e3c1da41f159a479131a78cd9b9c1fa2..392d07fe0d1b653b6cde1212f6b4896fb4061159 100644 (file)
@@ -34,15 +34,13 @@ SketchAPI_Offset::SketchAPI_Offset (const std::shared_ptr<ModelAPI_Feature> & th
 SketchAPI_Offset::SketchAPI_Offset (const std::shared_ptr<ModelAPI_Feature> & theFeature,
                                     const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
                                     const ModelHighAPI_Double & theOffsetValue,
-                                    bool theIsReversed,
-                                    bool theIsAuxiliary)
+                                    bool theIsReversed)
   : ModelHighAPI_Interface(theFeature)
 {
   if (initialize()) {
     fillAttribute(theObjects, edgesList());
     fillAttribute(theOffsetValue, value());
     fillAttribute(theIsReversed, reversed());
-    fillAttribute(theIsAuxiliary, auxiliary());
 
     execute();
   }
@@ -54,7 +52,7 @@ SketchAPI_Offset::~SketchAPI_Offset()
 
 std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Offset::offset() const
 {
-  std::list<ObjectPtr> aList = createdList()->list();
+  std::list<ObjectPtr> aList = feature()->reflist(SketchPlugin_Constraint::ENTITY_B())->list();
   std::list<FeaturePtr> anIntermediate;
   std::list<ObjectPtr>::const_iterator anIt = aList.begin();
   for (; anIt != aList.end(); ++anIt) {
@@ -74,7 +72,6 @@ void SketchAPI_Offset::dump (ModelHighAPI_Dumper& theDumper) const
   AttributeRefListPtr aOffsetObjects = edgesList();
   AttributeDoublePtr aValue = value();
   AttributeBooleanPtr aReversed = reversed();
-  AttributeBooleanPtr anAux = auxiliary();
 
   // Check all attributes are already dumped. If not, store the feature as postponed.
   if (!theDumper.isDumped(aOffsetObjects)) {
@@ -83,7 +80,7 @@ void SketchAPI_Offset::dump (ModelHighAPI_Dumper& theDumper) const
   }
 
   theDumper << aBase << " = " << aSketchName << ".addOffset(" << aOffsetObjects << ", "
-            << aValue << ", " << aReversed << ", " << anAux << ")" << std::endl;
+            << aValue << ", " << aReversed << ")" << std::endl;
 
   // Dump variables for a list of created features
   theDumper << "[";
@@ -96,13 +93,13 @@ void SketchAPI_Offset::dump (ModelHighAPI_Dumper& theDumper) const
   }
   theDumper << "] = " << theDumper.name(aBase) << ".offset()" << std::endl;
 
-  // Set necessary "auxiliary" flag for created features
-  // (flag is set if it differs to anAux)
-  for (anIt = aList.begin(); anIt != aList.end(); ++anIt) {
-    FeaturePtr aFeature = (*anIt)->feature();
-    bool aFeatAux = aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value();
-    if (aFeatAux != anAux->value())
-      theDumper << theDumper.name((*anIt)->feature(), false)
-                << ".setAuxiliary(" << aFeatAux << ")" <<std::endl;
-  }
+////  // Set necessary "auxiliary" flag for created features
+////  // (flag is set if it differs to anAux)
+////  for (anIt = aList.begin(); anIt != aList.end(); ++anIt) {
+////    FeaturePtr aFeature = (*anIt)->feature();
+////    bool aFeatAux = aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value();
+////    if (aFeatAux != anAux->value())
+////      theDumper << theDumper.name((*anIt)->feature(), false)
+////                << ".setAuxiliary(" << aFeatAux << ")" <<std::endl;
+////  }
 }
index 98412a8a20de55d8d96309ae8f3ccb5c0d2f90ef..b4d9ca9a2cb26800a233985320b9a6f3a2d52c2d 100644 (file)
@@ -50,13 +50,12 @@ public:
   SketchAPI_Offset(const std::shared_ptr<ModelAPI_Feature> & theFeature,
                    const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
                    const ModelHighAPI_Double & theOffsetValue,
-                   bool theIsReversed,
-                   bool theIsAuxiliary);
+                   bool theIsReversed);
   /// Destructor
   SKETCHAPI_EXPORT
   virtual ~SketchAPI_Offset();
 
-  INTERFACE_5(SketchPlugin_Offset::ID(),
+  INTERFACE_3(SketchPlugin_Offset::ID(),
 
               edgesList, SketchPlugin_Offset::EDGES_ID(),
               ModelAPI_AttributeRefList, /** Offset edges list */,
@@ -65,13 +64,7 @@ public:
               ModelAPI_AttributeDouble, /** Value */,
 
               reversed, SketchPlugin_Offset::REVERSED_ID(),
-              ModelAPI_AttributeBoolean, /** Negative value */,
-
-              auxiliary, SketchPlugin_Offset::AUXILIARY_ID(),
-              ModelAPI_AttributeBoolean, /** Auxiliary */,
-
-              createdList, SketchPlugin_Offset::CREATED_ID(),
-              ModelAPI_AttributeRefList, /** Created edges list */
+              ModelAPI_AttributeBoolean, /** Negative value */
               )
 
   /// List of created objects
index 2046d51034ac09bb02ea8ecde234ffc196d35454..a3efd9ef50d2eb0d584f7a7ca66446fb896a48cd 100644 (file)
@@ -895,12 +895,11 @@ std::shared_ptr<SketchAPI_Mirror> SketchAPI_Sketch::addMirror(
 std::shared_ptr<SketchAPI_Offset> SketchAPI_Sketch::addOffset(
     const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
     const ModelHighAPI_Double & theValue,
-    const bool theReversed,
-    const bool theAuxiliary)
+    const bool theReversed)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Offset::ID());
-  return OffsetPtr(new SketchAPI_Offset(aFeature, theObjects, theValue, theReversed, theAuxiliary));
+  return OffsetPtr(new SketchAPI_Offset(aFeature, theObjects, theValue, theReversed));
 }
 
 //--------------------------------------------------------------------------------------
index 6174ca23fd90dee5e5ee046edeb03891e4633698..3115cadf51a04c57dec012b19b3543ffb9562263 100644 (file)
@@ -376,8 +376,7 @@ public:
   std::shared_ptr<SketchAPI_Offset> addOffset(
       const std::list<std::shared_ptr<ModelAPI_Object> > & theObjects,
       const ModelHighAPI_Double & theValue,
-      const bool theReversed,
-      const bool theAuxiliary);
+      const bool theReversed);
 
   /// Add translation
   SKETCHAPI_EXPORT
index 0bdbb7f0602e7e81b5cc98535d0622ec96753326..2d82f01539e95260d5122bfac8b831f58a55977a 100644 (file)
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_Validator.h>
 
+#include <GeomAlgoAPI_MakeShapeList.h>
 #include <GeomAlgoAPI_Offset.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 #include <GeomAlgoAPI_WireBuilder.h>
 
-#include <GeomAPI_Edge.h>
+#include <GeomAPI_BSpline.h>
 #include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
 #include <GeomAPI_Ellipse.h>
-#include <GeomAPI_BSpline.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Point2DArray.h>
 #include <iostream>
 
 SketchPlugin_Offset::SketchPlugin_Offset()
-  : SketchPlugin_SketchEntity()
 {
 }
 
-void SketchPlugin_Offset::initDerivedClassAttributes()
+void SketchPlugin_Offset::initAttributes()
 {
   data()->addAttribute(EDGES_ID(), ModelAPI_AttributeRefList::typeId());
   data()->addAttribute(VALUE_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
-  data()->addAttribute(CREATED_ID(), ModelAPI_AttributeRefList::typeId());
 
-  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CREATED_ID());
+  // store original entities
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
+  // store offset entities
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
+  // store mapping between original entity and index of the corresponding offset entity
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeIntArray::typeId());
+
+  ModelAPI_Session::get()->validators()->
+      registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_A());
+  ModelAPI_Session::get()->validators()->
+      registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B());
+  ModelAPI_Session::get()->validators()->
+      registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C());
 }
 
 void SketchPlugin_Offset::execute()
 {
-  removeCreated(); // remove created objects
-
   SketchPlugin_Sketch* aSketch = sketch();
   if (!aSketch) return;
 
@@ -116,6 +127,7 @@ void SketchPlugin_Offset::execute()
     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
 
   // 5. Gather wires and make offset for each wire
+  ListOfMakeShape anOffsetAlgos;
   for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) {
     FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
     if (aFeature.get()) {
@@ -148,19 +160,25 @@ void SketchPlugin_Offset::execute()
           aTopoChain.push_back(aTopoEdge);
         }
       }
-      GeomShapePtr anEdgeOrWire = GeomAlgoAPI_WireBuilder::wire(aTopoChain);
+      std::shared_ptr<GeomAlgoAPI_WireBuilder> aWireBuilder(
+          new GeomAlgoAPI_WireBuilder(aTopoChain));
 
       // 5.d. Make offset for each wire
-      std::shared_ptr<GeomAPI_Shape> anOffsetShape =
-        GeomAlgoAPI_Offset::OffsetInPlane(aPlane, anEdgeOrWire, aValue);
+      std::shared_ptr<GeomAlgoAPI_Offset> anOffsetShape(
+          new GeomAlgoAPI_Offset(aPlane, aWireBuilder->shape(), aValue));
 
-      // 5.e. Store offset results.
-      //      Create sketch feature for each edge of anOffsetShape, and also store
-      //      created features in CREATED_ID() to remove them on next execute()
-      addToSketch(anOffsetShape);
+      std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeList(new GeomAlgoAPI_MakeShapeList);
+      aMakeList->appendAlgo(aWireBuilder);
+      aMakeList->appendAlgo(anOffsetShape);
+      anOffsetAlgos.push_back(aMakeList);
     }
   }
 
+  // 6. Store offset results.
+  //    Create sketch feature for each edge of anOffsetShape, and also store
+  //    created features in CREATED_ID() to remove them on next execute()
+  addToSketch(anOffsetAlgos);
+
   // send events to update the sub-features by the solver
   if (isUpdateFlushed)
     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
@@ -267,129 +285,280 @@ bool SketchPlugin_Offset::findWireOneWay (const FeaturePtr& theFirstEdge,
   return findWireOneWay (theFirstEdge, aNextEdgeFeature, aP2, theEdgesSet, theChain, isPrepend);
 }
 
-void SketchPlugin_Offset::addToSketch(const std::shared_ptr<GeomAPI_Shape>& anOffsetShape)
+static void setRefListValue(AttributeRefListPtr theList, int theListSize,
+                            ObjectPtr theValue, int theIndex)
 {
-  AttributeRefListPtr aRefListOfCreated =
-    std::dynamic_pointer_cast<ModelAPI_AttributeRefList>
-    (data()->attribute(SketchPlugin_Offset::CREATED_ID()));
-
-  ListOfShape aResEdges = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(anOffsetShape);
-  std::list<GeomShapePtr>::const_iterator aResEdgesIt = aResEdges.begin();
-  for (; aResEdgesIt != aResEdges.end(); aResEdgesIt++) {
-    GeomShapePtr aResShape = (*aResEdgesIt);
-    if (aResShape->shapeType() == GeomAPI_Shape::EDGE) {
-      // Add new feature
-      FeaturePtr aResFeature;
-      std::shared_ptr<GeomAPI_Edge> aResEdge (new GeomAPI_Edge(aResShape));
-
-      std::shared_ptr<GeomAPI_Pnt2d> aFP, aLP;
-      std::shared_ptr<GeomAPI_Pnt> aFP3d = aResEdge->firstPoint();
-      std::shared_ptr<GeomAPI_Pnt> aLP3d = aResEdge->lastPoint();
-      //if (aFP3d.get() && aLP3d.get()) {
-      if (aFP3d && aLP3d) {
-        aFP = sketch()->to2D(aFP3d);
-        aLP = sketch()->to2D(aLP3d);
-      }
+  if (theIndex < theListSize) {
+    ObjectPtr aCur = theList->object(theIndex);
+    if (aCur != theValue)
+      theList->substitute(aCur, theValue);
+  }
+  else
+    theList->append(theValue);
+}
 
-      if (aResEdge->isLine()) {
-        aResFeature = sketch()->addFeature(SketchPlugin_Line::ID());
+static void removeLastFromIndex(AttributeRefListPtr theList, int theListSize, int& theLastIndex)
+{
+  if (theLastIndex < theListSize) {
+    std::set<int> anIndicesToRemove;
+    for (; theLastIndex < theListSize; ++theLastIndex)
+      anIndicesToRemove.insert(theLastIndex);
+    theList->remove(anIndicesToRemove);
+  }
+}
 
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-          (aResFeature->attribute(SketchPlugin_Line::START_ID()))->setValue(aFP);
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-          (aResFeature->attribute(SketchPlugin_Line::END_ID()))->setValue(aLP);
-      }
-      else if (aResEdge->isArc()) {
-        std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
-        std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
-        std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
-
-        aResFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
-
-        bool aWasBlocked = aResFeature->data()->blockSendAttributeUpdated(true);
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-          (aResFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCP);
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-          (aResFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(aFP);
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-          (aResFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(aLP);
-        aResFeature->data()->blockSendAttributeUpdated(aWasBlocked);
-      }
-      else if (aResEdge->isCircle()) {
-        std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
-        std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
-        std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
-
-        aResFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-          (aResFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCP);
-        aResFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircEdge->radius());
-      }
-      else if (aResEdge->isEllipse()) {
-        std::shared_ptr<GeomAPI_Ellipse> anEllipseEdge = aResEdge->ellipse();
-
-        GeomPointPtr aCP3d = anEllipseEdge->center();
-        GeomPnt2dPtr aCP = sketch()->to2D(aCP3d);
-
-        GeomPointPtr aFocus3d = anEllipseEdge->firstFocus();
-        GeomPnt2dPtr aFocus = sketch()->to2D(aFocus3d);
-
-        if (aFP3d && aLP3d) {
-          // Elliptic arc
-          aResFeature = sketch()->addFeature(SketchPlugin_EllipticArc::ID());
-
-          bool aWasBlocked = aResFeature->data()->blockSendAttributeUpdated(true);
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-            (aResFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()))->setValue(aCP);
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-            (aResFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()))->setValue(aFocus);
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-            (aResFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))->setValue(aFP);
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-            (aResFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))->setValue(aLP);
-          aResFeature->data()->blockSendAttributeUpdated(aWasBlocked);
-        }
-        else {
-          // Ellipse
-          aResFeature = sketch()->addFeature(SketchPlugin_Ellipse::ID());
-
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-            (aResFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()))->setValue(aCP);
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-            (aResFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()))->setValue(aFocus);
-          aResFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipseEdge->minorRadius());
-        }
-      }
-      else if (aResEdge->isBSpline()) {
-        mkBSpline(aResFeature, aResEdge);
-      }
-      else {
-        // convert to b-spline
-        mkBSpline(aResFeature, aResEdge);
+void SketchPlugin_Offset::addToSketch(const ListOfMakeShape& theOffsetAlgos)
+{
+  AttributeRefListPtr aSelectedRefList = reflist(EDGES_ID());
+  AttributeRefListPtr aBaseRefList = reflist(ENTITY_A());
+  AttributeRefListPtr anOffsetRefList = reflist(ENTITY_B());
+  AttributeIntArrayPtr anOffsetToBaseMap = intArray(ENTITY_C());
+
+  // compare the list of selected edges and the previously stored,
+  // and store maping between them
+  std::map<ObjectPtr, std::list<ObjectPtr> > aMapExistent;
+  std::list<ObjectPtr> anObjectsToRemove;
+  std::list<ObjectPtr> aSelectedList = aSelectedRefList->list();
+  for (std::list<ObjectPtr>::iterator aSIt = aSelectedList.begin();
+       aSIt != aSelectedList.end(); ++aSIt) {
+    aMapExistent[*aSIt] = std::list<ObjectPtr>();
+  }
+  for (int anIndex = 0, aSize = anOffsetRefList->size(); anIndex < aSize; ++anIndex) {
+    ObjectPtr aCurrent = anOffsetRefList->object(anIndex);
+    int aBaseIndex = anOffsetToBaseMap->value(anIndex);
+    if (aBaseIndex >= 0) {
+      ObjectPtr aBaseObj = aBaseRefList->object(aBaseIndex);
+      std::map<ObjectPtr, std::list<ObjectPtr> >::iterator aFound = aMapExistent.find(aBaseObj);
+      if (aFound != aMapExistent.end())
+        aFound->second.push_back(aCurrent);
+      else
+        anObjectsToRemove.push_back(aCurrent);
+    }
+    else
+      anObjectsToRemove.push_back(aCurrent);
+  }
+
+  // update lists of base shapes and of offset shapes
+  int aBaseListSize = aBaseRefList->size();
+  int anOffsetListSize = anOffsetRefList->size();
+  int aBaseListIndex = 0, anOffsetListIndex = 0;
+  std::list<int> anOffsetBaseBackRefs;
+  std::set<GeomShapePtr, GeomAPI_Shape::ComparatorWithOri> aProcessedOffsets;
+  for (std::list<ObjectPtr>::iterator aSIt = aSelectedList.begin();
+       aSIt != aSelectedList.end(); ++aSIt) {
+    // find an offseted edge
+    FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*aSIt);
+    GeomShapePtr aBaseShape = aBaseFeature->lastResult()->shape();
+    ListOfShape aNewShapes;
+    for (ListOfMakeShape::const_iterator anAlgoIt = theOffsetAlgos.begin();
+         anAlgoIt != theOffsetAlgos.end() && aNewShapes.empty(); ++anAlgoIt) {
+      (*anAlgoIt)->generated(aBaseShape, aNewShapes);
+    }
+
+    // store base feature
+    setRefListValue(aBaseRefList, aBaseListSize, *aSIt, aBaseListIndex);
+
+    // create or update an offseted feature
+    const std::list<ObjectPtr>& anImages = aMapExistent[*aSIt];
+    std::list<ObjectPtr>::const_iterator anImgIt = anImages.begin();
+    for (ListOfShape::iterator aNewIt = aNewShapes.begin(); aNewIt != aNewShapes.end(); ++aNewIt) {
+      FeaturePtr aNewFeature;
+      if (anImgIt != anImages.end())
+        aNewFeature = ModelAPI_Feature::feature(*anImgIt++);
+      updateExistentOrCreateNew(*aNewIt, aNewFeature, anObjectsToRemove);
+      aProcessedOffsets.insert(*aNewIt);
+
+      // store an offseted feature
+      setRefListValue(anOffsetRefList, anOffsetListSize, aNewFeature, anOffsetListIndex);
+
+      anOffsetBaseBackRefs.push_back(aBaseListIndex);
+      ++anOffsetListIndex;
+    }
+    ++aBaseListIndex;
+    anObjectsToRemove.insert(anObjectsToRemove.end(), anImgIt, anImages.end());
+  }
+  // create arcs generated from vertices
+  for (ListOfMakeShape::const_iterator anAlgoIt = theOffsetAlgos.begin();
+       anAlgoIt != theOffsetAlgos.end(); ++anAlgoIt) {
+    GeomShapePtr aCurWire = (*anAlgoIt)->shape();
+    GeomAPI_ShapeExplorer anExp(aCurWire, GeomAPI_Shape::EDGE);
+    for (; anExp.more(); anExp.next()) {
+      GeomShapePtr aCurEdge = anExp.current();
+      if (aProcessedOffsets.find(aCurEdge) == aProcessedOffsets.end()) {
+        FeaturePtr aNewFeature;
+        updateExistentOrCreateNew(aCurEdge, aNewFeature, anObjectsToRemove);
+        aProcessedOffsets.insert(aCurEdge);
+
+        // store an offseted feature
+        setRefListValue(anOffsetRefList, anOffsetListSize, aNewFeature, anOffsetListIndex);
+
+        anOffsetBaseBackRefs.push_back(-1);
+        ++anOffsetListIndex;
       }
+    }
+  }
 
-      if (aResFeature.get()) {
-        aRefListOfCreated->append(aResFeature);
+  removeLastFromIndex(aBaseRefList, aBaseListSize, aBaseListIndex);
+  removeLastFromIndex(anOffsetRefList, anOffsetListSize, anOffsetListIndex);
+
+  anOffsetToBaseMap->setSize((int)anOffsetBaseBackRefs.size(), false);
+  int anIndex = 0;
+  for (std::list<int>::iterator anIt = anOffsetBaseBackRefs.begin();
+       anIt != anOffsetBaseBackRefs.end(); ++anIt) {
+    anOffsetToBaseMap->setValue(anIndex++, *anIt, false);
+  }
 
-        aResFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue
-          (boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
-        aResFeature->execute();
+  // remove unused objects
+  std::set<FeaturePtr> aSet;
+  for (std::list<ObjectPtr>::iterator anIt = anObjectsToRemove.begin();
+       anIt != anObjectsToRemove.end(); ++anIt) {
+    FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+    if (aFeature)
+      aSet.insert(aFeature);
+  }
+  ModelAPI_Tools::removeFeaturesAndReferences(aSet);
+}
+
+static void findOrCreateFeatureByKind(SketchPlugin_Sketch* theSketch,
+                                      const std::string& theFeatureKind,
+                                      FeaturePtr& theFeature,
+                                      std::list<ObjectPtr>& thePoolOfFeatures)
+{
+  if (!theFeature) {
+    // try to find appropriate feature in the pool
+    for (std::list<ObjectPtr>::iterator it = thePoolOfFeatures.begin();
+         it != thePoolOfFeatures.end(); ++it) {
+      FeaturePtr aCurFeature = ModelAPI_Feature::feature(*it);
+      if (aCurFeature->getKind() == theFeatureKind) {
+        theFeature = aCurFeature;
+        thePoolOfFeatures.erase(it);
+        break;
       }
     }
+    // feature not found, create new
+    if (!theFeature)
+      theFeature = theSketch->addFeature(theFeatureKind);
+  }
+}
+
+void SketchPlugin_Offset::updateExistentOrCreateNew(const GeomShapePtr& theShape,
+                                                    FeaturePtr& theFeature,
+                                                    std::list<ObjectPtr>& thePoolOfFeatures)
+{
+  if (theShape->shapeType() != GeomAPI_Shape::EDGE)
+    return;
+
+  std::shared_ptr<GeomAPI_Edge> aResEdge(new GeomAPI_Edge(theShape));
+
+  std::shared_ptr<GeomAPI_Pnt2d> aFP, aLP;
+  std::shared_ptr<GeomAPI_Pnt> aFP3d = aResEdge->firstPoint();
+  std::shared_ptr<GeomAPI_Pnt> aLP3d = aResEdge->lastPoint();
+  if (aFP3d && aLP3d) {
+    aFP = sketch()->to2D(aFP3d);
+    aLP = sketch()->to2D(aLP3d);
+  }
+
+  if (aResEdge->isLine()) {
+    findOrCreateFeatureByKind(sketch(), SketchPlugin_Line::ID(), theFeature, thePoolOfFeatures);
+
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (theFeature->attribute(SketchPlugin_Line::START_ID()))->setValue(aFP);
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (theFeature->attribute(SketchPlugin_Line::END_ID()))->setValue(aLP);
+  }
+  else if (aResEdge->isArc()) {
+    std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
+    std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
+    std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
+
+    findOrCreateFeatureByKind(sketch(), SketchPlugin_Arc::ID(), theFeature, thePoolOfFeatures);
+
+    bool aWasBlocked = theFeature->data()->blockSendAttributeUpdated(true);
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCP);
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (theFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(aFP);
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (theFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(aLP);
+    theFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+  }
+  else if (aResEdge->isCircle()) {
+    std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
+    std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
+    std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
+
+    findOrCreateFeatureByKind(sketch(), SketchPlugin_Circle::ID(), theFeature, thePoolOfFeatures);
+
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+      (theFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCP);
+    theFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircEdge->radius());
+  }
+  else if (aResEdge->isEllipse()) {
+    std::shared_ptr<GeomAPI_Ellipse> anEllipseEdge = aResEdge->ellipse();
+
+    GeomPointPtr aCP3d = anEllipseEdge->center();
+    GeomPnt2dPtr aCP = sketch()->to2D(aCP3d);
+
+    GeomPointPtr aFocus3d = anEllipseEdge->firstFocus();
+    GeomPnt2dPtr aFocus = sketch()->to2D(aFocus3d);
+
+    if (aFP3d && aLP3d) {
+      // Elliptic arc
+      findOrCreateFeatureByKind(sketch(), SketchPlugin_EllipticArc::ID(),
+                                theFeature, thePoolOfFeatures);
+
+      bool aWasBlocked = theFeature->data()->blockSendAttributeUpdated(true);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+        (theFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()))->setValue(aCP);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+        (theFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()))->setValue(aFocus);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+        (theFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))->setValue(aFP);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+        (theFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))->setValue(aLP);
+      theFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+    }
+    else {
+      // Ellipse
+      findOrCreateFeatureByKind(sketch(), SketchPlugin_Ellipse::ID(),
+                                theFeature, thePoolOfFeatures);
+
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+        (theFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()))->setValue(aCP);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+        (theFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()))->setValue(aFocus);
+      theFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipseEdge->minorRadius());
+    }
+  }
+  else {
+    // convert to b-spline
+    mkBSpline(theFeature, aResEdge, thePoolOfFeatures);
+  }
+
+  if (theFeature.get()) {
+    theFeature->boolean(SketchPlugin_SketchEntity::COPY_ID())->setValue(true);
+    theFeature->execute();
+
+    static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
+    ModelAPI_EventCreator::get()->sendUpdated(theFeature, aRedisplayEvent);
+    const std::list<ResultPtr>& aResults = theFeature->results();
+    for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+         anIt != aResults.end(); ++anIt)
+      ModelAPI_EventCreator::get()->sendUpdated(*anIt, aRedisplayEvent);
   }
 }
 
 void SketchPlugin_Offset::mkBSpline (FeaturePtr& theResult,
-                                     const GeomEdgePtr& theEdge)
+                                     const GeomEdgePtr& theEdge,
+                                     std::list<ObjectPtr>& thePoolOfFeatures)
 {
   GeomCurvePtr aCurve (new GeomAPI_Curve (theEdge));
   // Forced conversion to b-spline, if aCurve is not b-spline
   GeomAPI_BSpline aBSpline (aCurve, /*isForced*/true);
 
-  if (aBSpline.isPeriodic())
-    theResult = sketch()->addFeature(SketchPlugin_BSplinePeriodic::ID());
-  else
-    theResult = sketch()->addFeature(SketchPlugin_BSpline::ID());
+  const std::string& aBSplineKind = aBSpline.isPeriodic() ? SketchPlugin_BSplinePeriodic::ID()
+                                                          : SketchPlugin_BSpline::ID();
+  findOrCreateFeatureByKind(sketch(), aBSplineKind, theResult, thePoolOfFeatures);
 
   theResult->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree());
 
@@ -440,26 +609,8 @@ void SketchPlugin_Offset::mkBSpline (FeaturePtr& theResult,
 
 void SketchPlugin_Offset::attributeChanged(const std::string& theID)
 {
-//  removeCreated();
-}
-
-void SketchPlugin_Offset::removeCreated()
-{
-  if (!sketch()) return;
-
-  // Remove all created objects
-  AttributeRefListPtr aRefListOfCreated =
-    std::dynamic_pointer_cast<ModelAPI_AttributeRefList>
-    (data()->attribute(SketchPlugin_Offset::CREATED_ID()));
-  std::list<ObjectPtr> aList = aRefListOfCreated->list();
-  std::set<FeaturePtr> aSet;
-  std::list<ObjectPtr>::iterator anIter = aList.begin();
-  for (; anIter != aList.end(); anIter++) {
-    FeaturePtr aFeature = ModelAPI_Feature::feature(*anIter);
-    aSet.insert(aFeature);
-  }
-  aRefListOfCreated->clear();
-  ModelAPI_Tools::removeFeaturesAndReferences(aSet);
+////  if (theID == EDGES_ID())
+////    removeCreated();
 }
 
 bool SketchPlugin_Offset::customAction(const std::string& theActionId)
index 482a752457f0774aa98a0f844f7e0ba261247103..355e1e58ff18fae10067363aeea4aeac805ebfb4 100644 (file)
 #define SketchPlugin_Offset_H_
 
 #include <SketchPlugin.h>
-#include <SketchPlugin_SketchEntity.h>
+#include <SketchPlugin_ConstraintBase.h>
 
 #include <GeomDataAPI_Point2D.h>
 
 #include <GeomAPI_Edge.h>
-#include <GeomAPI_IPresentable.h>
+
+class GeomAlgoAPI_MakeShape;
 
 /**\class SketchPlugin_Offset
  * \ingroup Plugins
  * \brief Builds offset curves in the sketch.
  */
-class SketchPlugin_Offset : public SketchPlugin_SketchEntity, public GeomAPI_IPresentable
+class SketchPlugin_Offset : public SketchPlugin_ConstraintBase
 {
 public:
   /// Offset macro feature kind
@@ -70,13 +71,6 @@ public:
     return ID;
   }
 
-  /// attribute to store the created objects
-  inline static const std::string& CREATED_ID()
-  {
-    static const std::string ID("created");
-    return ID;
-  }
-
   /// name for add wire action
   inline static const std::string& ADD_WIRE_ACTION_ID()
   {
@@ -90,11 +84,6 @@ public:
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
-  /// Reimplemented from ModelAPI_Feature::isMacro().
-  /// \returns true
-  //SKETCHPLUGIN_EXPORT virtual bool isMacro() const { return false; }
-
-  //SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; }
   SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return true; }
 
   /// Find edges connected by coincident boundary constraint and composing a wire with
@@ -112,30 +101,36 @@ public:
 
 protected:
   /// \brief Initializes attributes of derived class.
-  virtual void initDerivedClassAttributes();
+  virtual void initAttributes();
 
 private:
   /// Find all wires connected with the selected edges
   bool findWires();
 
-  // Create sketch feature for each edge of theOffsetResult,
-  // and store it in CREATED_ID()
-  void addToSketch (const std::shared_ptr<GeomAPI_Shape>& theOffsetResult);
-
-  // Remove created features
-  void removeCreated ();
-
-  // Create BSpline or BSplinePeriodic sketch feature from theEdge
-  void mkBSpline (FeaturePtr& theResult, const GeomEdgePtr& theEdge);
-
-  // Find edges that prolongate theEdgeFeature (in a chain) at theEndPoint
-  // Recursive method.
-  // \param[in] theFirstEdge Start edge of wire searching
-  // \param[in] theEdge Current edge
-  // \param[in] theEndPoint Point of the Current edge, not belonging to a previous edge
-  // \param[in/out] theEdgesSet All edges to find among. If empty, all sketch edges assumed.
-  // \param[in/out] theChain Resulting edges
-  // \param[in] isPrepend if true, push new found edges to theChain front, else to the back
+  /// Create sketch feature for each edge of the offset result,
+  /// and store it in ENTITY_B(). Original edges are copied to ENTITY_A() to update
+  /// correctly if original selection is modified.
+  void addToSketch (const std::list< std::shared_ptr<GeomAlgoAPI_MakeShape> >& theOffsetAlgos);
+
+  /// Create BSpline or BSplinePeriodic sketch feature from theEdge
+  void mkBSpline (FeaturePtr& theResult, const GeomEdgePtr& theEdge,
+                  std::list<ObjectPtr>& thePoolOfFeatures);
+
+  /// Update existent feature by the parameters of the given edge or create a new feature.
+  /// \param[in]     theShape          a shape to be converted to sketch feature
+  /// \param[in,out] theFeature        sketch feature to be updated or created from scratch
+  /// \param[in,out] thePoolOfFeatures list of features to be removed (may be used as a new feature)
+  void updateExistentOrCreateNew (const GeomShapePtr& theShape, FeaturePtr& theFeature,
+                                  std::list<ObjectPtr>& thePoolOfFeatures);
+
+  /// Find edges that prolongate theEdgeFeature (in a chain) at theEndPoint
+  /// Recursive method.
+  /// \param[in] theFirstEdge Start edge of wire searching
+  /// \param[in] theEdge Current edge
+  /// \param[in] theEndPoint Point of the Current edge, not belonging to a previous edge
+  /// \param[in/out] theEdgesSet All edges to find among. If empty, all sketch edges assumed.
+  /// \param[in/out] theChain Resulting edges
+  /// \param[in] isPrepend if true, push new found edges to theChain front, else to the back
   /// \return \c true if the chain is closed
   bool findWireOneWay (const FeaturePtr& theFirstEdge,
                        const FeaturePtr& theEdge,
index b0bc3332859d152f8b40b408bd8c0510d37d91b8..2295a3f5e7fb6f461e1d358deba289498ca53c7d 100644 (file)
                    tooltip="Reverse the offset"
                    default="false"
                    obligatory="0"/>
-        <boolvalue id="Auxiliary"
-                   label="Auxiliary"
-                   tooltip="Construction element"
-                   default="false"
-                   obligatory="0"
-                   change_visual_attributes="true"/>
         <action id="add_wire"
                 label="Select wire"
                 tooltip="Add the list of segments composing a wire with the selected items through the coincidence by boundary points"/>
index fafa0372ac5780f3b4d4905d4985d8a3f2498eca..0786930b73e1136358bdd4fb1e38b9a52d70b1fe 100644 (file)
@@ -56,6 +56,7 @@ SET(SKETCHSOLVER_CONSTRAINT_HEADERS
     SketchSolver_ConstraintMultiRotation.h
     SketchSolver_ConstraintMultiTranslation.h
     SketchSolver_ConstraintMovement.h
+    SketchSolver_ConstraintOffset.h
 )
 
 SET(SKETCHSOLVER_SOURCES
@@ -81,6 +82,7 @@ SET(SKETCHSOLVER_CONSTRAINT_SOURCES
     SketchSolver_ConstraintMultiRotation.cpp
     SketchSolver_ConstraintMultiTranslation.cpp
     SketchSolver_ConstraintMovement.cpp
+    SketchSolver_ConstraintOffset.cpp
 )
 
 SET(SKETCHSOLVER_LIBRARIES
index 5cc2e86c15a36e9cd3540c4d5eba95e937ba8e48..aa433a9c4991e5f93743f19cd613f2d4ef388df9 100644 (file)
@@ -40,6 +40,7 @@
 #include <SketchSolver_ConstraintTangent.h>
 #include <SketchSolver_ConstraintMultiRotation.h>
 #include <SketchSolver_ConstraintMultiTranslation.h>
+#include <SketchSolver_ConstraintOffset.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_BSpline.h>
@@ -63,6 +64,7 @@
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
+#include <SketchPlugin_Offset.h>
 #include <SketchPlugin_Point.h>
 
 #include <GeomAPI_BSpline2d.h>
@@ -186,6 +188,8 @@ SolverConstraintPtr PlaneGCSSolver_Tools::createConstraint(ConstraintPtr theCons
     return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_Offset::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintOffset(theConstraint));
   }
   // All other types of constraints
   return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint));
diff --git a/src/SketchSolver/SketchSolver_ConstraintOffset.cpp b/src/SketchSolver/SketchSolver_ConstraintOffset.cpp
new file mode 100644 (file)
index 0000000..dbe4197
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <SketchSolver_ConstraintOffset.h>
+
+
+void SketchSolver_ConstraintOffset::getAttributes(
+    EntityWrapperPtr&,
+    std::vector<EntityWrapperPtr>&)
+{
+}
+
+void SketchSolver_ConstraintOffset::process()
+{
+  cleanErrorMsg();
+}
+
+
+void SketchSolver_ConstraintOffset::update()
+{
+  cleanErrorMsg();
+  remove();
+  process();
+}
diff --git a/src/SketchSolver/SketchSolver_ConstraintOffset.h b/src/SketchSolver/SketchSolver_ConstraintOffset.h
new file mode 100644 (file)
index 0000000..45d760b
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2020  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SketchSolver_ConstraintOffset_H_
+#define SketchSolver_ConstraintOffset_H_
+
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintOffset
+ *  \ingroup Plugins
+ *  \brief   Convert offset to the solver's data model
+ */
+class SketchSolver_ConstraintOffset : public SketchSolver_Constraint
+{
+public:
+  /// Constructor based on SketchPlugin constraint
+  SketchSolver_ConstraintOffset(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  /// \brief Update constraint
+  virtual void update();
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of entities of mirror constraint
+  virtual void getAttributes(EntityWrapperPtr&, std::vector<EntityWrapperPtr>&);
+};
+
+#endif