]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Correct processing of the last feature if the sketch is being added to/removed from...
authorazv <azv@opencascade.com>
Fri, 1 Dec 2017 08:56:12 +0000 (11:56 +0300)
committerazv <azv@opencascade.com>
Fri, 1 Dec 2017 08:56:12 +0000 (11:56 +0300)
src/Model/Model_Objects.cpp
src/ModelAPI/Test/TestFolder_Sketch.py [new file with mode: 0644]

index 0f3b779f43aaa535d84239cc3ce826f1f4b673a8..b5dcbbd18ad1cd3fc885f8beca3198c0385256c4 100644 (file)
@@ -1351,6 +1351,26 @@ static FeaturePtr limitingFeature(std::list<FeaturePtr>& theFeatures, const bool
   return aFeature;
 }
 
+// Obtain index of last sub-feature in the composite feature.
+// Parameter theIndex is an index of theComposite feature in theReferences list.
+static void lastIndexOfComposite(Model_Objects* theObjectsEnt,
+                                 const FeaturePtr& theComposite,
+                                 const Handle(TDataStd_ReferenceArray)& theReferences,
+                                 int& theIndex)
+{
+  CompositeFeaturePtr aComposite =
+      std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theComposite);
+  if (!aComposite)
+    return;
+
+  for (; theIndex < theReferences->Upper(); ++theIndex) {
+    TDF_Label aNextLab = theReferences->Value(theIndex + 1);
+    ObjectPtr aNextObj = theObjectsEnt->object(aNextLab);
+    if (!aComposite->isSub(aNextObj))
+      break;
+  }
+}
+
 std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
       const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
       const bool theBelow)
@@ -1363,9 +1383,9 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
   if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
     return FolderPtr(); // no reference array (something is wrong)
 
+  // obtain first or last feature of the list according to the direction where to search a folder
   std::list<std::shared_ptr<ModelAPI_Feature> > aFeatures = theFeatures;
   std::shared_ptr<ModelAPI_Feature> aLimitingFeature = limitingFeature(aFeatures, theBelow);
-
   std::shared_ptr<Model_Data> aData =
       std::static_pointer_cast<Model_Data>(aLimitingFeature->data());
   if (!aData || !aData->isValid())
@@ -1374,8 +1394,11 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
   // label of the first feature in the list for fast searching
   TDF_Label aFirstFeatureLabel = aData->label().Father();
 
-  // find a folder above the features and
-  // check the given features represent a sequential list of objects following the folder
+  // Search applicable folder (above or below the list of features):
+  // [above] - find in the list of references the last folder
+  //           before the first feature from the list;
+  // [below] - skip all references until last feature in the list is found,
+  //           then check the next reference is a folder.
   FolderPtr aFoundFolder;
   TDF_Label aLastFeatureInFolder;
   int aRefIndex = aRefs->Lower();
@@ -1388,6 +1411,7 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
     if (theBelow)
       continue;
 
+    // skip features in the current folder
     if (!aLastFeatureInFolder.IsNull()) {
       if (IsEqual(aCurLabel, aLastFeatureInFolder))
         aLastFeatureInFolder.Nullify(); // the last feature in the folder is achived
@@ -1410,10 +1434,18 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
     }
   }
 
+  // Skip all features in the composite until the last feature is not reached.
+  // Keep the index, due to aLimitingFeature may be composite, thus aRefIndex
+  // will be set to the last sub. But if we search a folder below the features,
+  // we do not want to obtain index current composite feature once again.
+  int anIndexCopy = aRefIndex;
+  lastIndexOfComposite(this, aLimitingFeature, aRefs, aRefIndex);
+
   if (theBelow && aRefIndex < aRefs->Upper()) {
     // check the next object is a folder
     TDF_Label aLabel = aRefs->Value(aRefIndex + 1);
     aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aLabel));
+    aRefIndex = anIndexCopy; // restore index of parent composite
   }
 
   if (!aLastFeatureInFolder.IsNull() || // the last feature of the folder above is not found
@@ -1433,6 +1465,21 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
     if (aData && aData->isValid())
       aFeatureLabel = aData->label().Father();
 
+    if (theBelow) {
+      // find index of parent composite feature
+      FeaturePtr aComposite = ModelAPI_Tools::compositeOwner(feature(aCurLabel));
+      if (aComposite) {
+        aData = std::static_pointer_cast<Model_Data>(aComposite->data());
+        if (aData && aData->isValid())
+          aCurLabel = aData->label().Father();
+        while (aRefs->Value(aRefIndex) != aCurLabel)
+          --aRefIndex;
+      }
+    } else {
+      // skip all features in the composite until the last feature is not reached
+      lastIndexOfComposite(this, aLimitingFeature, aRefs, aRefIndex);
+    }
+
     if (!IsEqual(aCurLabel, aFeatureLabel))
       return FolderPtr(); // not a sequential list
   }
@@ -1448,11 +1495,17 @@ bool Model_Objects::moveToFolder(
     return false;
 
   // labels for the folder and last feature in the list
+  // (if the last feature is composite, obtain label of the last sub-feature)
   TDF_Label aFolderLabel, aLastFeatureLabel;
   std::shared_ptr<Model_Data> aData =
       std::static_pointer_cast<Model_Data>(theFolder->data());
   if (aData && aData->isValid())
     aFolderLabel = aData->label().Father();
+  FeaturePtr aLastFeature = theFeatures.back();
+  CompositeFeaturePtr aComposite =
+      std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aLastFeature);
+  if (aComposite)
+    aLastFeature = aComposite->subFeature(aComposite->numberOfSubs() - 1);
   aData = std::static_pointer_cast<Model_Data>(theFeatures.back()->data());
   if (aData && aData->isValid())
     aLastFeatureLabel = aData->label().Father();
@@ -1576,7 +1629,16 @@ bool Model_Objects::removeFromFolder(
     aFolderEndFeature   = aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->value();
   }
 
-  FeaturePtr aFeatureToFind = isExtractBeforeFolder ? theFeatures.back() : theFeatures.front();
+  FeaturePtr aFeatureToFind;
+  if (isExtractBeforeFolder) {
+    aFeatureToFind = theFeatures.back();
+    // if the last feature is composite, obtain its last sub-feature
+    CompositeFeaturePtr aComposite =
+        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureToFind);
+    if (aComposite)
+      aFeatureToFind = aComposite->subFeature(aComposite->numberOfSubs() - 1);
+  } else
+    aFeatureToFind = theFeatures.front();
   std::shared_ptr<Model_Data> aData =
       std::static_pointer_cast<Model_Data>(aFeatureToFind->data());
   if (!aData || !aData->isValid())
diff --git a/src/ModelAPI/Test/TestFolder_Sketch.py b/src/ModelAPI/Test/TestFolder_Sketch.py
new file mode 100644 (file)
index 0000000..fb7cbf1
--- /dev/null
@@ -0,0 +1,188 @@
+## Copyright (C) 2014-2017  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<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+    Test checks adding sketch into a folder
+"""
+
+from ModelAPI import *
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+Sketch_0 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_0.addLine(10, -10, 10, 10)
+model.do()
+
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 25)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 50, 0)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchCircle_2 = Sketch_2.addCircle(100, -100, 50)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")], model.selection(), 10, 0)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("SOLID", "Extrusion_2_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_2_1/To_Face_1"))
+SketchProjection_1 = Sketch_3.addProjection(model.selection("VERTEX", "Extrusion_2_1/Generated_Face_1&Extrusion_2_1/To_Face_1__cc"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_3 = Sketch_3.addCircle(100, -100, 25)
+SketchConstraintCoincidence_1 = Sketch_3.setCoincident(SketchPoint_1.result(), SketchCircle_3.center())
+ExtrusionCut_1.setNestedSketch(Sketch_3)
+model.do()
+model.end()
+
+
+aSession = ModelAPI_Session.get()
+aPartDoc = aSession.activeDocument()
+
+
+#=========================================================================
+# Test 1. Sketch and extrusion could be added to the folder above
+#=========================================================================
+aSession.startOperation()
+Folder_1 = aPartDoc.addFolder(Sketch_1.feature())
+aSession.finishOperation()
+
+NB_FEATURES_FULL = 7
+NB_FEATURES_OUT  = 7
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+toFolder = FeatureList()
+toFolder.append(Sketch_1.feature())
+toFolder.append(Extrusion_1.feature())
+
+# move features to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderAbove(toFolder)
+assert(aFolder is not None and aFolder.data().isEqual(Folder_1.data()))
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+NB_FEATURES_OUT -= 2
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the sketch in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_1.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 0)
+# check the index of the extrusion in the folder
+aFound = aPartDoc.findContainingFolder(Extrusion_1.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 1)
+
+
+#=========================================================================
+# Test 2. Sketch could be added to the folder below
+#=========================================================================
+aSession.startOperation()
+Folder_2 = aPartDoc.addFolder(Extrusion_2.feature())
+aSession.finishOperation()
+
+NB_FEATURES_FULL += 1
+NB_FEATURES_OUT  += 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+toFolder = FeatureList()
+toFolder.append(Sketch_2.feature())
+
+# move feature to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderBelow(toFolder)
+assert(aFolder is not None and aFolder.data().isEqual(Folder_2.data()))
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+NB_FEATURES_OUT -= 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the sketch in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_2.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 0)
+
+
+#=========================================================================
+# Test 3. Sketch could be removed from the folder
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(Sketch_1.feature())
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder)
+aSession.finishOperation()
+assert(isMovedOut)
+assert(aPartDoc.index(Sketch_1.feature(), True) == 1), "Wrong index of the {}: {}".format(Sketch_1.feature().name(), aPartDoc.index(Sketch_1.feature(), True))
+NB_FEATURES_OUT += 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+
+#=========================================================================
+# Test 4. Add 2 sketches to the folder below
+#=========================================================================
+
+toFolder = FeatureList()
+toFolder.append(Sketch_0.feature())
+toFolder.append(Sketch_1.feature())
+
+# move features to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderBelow(toFolder)
+assert(aFolder is not None and aFolder.data().isEqual(Folder_1.data()))
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+NB_FEATURES_OUT -= 2
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the sketch in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_0.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 0)
+# check the index of the extrusion in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_1.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 1)
+
+
+from salome.shaper import model
+assert(model.checkPythonDump())