Salome HOME
Additional fix for the #2659 optimization
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
index 72fff493f6b380c846efc0562dd475b5dd9d4a8e..7b1259db39ecaa7c013a37deb329fdf113d7fa38 100644 (file)
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
+#include <ModelGeomAlgo_Shape.h>
 #include <Events_InfoMessage.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Vertex.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_NExplode.h>
 
 #include <TNaming_Selector.hxx>
 #include <TNaming_NamedShape.hxx>
@@ -86,6 +88,10 @@ Standard_GUID kCIRCLE_CENTER("d0d0e0f1-217a-4b95-8fbb-0c4132f23718");
 Standard_GUID kELLIPSE_CENTER1("f70df04c-3168-4dc9-87a4-f1f840c1275d");
 // identifier of the selection of the second focus point of ellipse on edge
 Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32");
+// identifier of the weak naming index
+Standard_GUID kWEAK_NAMING("9dcdd9be-a3a9-46eb-9b16-1c957ab20142");
+// identifier of the weak naming sub-shape type
+Standard_GUID kWEAK_NAMING_SHAPETYPE("6b9cc709-e320-4a1f-9c42-df5622369ea7");
 
 // prefix for the whole feature context identification
 const static std::string kWHOLE_FEATURE = "all-in-";
@@ -132,6 +138,8 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext,
   aSelLab.ForgetAttribute(kCIRCLE_CENTER);
   aSelLab.ForgetAttribute(kELLIPSE_CENTER1);
   aSelLab.ForgetAttribute(kELLIPSE_CENTER2);
+  aSelLab.ForgetAttribute(kWEAK_NAMING);
+  aSelLab.ForgetAttribute(kWEAK_NAMING_SHAPETYPE);
 
   bool isDegeneratedEdge = false;
   // do not use the degenerated edge as a shape, a null context and shape is used in the case
@@ -383,6 +391,30 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::internalValue(CenterTyp
       }
     }
 
+    if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used
+      Handle(TDataStd_Integer) aWeakId;
+      aSelLab.FindAttribute(kWEAK_NAMING, aWeakId);
+      // get the context shape
+      GeomShapePtr aContextShape;
+      ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(context());
+      if (aBody.get()) {
+        aContextShape = aBody->shape();
+      } else {
+        ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
+        if (aResult) {
+          aContextShape = aResult->shape();
+        }
+      }
+      if (!aContextShape.get())
+        return GeomShapePtr();
+      Handle(TDataStd_Integer) aWeakShapeType;
+      aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType);
+      GeomAlgoAPI_NExplode aNExplode(
+        aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get()));
+      GeomShapePtr aValue = aNExplode.shape(aWeakId->Get());
+      return aValue;
+    }
+
     Handle(TNaming_NamedShape) aSelection;
     if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
       TopoDS_Shape aSelShape = aSelection->Get();
@@ -631,6 +663,29 @@ bool Model_AttributeSelection::update()
   }
 
   if (aContext->groupName() == ModelAPI_ResultBody::group()) {
+    if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used
+      Handle(TDataStd_Integer) aWeakId;
+      aSelLab.FindAttribute(kWEAK_NAMING, aWeakId);
+      // get the context shape
+      GeomShapePtr aContextShape;
+      ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
+      if (aBody.get()) {
+        aContextShape = aBody->shape();
+      } else {
+        ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
+        if (aResult) {
+          aContextShape = aResult->shape();
+        }
+      }
+      if (!setInvalidIfFalse(aSelLab, aContextShape.get() != NULL)) // context shape not found
+        return false;
+      Handle(TDataStd_Integer) aWeakShapeType;
+      aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType);
+      GeomAlgoAPI_NExplode aNExplode(
+        aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get()));
+      GeomShapePtr aValue = aNExplode.shape(aWeakId->Get());
+      return setInvalidIfFalse(aSelLab, aValue.get() != NULL);
+    }
     // body: just a named shape, use selection mechanism from OCCT
     TNaming_Selector aSelector(aSelLab);
     TopoDS_Shape anOldShape;
@@ -772,7 +827,38 @@ void Model_AttributeSelection::selectBody(
       if (aEraseResults) // erase results without flash deleted and redisplay: do it after Select
         aFeatureOwner->removeResults(0, false, false);
     }
-    aSel.Select(aNewSub, aNewContext);
+    bool aSelectorOk = true;
+    try {
+      aSel.Select(aNewSub, aNewContext);
+    } catch(...) {
+      aSelectorOk = false;
+    }
+    // face may become divided after the model update, so, new labels may be added to the scope
+    myScope.Clear();
+
+    // check that selection is correct, otherwise use weak naming solution
+    TDF_Label aSelLab = selectionLabel();
+    aSelLab.ForgetAttribute(kWEAK_NAMING);
+    Handle(TNaming_NamedShape) aSelectorShape;
+    if (aSelectorOk && aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelectorShape))
+    {
+      TopoDS_Shape aShape = aSelectorShape->Get();
+      if (aShape.IsNull() || aShape.ShapeType() != aNewSub.ShapeType())
+        aSelectorOk = false;
+    }
+    if (!aSelectorOk) { // weak naming identifier instead
+      GeomShapePtr aContextShape(new GeomAPI_Shape);
+      aContextShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aNewContext));
+      GeomShapePtr aValueShape(new GeomAPI_Shape);
+      aValueShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aNewSub));
+
+      GeomAlgoAPI_NExplode aNExplode(aContextShape, aValueShape->shapeType());
+      int anId = aNExplode.index(aValueShape);
+      if (anId) {
+        TDataStd_Integer::Set(aSelLab, kWEAK_NAMING, anId);
+        TDataStd_Integer::Set(aSelLab, kWEAK_NAMING_SHAPETYPE, int(aValueShape->shapeType()));
+      }
+    }
 
     if (aEraseResults) { // flash after Select : in Groups it makes selection with shift working
       static Events_Loop* aLoop = Events_Loop::loop();
@@ -860,7 +946,15 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
     return "";
   }
 
-  Model_SelectionNaming aSelNaming(selectionLabel());
+  TDF_Label aSelLab = selectionLabel();
+  Handle(TDataStd_Integer) aWeakId;
+  if (aSelLab.FindAttribute(kWEAK_NAMING, aWeakId)) { // a weak naming is used
+    std::ostringstream aNameStream;
+    aNameStream<<aCont->data()->name()<<"/weak_name_"<<aWeakId->Get();
+    return aNameStream.str();
+  }
+
+  Model_SelectionNaming aSelNaming(aSelLab);
   std::string aResult = aSelNaming.namingName(
     aCont, aSubSh, theDefaultName, owner()->document() != aCont->document());
   if (aCenterType != NOT_CENTER) {
@@ -1066,81 +1160,83 @@ void Model_AttributeSelection::selectSubShape(
   reset();
 }
 
-
-// Check the point is within shape's bounding box
-static bool isPointWithinBB(const GeomPointPtr& thePoint, const GeomShapePtr& theShape)
-{
-  double aXMin, aXMax, aYMin, aYMax, aZMin, aZMax;
-  theShape->computeSize(aXMin, aYMin, aZMin, aXMax, aYMax, aZMax);
-  return thePoint->x() >= aXMin - Precision::Confusion() &&
-         thePoint->x() <= aXMax + Precision::Confusion() &&
-         thePoint->y() >= aYMin - Precision::Confusion() &&
-         thePoint->y() <= aYMax + Precision::Confusion() &&
-         thePoint->z() >= aZMin - Precision::Confusion() &&
-         thePoint->z() <= aZMax + Precision::Confusion();
-}
-
-// Select sub-shape of the given type, which contains the given point
-static GeomShapePtr findSubShape(const GeomShapePtr& theShape,
-                                   const GeomAPI_Shape::ShapeType& theType,
-                                   const GeomPointPtr& thePoint)
-{
-  std::list<GeomShapePtr> aSubs = theShape->subShapes(theType);
-  for (std::list<GeomShapePtr>::const_iterator aSubIt = aSubs.begin();
-    aSubIt != aSubs.end(); ++aSubIt) {
-    if ((*aSubIt)->middlePoint()->distance(thePoint) < Precision::Confusion())
-      return *aSubIt;
-  }
-
-  // not found
-  return GeomShapePtr();
-}
-
 void Model_AttributeSelection::selectSubShape(const std::string& theType,
                                               const GeomPointPtr& thePoint)
 {
   if (theType.empty() || !thePoint)
     return;
 
+  // list of parent features
+  FeaturePtr anOwner = ModelAPI_Feature::feature(owner());
+  std::set<FeaturePtr> aParents = ModelAPI_Tools::getParents(anOwner);
+
+  int aSelectionIndex = 0;
   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(theType);
-  GeomShapePtr aFoundSubShape;
+  if (aType == GeomAPI_Shape::SHAPE) {
+    // possibly, the string consists of the type and the index,
+    // thus, try to separate them
+    size_t aUndersporePos = theType.find_first_of('_');
+    if (aUndersporePos != std::string::npos)
+      aType = GeomAPI_Shape::shapeTypeByStr(theType.substr(0, aUndersporePos));
+
+    if (aType != GeomAPI_Shape::SHAPE) {
+      for (std::string::const_iterator aChar = theType.begin() + aUndersporePos + 1;
+           aChar != theType.end(); ++aChar) {
+        if (std::isdigit(*aChar))
+          aSelectionIndex = aSelectionIndex * 10 + (*aChar - '0');
+        else {
+          aSelectionIndex = 1;
+          break;
+        }
+      }
+      aSelectionIndex -= 1;
+    }
+  }
 
-  std::list<FeaturePtr> aFeatures = owner()->document()->allFeatures();
+  std::list<ModelGeomAlgo_Shape::SubshapeOfResult> anAppropriate;
+
+  // collect features from PartSet and the current part
+  SessionPtr aSession = ModelAPI_Session::get();
+  std::list<FeaturePtr> aFeatures = aSession->moduleDocument()->allFeatures();
+  if (aSession->moduleDocument() != owner()->document()) {
+    std::list<FeaturePtr> aPartFeatures = owner()->document()->allFeatures();
+    aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end());
+  }
   // Process results of all features from the last to the first
   // to find appropriate sub-shape
   for (std::list<FeaturePtr>::const_reverse_iterator anIt = aFeatures.rbegin();
        anIt != aFeatures.rend(); ++anIt) {
-    const std::list<ResultPtr>& aResults = (*anIt)->results();
-    for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
-         aResIt != aResults.end(); ++aResIt) {
-      GeomShapePtr aCurShape = (*aResIt)->shape();
-      // first of all, check the point is within bounding box of the result
-      if (!isPointWithinBB(thePoint, aCurShape))
-        continue;
-      // now, process all sub-shapes of the given type and check their inner points
-      aFoundSubShape = findSubShape(aCurShape, aType, thePoint);
-      if (aFoundSubShape) {
-        setValue(*aResIt, aFoundSubShape);
+    // selection cannot be linked to the parent features
+    if (aParents.find(*anIt) != aParents.end())
+      continue;
+    // check the feature is a part of composite feature (like sketch elements),
+    // then do not process it, it will be processed in scope of composite feature
+    bool isSubOfComposite = false;
+    const std::set<AttributePtr>& aRefs = (*anIt)->data()->refsToMe();
+    for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+         aRefIt != aRefs.end() && !isSubOfComposite; ++aRefIt) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature((*aRefIt)->owner());
+      CompositeFeaturePtr aCompFeature =
+          std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
+      isSubOfComposite = aCompFeature && aCompFeature->isSub(*anIt);
+    }
+    if (isSubOfComposite)
+      continue;
+
+    // process results of the current feature to find appropriate sub-shape
+    if (ModelGeomAlgo_Shape::findSubshapeByPoint(*anIt, thePoint, aType, anAppropriate)) {
+      std::list<ModelGeomAlgo_Shape::SubshapeOfResult>::iterator anApIt = anAppropriate.begin();
+      for (; aSelectionIndex > 0 && anApIt != anAppropriate.end(); --aSelectionIndex)
+        ++anApIt; // skip this shape, because one of the previous is selected
+
+      if (anApIt != anAppropriate.end()) {
+        if (anApIt->myCenterType == (int)ModelAPI_AttributeSelection::NOT_CENTER)
+          setValue(anApIt->myResult, anApIt->mySubshape);
+        else
+          setValueCenter(anApIt->myResult, anApIt->mySubshape->edge(),
+                         (ModelAPI_AttributeSelection::CenterType)anApIt->myCenterType);
         return;
       }
-
-      // special case for ResultConstruction if the FACE is selected
-      ResultConstructionPtr aResConstr =
-          std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIt);
-      if (aResConstr && aType >= GeomAPI_Shape::FACE) {
-        int aNbFaces = aResConstr->facesNum();
-        for (int aFaceInd = 0; aFaceInd < aNbFaces; ++aFaceInd) {
-          GeomFacePtr aCurFace = aResConstr->face(aFaceInd);
-          // check the point is within bounding box of the face
-          if (!isPointWithinBB(thePoint, aCurFace))
-            continue;
-          aFoundSubShape = findSubShape(aCurFace, aType, thePoint);
-          if (aFoundSubShape) {
-            setValue(*aResIt, aFoundSubShape);
-            return;
-          }
-        }
-      }
     }
   }
 
@@ -1149,6 +1245,32 @@ void Model_AttributeSelection::selectSubShape(const std::string& theType,
   reset();
 }
 
+void Model_AttributeSelection::selectSubShape(const std::string& theType,
+  const std::string& theContextName, const int theIndex)
+{
+  // selection of context by name
+  //std::string aNamingContextName = theContextName + "/";
+  //selectSubShape(theType, aNamingContextName);
+  std::shared_ptr<Model_Document> aDoc =
+    std::dynamic_pointer_cast<Model_Document>(owner()->document());
+  if (aDoc.get()) {
+    bool aUnique = true;
+    std::string aContextName = theContextName;
+    std::string anEmptySub = "";
+    ResultPtr aContext = aDoc->findByName(aContextName, anEmptySub, aUnique);
+    //ResultPtr aContext = context();
+    if (aContext.get()) {
+      GeomShapePtr aContShape = aContext->shape();
+      if (aContShape.get()) {
+        GeomAlgoAPI_NExplode aNExp(aContShape, GeomAPI_Shape::shapeTypeByStr(theType));
+        GeomShapePtr aValue = aNExp.shape(theIndex);
+        if (aValue.get())
+          setValue(aContext, aValue);
+      }
+    }
+  }
+}
+
 int Model_AttributeSelection::Id()
 {
   int anID = 0;
@@ -1565,3 +1687,8 @@ void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent
 {
   myParent = theParent;
 }
+
+bool Model_AttributeSelection::isWeakNaming()
+{
+  return selectionLabel().IsAttribute(kWEAK_NAMING);
+}