From 9fd87da35f5d3f190b72fed3bb03ffea6eed3404 Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 1 Dec 2017 11:56:12 +0300 Subject: [PATCH] Correct processing of the last feature if the sketch is being added to/removed from the folder --- src/Model/Model_Objects.cpp | 70 ++++++++- src/ModelAPI/Test/TestFolder_Sketch.py | 188 +++++++++++++++++++++++++ 2 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 src/ModelAPI/Test/TestFolder_Sketch.py diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 0f3b779f4..b5dcbbd18 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -1351,6 +1351,26 @@ static FeaturePtr limitingFeature(std::list& 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(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 Model_Objects::findFolder( const std::list >& theFeatures, const bool theBelow) @@ -1363,9 +1383,9 @@ std::shared_ptr 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 > aFeatures = theFeatures; std::shared_ptr aLimitingFeature = limitingFeature(aFeatures, theBelow); - std::shared_ptr aData = std::static_pointer_cast(aLimitingFeature->data()); if (!aData || !aData->isValid()) @@ -1374,8 +1394,11 @@ std::shared_ptr 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 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 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(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 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(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 aData = std::static_pointer_cast(theFolder->data()); if (aData && aData->isValid()) aFolderLabel = aData->label().Father(); + FeaturePtr aLastFeature = theFeatures.back(); + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(aLastFeature); + if (aComposite) + aLastFeature = aComposite->subFeature(aComposite->numberOfSubs() - 1); aData = std::static_pointer_cast(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(aFeatureToFind); + if (aComposite) + aFeatureToFind = aComposite->subFeature(aComposite->numberOfSubs() - 1); + } else + aFeatureToFind = theFeatures.front(); std::shared_ptr aData = std::static_pointer_cast(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 index 000000000..fb7cbf1c6 --- /dev/null +++ b/src/ModelAPI/Test/TestFolder_Sketch.py @@ -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 +## + +""" + 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()) -- 2.39.2