Salome HOME
Add tutorial help page.
[modules/shaper.git] / src / Model / Model_ResultConstruction.cpp
index 371d4062b9fdb03649a99f9a2dd729a0f92f024f..ad9c9a3070e2f9c060b0a9affef787a4e46d243f 100644 (file)
@@ -68,12 +68,12 @@ void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
     if (!theShape.get() || !theShape->isEqual(myShape)) {
         static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
         ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
+        if (theShape.get()) {
+          myFacesUpToDate = false;
+          myFaces.clear();
+        }
     }
     myShape = theShape;
-    if (theShape.get()) {
-      myFacesUpToDate = false;
-      myFaces.clear();
-    }
   }
 }
 
@@ -94,7 +94,7 @@ void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
   myIsInHistory = isInHistory;
 }
 
-int Model_ResultConstruction::facesNum()
+int Model_ResultConstruction::facesNum(const bool theUpdateNaming)
 {
   if (!myFacesUpToDate) {
     std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
@@ -111,6 +111,23 @@ int Model_ResultConstruction::facesNum()
       }
     }
     myFacesUpToDate = true;
+
+    // update all the faces and sub-elements in the naming structure
+    if (theUpdateNaming) {
+      DocumentPtr anEmptyExt;
+      bool aNotExt = false;
+      TDF_Label aDataLab = startLabel(anEmptyExt, aNotExt);
+      TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
+      for(; aSubsIter.More(); aSubsIter.Next()) {
+        const TDF_Label aLab = aSubsIter.Value();
+        if (aLab.Tag() == 1) // skip the root shape label
+          continue;
+        Handle(TNaming_NamedShape) aNS;
+        if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+          update(aLab.Tag() - 1, anEmptyExt, aNotExt);
+        }
+      }
+    }
   }
   return int(myFaces.size());
 }
@@ -132,7 +149,7 @@ void Model_ResultConstruction::setInfinite(const bool theInfinite)
 
 void Model_ResultConstruction::setIsConcealed(const bool theValue)
 {
-  // do nothing: the construction element is never consealed
+  // do nothing: the construction element is never concealed
 }
 
 static const int kSTART_VERTEX_DELTA = 1000000;
@@ -267,9 +284,36 @@ std::string fullName(CompositeFeaturePtr theComposite, const TopoDS_Shape& theSu
 }
 
 // stores shape and name on sub-label of the main stored shape
-static void saveSubName(TDF_Label& theLab, const bool isSelectionMode, const TopoDS_Shape& aSub,
+static void saveSubName(CompositeFeaturePtr theComposite,
+  TDF_Label& theLab, const bool isSelectionMode, TopoDS_Shape aSub,
   std::shared_ptr<Model_Document> theDoc, std::string theFullName)
 {
+  // trying to store the edge of composite result, not sketch sub as it is
+  if (aSub.ShapeType() == TopAbs_EDGE) {
+    ResultPtr aRes = theComposite->firstResult();
+    ResultConstructionPtr aConstr = std::dynamic_pointer_cast<Model_ResultConstruction>(aRes);
+    if (aConstr.get()) {
+      Standard_Real aSubFirst, aSubLast;
+      TopoDS_Edge aSubEdge = TopoDS::Edge(aSub);
+      Handle(Geom_Curve) aSubCurve = BRep_Tool::Curve(aSubEdge, aSubFirst, aSubLast);
+      for(int aFaceIndex = 0; aFaceIndex < aConstr->facesNum(); aFaceIndex++) {
+        GeomShapePtr aGFace = aConstr->face(aFaceIndex);
+        TopoDS_Shape aFace = aGFace->impl<TopoDS_Shape>();
+        for(TopExp_Explorer anExp(aFace, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+          TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current());
+          Standard_Real aFirst, aLast;
+          Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+          if (aCurve == aSubCurve &&
+              ((fabs(aFirst - aSubFirst) < 1.e-9 &&  fabs(aLast - aSubLast) < 1.e-9)) ||
+              (fabs(aFirst - aSubLast) < 1.e-9 &&  fabs(aLast - aSubFirst) < 1.e-9)) {
+            aSub = anEdge;
+            break;
+          }
+        }
+      }
+    }
+  }
+
   TNaming_Builder aBuilder(theLab);
   if (isSelectionMode)
     aBuilder.Select(aSub, aSub);
@@ -336,17 +380,50 @@ int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSu
   // if the subshape is part of a result face, select the whole face (#1997)
   bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label
   if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) {
-    for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
-      TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
-      for(; anExp.More(); anExp.Next()) {
-        if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
-          // here just store the face index (to update face if update of edge is needed)
-          TNaming_Builder aBuilder(aLab);
-          aBuilder.Select(aSubShape, aSubShape);
-          int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
-          TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
-          isSelectionMode = true;
-          break;
+    // but before check that sub-vertex correctly detected as intersection of sketch edges (#2389)
+    int anEdgesNum = 2;
+    if (aSubShape.ShapeType() == TopAbs_VERTEX) {
+      anEdgesNum = 0;
+      ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
+      FeaturePtr aThisFeature = document()->feature(aThisPtr);
+      CompositeFeaturePtr aComposite =
+        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
+      if (aComposite.get()) {
+        const int aSubNum = aComposite->numberOfSubs();
+        for(int a = 0; a < aSubNum; a++) {
+          int aSubID = aComposite->subFeatureId(a);
+          FeaturePtr aSub = aComposite->subFeature(a);
+          const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
+          std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
+          for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
+            ResultConstructionPtr aConstr =
+              std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
+            if (aConstr->shape() && aConstr->shape()->isEdge()) {
+              TopoDS_Shape aResShape = aConstr->shape()->impl<TopoDS_Shape>();
+              for(TopExp_Explorer anExp(aResShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
+                if (aSubShape.IsSame(anExp.Current())) {
+                  anEdgesNum++;
+                  break;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    if (anEdgesNum > 1) {
+      for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
+        TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
+        for(; anExp.More(); anExp.Next()) {
+          if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
+            // here just store the face index (to update face if update of edge is needed)
+            TNaming_Builder aBuilder(aLab);
+            aBuilder.Select(aSubShape, aSubShape);
+            int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
+            TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
+            isSelectionMode = true;
+            break;
+          }
         }
       }
     }
@@ -413,6 +490,10 @@ int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSu
   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
   const int aSubNum = aComposite->numberOfSubs();
+  // subs are placed on unique labels because of #2248: sketch curve may produce several edges,
+  // but #2401 - on stable labels
+  NCollection_Map<int> aUsedIDMap; // already used lab tags for placement of shapes
+
   for(int a = 0; a < aSubNum; a++) {
     FeaturePtr aSub = aComposite->subFeature(a);
     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
@@ -441,9 +522,12 @@ int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSu
                   Standard_Real aFirst, aLast;
                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
                   if (aFaceCurve == aCurve) {
+                    while(aUsedIDMap.Contains(anID))
+                      anID += 100000;
+                    aUsedIDMap.Add(anID);
                     TDF_Label aSubLab = aLab.FindChild(anID);
                     std::string aFullNameSub = fullName(aComposite, anEdge);
-                    saveSubName(aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub);
+                    saveSubName(aComposite, aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub);
 
                     int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
                     if (anOrient != 0) {
@@ -454,14 +538,15 @@ int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSu
                 }
               } else { // put vertices of the selected edge to sub-labels
                 // add edges to sub-label to support naming for edges selection
-                int aTagIndex = anID + kSTART_VERTEX_DELTA;
                 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
-                  anEdgeExp.More();
-                  anEdgeExp.Next(), aTagIndex += kSTART_VERTEX_DELTA) {
+                      anEdgeExp.More(); anEdgeExp.Next()) {
                     TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
-                    TDF_Label aSubLab = aLab.FindChild(aTagIndex);
+                    while(aUsedIDMap.Contains(anID))
+                      anID += 100000;
+                    aUsedIDMap.Add(anID);
+                    TDF_Label aSubLab = aLab.FindChild(anID);
                     std::string aFullNameSub = fullName(aComposite, aV);
-                    saveSubName(aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub);
+                    saveSubName(aComposite, aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub);
                 }
               }
             }
@@ -543,10 +628,30 @@ bool Model_ResultConstruction::update(const int theIndex,
       }
       return aRes;
     } else {
+      // check is this modified or not
+      std::shared_ptr<GeomAPI_Shape> aNewShape = shape();
+      TopoDS_Shape anOldSh;
+      Handle(TNaming_NamedShape) aNS;
+      if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        anOldSh = aNS->Get();
+      }
+      if (aNewShape.get()) {
+        if (anOldSh.IsNull())
+          theModified = true;
+        else {
+          std::shared_ptr<GeomAPI_Shape> anOldShape(new GeomAPI_Shape);
+          anOldShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(anOldSh));
+          theModified = !anOldShape->isEqual(aNewShape);
+        }
+      }
+      else if (!anOldSh.IsNull()) {
+        theModified = true;
+      }
+
       // For correct naming selection, put the shape into the naming structure.
       // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
       TNaming_Builder aBuilder(aLab);
-      aBuilder.Generated(shape()->impl<TopoDS_Shape>());
+      aBuilder.Generated(aNewShape->impl<TopoDS_Shape>());
     }
     return shape() && !shape()->isNull();
   }
@@ -562,7 +667,7 @@ bool Model_ResultConstruction::update(const int theIndex,
     Handle(TDF_Reference) aRef;
     if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
       int aFaceIndex = aRef->Get().Tag();
-      // don't check selection ,since face may disappear, but the shape stays correct
+      // don't check selection since face may disappear, but the shape stays correct
       Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified);
     }
     // getting a type of selected shape