Salome HOME
High level objects history implementation for Intersection and Compound features...
authormpv <mpv@opencascade.com>
Wed, 23 Jan 2019 09:14:08 +0000 (12:14 +0300)
committermpv <mpv@opencascade.com>
Wed, 23 Jan 2019 09:14:08 +0000 (12:14 +0300)
src/BuildPlugin/BuildPlugin_Compound.cpp
src/FeaturesPlugin/FeaturesPlugin_Intersection.cpp
src/FeaturesPlugin/Test/Test1876.py
src/FeaturesPlugin/Test/Test1942.py
src/Model/Model_AttributeSelection.cpp
src/Model/Model_BodyBuilder.cpp
src/Model/Model_ResultBody.cpp
src/Model/Model_ResultBody.h
src/Model/Model_Update.cpp

index 6d6c0c79f9a3f70b284d5969ba31e5e7fb54cafd..68997c9880a95d84ca4cb0cc281cc3a5d3985423 100644 (file)
@@ -76,7 +76,7 @@ void BuildPlugin_Compound::execute()
   int anIndexToRemove = 0;
   if (aCopyCompound) {
     ResultBodyPtr aResultBody = document()->createBody(data(), anIndexToRemove++);
-    aResultBody->store(aCopyCompound);
+    aResultBody->storeModified(anOriginalShapes, aCopyCompound, aCopyAlgo);
     aResultBody->loadModifiedShapes(aCopyAlgo, aCompound, GeomAPI_Shape::VERTEX);
     aResultBody->loadModifiedShapes(aCopyAlgo, aCompound, GeomAPI_Shape::EDGE);
     aResultBody->loadModifiedShapes(aCopyAlgo, aCompound, GeomAPI_Shape::FACE);
index 93a02c79fe6399e022263c595acfd5ce5a4f37be..471e0cff18d272a5ed88810b58472aae9a83a60a 100644 (file)
@@ -83,7 +83,6 @@ void FeaturesPlugin_Intersection::execute()
   setResult(aResultBody, aResultIndex);
   aResultIndex++;
 
-
   // remove the rest results if there were produced in the previous pass
   removeResults(aResultIndex);
 }
@@ -100,7 +99,7 @@ void FeaturesPlugin_Intersection::loadNamingDS(ResultBodyPtr theResultBody,
     return;
   }
 
-  theResultBody->storeModified(theObjects.front(), aResultShape);
+  theResultBody->storeModified(theObjects, aResultShape, theMakeShape);
 
   const int aShapeTypesNb = 3;
   const GeomAPI_Shape::ShapeType aShapeTypes[aShapeTypesNb] = {GeomAPI_Shape::VERTEX,
index 4b01039f9a6f94b360ca708eba080ff3b84fce08..47709b5f5b0684163d909011cc2e32ebb7f5669b 100644 (file)
@@ -69,4 +69,4 @@ assert(aList1.value(1).value().shapeTypeStr() == "SOLID")
 assert(aList2.value(0).value().shapeTypeStr() == "SOLID")
 assert(aList2.value(1).value().shapeTypeStr() == "SOLID")
 assert(aList1.value(0).value().isSame(aList2.value(0).value()) or aList1.value(1).value().isSame(aList2.value(0).value()) or
-aList1.value(1).value().isSame(aList2.value(0).value()) or aList1.value(1).value().isSame(aList2.value(1).value()))
+aList1.value(0).value().isSame(aList2.value(1).value()) or aList1.value(1).value().isSame(aList2.value(1).value()))
index ada970bc5b44a15aa44acc4652b5f8210ab4589e..efd3de9c8217685df11f4f76210902b18e31815d 100644 (file)
@@ -184,7 +184,19 @@ Plane_5 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/Axis_4"),
 Face_1_objects = [model.selection("EDGE", "Sketch_1/SketchArc_2_2"), model.selection("EDGE", "Sketch_1/SketchLine_4"), model.selection("EDGE", "Sketch_1/SketchLine_5"), model.selection("EDGE", "Sketch_1/SketchLine_6"), model.selection("EDGE", "Sketch_1/SketchLine_7"), model.selection("EDGE", "Sketch_1/SketchLine_8"), model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")]
 Face_1 = model.addFace(Part_1_doc, Face_1_objects)
 Intersection_1 = model.addIntersection(Part_1_doc, [model.selection("SOLID", "Recover_1_1"), model.selection("FACE", "Face_1_1")])
-Group_1_objects = [model.selection("VERTEX", "[Intersection_1_1_3/Intersection_1_1_3&Face_1_1/Edge_3][weak_name_2]"), model.selection("VERTEX", "[Intersection_1_1_1/Intersection_1_1_1][weak_name_2]"), model.selection("VERTEX", "[Intersection_1_1_9/Intersection_1_1_9&Face_1_1/Edge_7][weak_name_1]"), model.selection("VERTEX", "[Intersection_1_1_7/Intersection_1_1_7&Face_1_1/Edge_5][weak_name_2]"), model.selection("VERTEX", "[Intersection_1_1_4/Intersection_1_1_4][weak_name_2]"), model.selection("VERTEX", "[Intersection_1_1_1/Intersection_1_1_1][weak_name_1]"), model.selection("VERTEX", "[Intersection_1_1_2/Intersection_1_1_2&Face_1_1/Edge_2][weak_name_1]"), model.selection("VERTEX", "[Intersection_1_1_4/Intersection_1_1_4][weak_name_1]"), model.selection("VERTEX", "[Intersection_1_1_6/Intersection_1_1_6&Face_1_1/Edge_4][weak_name_2]"), model.selection("VERTEX", "[Intersection_1_1_10/Intersection_1_1_10&Face_1_1/Edge_8][weak_name_1]"), model.selection("VERTEX", "[Intersection_1_1_8/Intersection_1_1_8&Face_1_1/Edge_6][weak_name_1]")]
+Group_1_objects = [
+model.selection("VERTEX", "[Intersection_1_1_3/Intersection_1_1_3&Face_1_1/Edge_3][weak_name_2]"),
+model.selection("VERTEX", "[Intersection_1_1_1/Intersection_1_1_1][weak_name_2]"),
+model.selection("VERTEX", "[Intersection_1_1_9/Intersection_1_1_9&Face_1_1/Edge_7][weak_name_1]"),
+model.selection("VERTEX", "[Intersection_1_1_7/Intersection_1_1_7&Face_1_1/Edge_5][weak_name_2]"),
+model.selection("VERTEX", "[Intersection_1_1_4/Intersection_1_1_4][weak_name_2]"),
+model.selection("VERTEX", "[Intersection_1_1_1/Intersection_1_1_1][weak_name_1]"),
+model.selection("VERTEX", "[Intersection_1_1_2/Intersection_1_1_2&Face_1_1/Edge_2][weak_name_1]"),
+model.selection("VERTEX", "[Intersection_1_1_4/Intersection_1_1_4][weak_name_1]"),
+model.selection("VERTEX", "[Intersection_1_1_6/Intersection_1_1_6&Face_1_1/Edge_4][weak_name_2]"),
+model.selection("VERTEX", "[Intersection_1_1_10/Intersection_1_1_10&Face_1_1/Edge_8][weak_name_1]"),
+model.selection("VERTEX", "[Intersection_1_1_8/Intersection_1_1_8&Face_1_1/Edge_6][weak_name_1]")]
+
 Group_1 = model.addGroup(Part_1_doc, Group_1_objects)
 Group_2_objects = [model.selection("EDGE", "Intersection_1_1_7"), model.selection("EDGE", "Intersection_1_1_6"), model.selection("EDGE", "Intersection_1_1_3"), model.selection("EDGE", "Intersection_1_1_11"), model.selection("EDGE", "Intersection_1_1_5"), model.selection("EDGE", "Intersection_1_1_1"), model.selection("EDGE", "Intersection_1_1_4"), model.selection("EDGE", "Intersection_1_1_2"), model.selection("EDGE", "Intersection_1_1_10"), model.selection("EDGE", "Intersection_1_1_9"), model.selection("EDGE", "Intersection_1_1_8")]
 Group_2 = model.addGroup(Part_1_doc, Group_2_objects)
index 6940cdbe1e9cb54df8e1d517af4a6e40652b72ef..d4ce0fcd66b2c1700fd9ed474fce3706933620f5 100644 (file)
@@ -1155,6 +1155,32 @@ void Model_AttributeSelection::computeValues(
     }
   }
   if (aToFindPart == 2 && !aNewToOld.IsEmpty()) {
+    // also iterate the whole old shape to find not-modified shapes that contain this old
+    TopoDS_Shape anOldContShape = theOldContext->shape()->impl<TopoDS_Shape>();
+    NCollection_Map<TopAbs_ShapeEnum> aNewTypes; // types of shapes to iterate
+    TopTools_DataMapOfShapeShape::Iterator aNewTypeIter(aNewToOld);
+    for(; aNewTypeIter.More(); aNewTypeIter.Next()) {
+      if (aNewTypeIter.Key().ShapeType() != theValShape.ShapeType())
+        aNewTypes.Add(aNewTypeIter.Key().ShapeType());
+    }
+    NCollection_Map<TopAbs_ShapeEnum>::Iterator aTypeIter(aNewTypes);
+    for(; aTypeIter.More(); aTypeIter.Next()) {
+      for(TopExp_Explorer anExp(anOldContShape, aTypeIter.Value()); anExp.More(); anExp.Next()) {
+        TopoDS_Shape anOld = anExp.Current();
+        if (aNewToOld.IsBound(anOld) || anOlds.Contains(anOld)) // this was modified
+          continue;
+        TopExp_Explorer aValExp(anOld, theValShape.ShapeType());
+        for(; aValExp.More(); aValExp.Next()) {
+          const TopoDS_Shape& anUnchanged = aValExp.Current();
+          if (anUnchanged.IsSame(theValShape)) {
+            aNewToOld.Bind(anOld, anOld);
+            anOlds.Add(anOld);
+            break;
+          }
+        }
+      }
+    }
+
     // map of sub-shapes -> number of occurrences of these shapes in containers
     NCollection_DataMap<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> aSubs;
     TopTools_DataMapOfShapeShape::Iterator aContIter(aNewToOld);
@@ -1174,12 +1200,29 @@ void Model_AttributeSelection::computeValues(
       aSubsIter(aSubs);
     for(; aSubsIter.More(); aSubsIter.Next()) {
       if (aSubsIter.Value().Size() == aCountInOld) {
-        theShapes.Append(aSubsIter.Key());
+        TopoDS_Shape anOld = aSubsIter.Key();
+        // check this exists in the new shape
+        TopExp_Explorer aNew(aNewContShape, anOld.ShapeType());
+        for (; aNew.More(); aNew.Next()) {
+          if (aNew.Current().IsSame(anOld))
+            break;
+        }
+        if (aNew.More())
+          theShapes.Append(anOld);
       }
     }
   }
   if (theShapes.IsEmpty()) { // nothing was changed
-    theShapes.Append(aWasWholeContext ? TopoDS_Shape() : theValShape);
+    if (aWasWholeContext)
+      theShapes.Append(TopoDS_Shape());
+    else { // if theValShape exists in new context, add it without changes, otherwise - nothing
+      for (TopExp_Explorer aNew(aNewContShape, theValShape.ShapeType()); aNew.More(); aNew.Next()){
+        if (aNew.Current().IsSame(theValShape)) {
+          theShapes.Append(theValShape);
+          break;
+        }
+      }
+    }
   }
 }
 
index 893b4fc1cdbd35a0a8d177274b941c3c4844cb28..a0f074c755aaad0c2f3d656d4c523388595490f1 100755 (executable)
@@ -120,6 +120,53 @@ Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner)
 {
 }
 
+/// Checks that shape is presented in the tree with not-selection evolution
+/// In theOriginalLabel it returns label where NS of old sub-shape is stored
+static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAccess2,
+  TopoDS_Shape theShape, TDF_Label& theOriginalLabel)
+{
+  bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape);
+  if (aResult) { //check evolution and a label of this shape
+    for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next())
+    {
+      static Handle(TNaming_NamedShape) aNS;
+      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        if (aNS->Evolution() != TNaming_SELECTED) {
+          theOriginalLabel = aNS->Label();
+          return true;
+        }
+      }
+    }
+  }
+  if (!theAccess2.IsNull()) {
+    static const TDF_Label anEmpty;
+    return isShapeInTree(theAccess2, anEmpty, theShape, theOriginalLabel);
+  }
+  return false;
+}
+
+/// Stores entry to the external label in the entries list at this label
+static void storeExternalReference(const TDF_Label& theExternal, const TDF_Label theThis)
+{
+  // store information about the external document reference to restore old shape on open
+  if (!theExternal.IsNull() && !theExternal.Root().IsEqual(theThis.Root())) {
+    Handle(TDataStd_ExtStringList) anEntries;
+    if (!theThis.FindAttribute(kEXTERNAL_SHAPE_REF, anEntries)) {
+      anEntries = TDataStd_ExtStringList::Set(theThis, kEXTERNAL_SHAPE_REF);
+    }
+    TCollection_AsciiString anEntry;
+    TDF_Tool::Entry(theExternal, anEntry);
+    // check it already contains this entry
+    TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List());
+    for(; anIter.More(); anIter.Next())
+      if (anIter.Value() == anEntry)
+        break;
+    if (!anIter.More()) {
+      anEntries->Append(anEntry);
+    }
+  }
+}
+
 void Model_BodyBuilder::store(const GeomShapePtr& theShape,
                               const bool theIsStoreSameShapes)
 {
@@ -174,8 +221,7 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
     // clean builders
     if (theIsCleanStored)
       clean();
-    // store the new shape as primitive
-    TNaming_Builder aBuilder(aShapeLab);
+    TNaming_Builder* aBuilder = builder(0);
     if (!theFromShape || !theToShape)
       return;  // bad shape
     TopoDS_Shape aShapeBasis = theFromShape->impl<TopoDS_Shape>();
@@ -184,16 +230,35 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
     TopoDS_Shape aShapeNew = theToShape->impl<TopoDS_Shape>();
     if (aShapeNew.IsNull())
       return;  // null shape inside
-    aBuilder.Generated(aShapeBasis, aShapeNew);
+
+    // There is no sense to write history if old shape does not exist in the document.
+    TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
+      ModelAPI_Session::get()->moduleDocument())->generalLabel();
+    TDF_Label anOriginalLabel;
+    if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeBasis, anOriginalLabel)) {
+      if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway
+        aBuilder->Generated(aShapeNew);
+      }
+    } else {
+      if (aBuilder->NamedShape()->Evolution() == TNaming_PRIMITIVE) { // erase primitive before
+        myBuilders.erase(0);
+        aBuilder = builder(0);
+      }
+
+      aBuilder->Generated(aShapeBasis, aShapeNew);
+      // store information about the external document reference to restore old shape on open
+      storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
+    }
+
     // register name
-    if(!aBuilder.NamedShape()->IsEmpty()) {
+    if(!aBuilder->NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
-      if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
+      if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
         std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
         if(!aName.empty()) {
           std::shared_ptr<Model_Document> aDoc =
             std::dynamic_pointer_cast<Model_Document>(document());
-          aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
+          aDoc->addNamingName(aBuilder->NamedShape()->Label(), aName);
         }
       }
     }
@@ -245,7 +310,6 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
   if (aData) {
     // clean builders
     if (theIsCleanStored) clean();
-    // store the new shape as primitive
     TNaming_Builder* aBuilder = builder(0);
     if (!theOldShape || !theNewShape)
       return;  // bad shape
@@ -255,7 +319,26 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
     TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
     if (aShapeNew.IsNull())
       return;  // null shape inside
-    aBuilder->Modify(aShapeOld, aShapeNew);
+
+    // There is no sense to write history if old shape does not exist in the document.
+    TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
+      ModelAPI_Session::get()->moduleDocument())->generalLabel();
+    TDF_Label anOriginalLabel;
+    if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeOld, anOriginalLabel)) {
+      if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway
+        aBuilder->Generated(aShapeNew);
+      }
+    } else {
+      if (aBuilder->NamedShape()->Evolution() == TNaming_PRIMITIVE) { // erase primitive before
+        myBuilders.erase(0);
+        aBuilder = builder(0);
+      }
+
+      aBuilder->Modify(aShapeOld, aShapeNew);
+      // store information about the external document reference to restore old shape on open
+      storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
+    }
+
     if(!aBuilder->NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
       if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
@@ -482,53 +565,6 @@ static void keepTopLevelShapes(ListOfShape& theShapes,
   }
 }
 
-/// Checks that shape is presented in the tree with not-selection evolution
-/// In theOriginalLabel it returns label where NS of old sub-shape is stored
-static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAccess2,
-  TopoDS_Shape theShape, TDF_Label& theOriginalLabel)
-{
-  bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape);
-  if (aResult) { //check evolution and a label of this shape
-    for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next())
-    {
-      static Handle(TNaming_NamedShape) aNS;
-      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
-        if (aNS->Evolution() != TNaming_SELECTED) {
-          theOriginalLabel = aNS->Label();
-          return true;
-        }
-      }
-    }
-  }
-  if (!theAccess2.IsNull()) {
-    static const TDF_Label anEmpty;
-    return isShapeInTree(theAccess2, anEmpty, theShape, theOriginalLabel);
-  }
-  return false;
-}
-
-/// Stores entry to the external label in the entries list at this label
-static void storeExternalReference(const TDF_Label& theExternal, const TDF_Label theThis)
-{
-  // store information about the external document reference to restore old shape on open
-  if (!theExternal.IsNull() && !theExternal.Root().IsEqual(theThis.Root())) {
-    Handle(TDataStd_ExtStringList) anEntries;
-    if (!theThis.FindAttribute(kEXTERNAL_SHAPE_REF, anEntries)) {
-      anEntries = TDataStd_ExtStringList::Set(theThis, kEXTERNAL_SHAPE_REF);
-    }
-    TCollection_AsciiString anEntry;
-    TDF_Tool::Entry(theExternal, anEntry);
-    // check it already contains this entry
-    TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List());
-    for(; anIter.More(); anIter.Next())
-      if (anIter.Value() == anEntry)
-        break;
-    if (!anIter.More()) {
-      anEntries->Append(anEntry);
-    }
-  }
-}
-
 void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
                                            const GeomShapePtr& theOldShape,
                                            const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
index 8368220f942ce1eae62c42e4b1a70bf5d6f7a7c3..3d28be7c668bdff13d28f9f393dc037bfbaf798b 100644 (file)
@@ -29,6 +29,7 @@
 #include <ModelAPI_Tools.h>
 #include <Model_Data.h>
 #include <Events_Loop.h>
+#include <GeomAPI_ShapeIterator.h>
 
 #include <TopoDS_Shape.hxx>
 #include <TopExp_Explorer.hxx>
@@ -256,7 +257,7 @@ void Model_ResultBody::updateSubs(const std::shared_ptr<GeomAPI_Shape>& theThisS
       if (!aShape->isEqual(anOldSubShape)) {
         if (myAlgo.get()) {
           std::list<GeomShapePtr> anOldForSub;
-          computeOldForSub(aShape, anOldForSub);
+          computeOldForSub(aShape, myOlds, anOldForSub);
           myIsGenerated ? aSub->storeGenerated(anOldForSub, aShape, myAlgo) :
             aSub->storeModified(anOldForSub, aShape, myAlgo);
         } else {
@@ -341,15 +342,27 @@ void Model_ResultBody::cleanCash()
   }
 }
 
-void Model_ResultBody::computeOldForSub(
-  const GeomShapePtr& theSubShape, std::list<GeomShapePtr>& theOldForSub)
+void Model_ResultBody::computeOldForSub(const GeomShapePtr& theSub,
+  const std::list<GeomShapePtr>& theAllOlds, std::list<GeomShapePtr>& theOldForSub)
 {
-  std::list<GeomShapePtr>::iterator aRootOlds = myOlds.begin();
-  for(; aRootOlds != myOlds.end(); aRootOlds++) {
+  std::list<GeomShapePtr>::const_iterator aRootOlds = theAllOlds.cbegin();
+  for(; aRootOlds != theAllOlds.cend(); aRootOlds++) {
     ListOfShape aNews;
     myIsGenerated ? myAlgo->generated(*aRootOlds, aNews) : myAlgo->modified(*aRootOlds, aNews);
+    // MakeShape may return alone old shape if there is no history information for this input
+    if (aNews.size() == 1 && aNews.front()->isEqual(*aRootOlds))
+      aNews.clear();
+    if (aNews.empty()) { // try to iterate to sub-elements (for intersection of solids this is face)
+      std::list<GeomShapePtr> theAllSubOlds;
+      for(GeomAPI_ShapeIterator aSubOld(*aRootOlds); aSubOld.more(); aSubOld.next()) {
+        GeomShapePtr aSub = aSubOld.current();
+        if (aSub.get() && !aSub->isNull())
+          theAllSubOlds.push_back(aSub);
+      }
+      computeOldForSub(theSub, theAllSubOlds, theOldForSub);
+    }
     for(ListOfShape::iterator aNewIter = aNews.begin(); aNewIter != aNews.end(); aNewIter++) {
-      if (theSubShape->isSame(*aNewIter)) { // found old that was used for new theSubShape creation
+      if (theSub->isSame(*aNewIter)) { // found old that was used for new theSubShape creation
         theOldForSub.push_back(*aRootOlds);
         break;
       }
index e34d1989b842d1fd1e630c5a18f67db71a0a40d8..a810f2ea0fd0a9bdd5a5e100bad014f1a3b91c96 100644 (file)
@@ -123,8 +123,9 @@ protected:
   // Checks the state of children and parents to send events of creation/erase when needed
   void updateConcealment();
 
-  /// Adds to theOldForSub only old shapes that where used for theSubShape creation
-  void computeOldForSub(const GeomShapePtr& theSubShape, std::list<GeomShapePtr>& theOldForSub);
+  /// Adds to theOldForSub only old shapes that where used for theSub creation
+  void computeOldForSub(const GeomShapePtr& theSub,
+    const std::list<GeomShapePtr>& theAllOlds, std::list<GeomShapePtr>& theOldForSub);
 
   friend class Model_Objects;
 };
index db6fc41bc4115ab0bf14bd504be450872b6f399e..1f4001e78badf99f6ea304ea9673eb6e96cdf5ad 100755 (executable)
@@ -589,7 +589,7 @@ bool Model_Update::processFeature(FeaturePtr theFeature)
           double aNX = aNorm->x(), aNY = aNorm->y(), aNZ = aNorm->z();
           // update sketch plane
           updateArguments(theFeature);
-          //theFeature->attributeChanged("External"); // to recompute origin, direction and normal
+          theFeature->attributeChanged("External"); // to recompute origin, direction and normal
           // check it is updated, so all must be changed
           if (anOrigin->x() != anOX || anOrigin->y() != anOY || anOrigin->z() != anOZ ||
               aDir->x() != aDX || aDir->y() != aDY || aDir->z() != aDZ ||