From df0e68da0ae0ddc9f9b4ad6a63fd57d4f32ebdf3 Mon Sep 17 00:00:00 2001 From: mpv Date: Tue, 6 Nov 2018 15:06:42 +0300 Subject: [PATCH] Implementation of geometrical naming and a first unit-test for placement face selection. --- src/FeaturesPlugin/Test/Test2724.py | 2 +- src/Model/Model_AttributeSelection.cpp | 31 +++++-- src/ModelAPI/CMakeLists.txt | 1 + src/ModelAPI/Test/Test2685.py | 2 +- src/ModelAPI/Test/TestGeomNamingPlacement.py | 89 ++++++++++++++++++++ src/ModelHighAPI/ModelHighAPI_Tools.cpp | 24 ++++-- src/ModelHighAPI/ModelHighAPI_Tools.h | 10 ++- src/Selector/Selector_Selector.cpp | 6 +- 8 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 src/ModelAPI/Test/TestGeomNamingPlacement.py diff --git a/src/FeaturesPlugin/Test/Test2724.py b/src/FeaturesPlugin/Test/Test2724.py index 98272e6d0..16cd2c330 100644 --- a/src/FeaturesPlugin/Test/Test2724.py +++ b/src/FeaturesPlugin/Test/Test2724.py @@ -63,5 +63,5 @@ Box_1 = model.addBox(Part_1_doc, 10, 10, 10) Placement_1 = model.addPlacement(Part_1_doc, [model.selection("SOLID", (-30.00000000000001, -10, -10))], model.selection("FACE", (5, 10, 5)), model.selection("FACE", (-30, 40, -10)), True, True) Common_1 = model.addCommon(Part_1_doc, [model.selection("SOLID", (-30.00000000000001, -210, -10)), model.selection("SOLID", (18, -293.9999999999999, -9.999999999999998))]) model.do() -assert(model.checkPythonDump(True)) +assert(model.checkPythonDump(model.ModelHighAPI.CHECK_WEAK)) model.end() diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 7abe5fa37..4b9b6e97f 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -911,13 +911,14 @@ void Model_AttributeSelection::selectSubShape( } } - Selector_Selector aSelector(aDoc->generalLabel()); + Selector_Selector aSelector(selectionLabel()); if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { aSelector.setBaseDocument(std::dynamic_pointer_cast (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); } myRestoreDocument = aDoc; - TDF_Label aContextLabel = aSelector.restoreByName(aSubShapeName, aShapeType, this); + TDF_Label aContextLabel = aSelector.restoreByName( + aSubShapeName, aShapeType, this, myIsGeometricalSelection); myRestoreDocument.reset(); if (!aContextLabel.IsNull()) { ResultPtr aContext = aDoc->resultByLab(aContextLabel); // any label for document access @@ -929,14 +930,26 @@ void Model_AttributeSelection::selectSubShape( aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelectorShape)); // make the context result the latest existing aContext = newestContext(aContext, aShapeToBeSelected); - if (aCenterType != NOT_CENTER) { - if (!aShapeToBeSelected->isEdge()) - continue; - std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected)); - setValueCenter(aContext, aSelectedEdge, aCenterType); + if (myIsGeometricalSelection) { // store the currently generated name + selectionLabel().ForgetAllAttributes(true); + bool aToUnblock = false; + aToUnblock = !owner()->data()->blockSendAttributeUpdated(true); + myRef.setValue(aContext); + aSelector.store(); + owner()->data()->sendAttributeUpdated(this); + if (aToUnblock) + owner()->data()->blockSendAttributeUpdated(false); + return; + } else { // re-select by context and value + if (aCenterType != NOT_CENTER) { + if (!aShapeToBeSelected->isEdge()) + continue; + std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected)); + setValueCenter(aContext, aSelectedEdge, aCenterType); + } + else + setValue(aContext, aShapeToBeSelected); } - else - setValue(aContext, aShapeToBeSelected); return; } } diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 0f513a9ca..96ad5bed3 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -224,4 +224,5 @@ ADD_UNIT_TESTS(TestConstants.py TestWeakNaming2446.py TestWeakNaming2452.py Test2685.py + TestGeomNamingPlacement.py ) diff --git a/src/ModelAPI/Test/Test2685.py b/src/ModelAPI/Test/Test2685.py index a86173946..f851694d7 100644 --- a/src/ModelAPI/Test/Test2685.py +++ b/src/ModelAPI/Test/Test2685.py @@ -63,4 +63,4 @@ SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_5.result()) SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_5.result(), 25) model.end() -assert(model.checkPythonDump(True)) +assert(model.checkPythonDump(model.ModelHighAPI.CHECK_WEAK)) diff --git a/src/ModelAPI/Test/TestGeomNamingPlacement.py b/src/ModelAPI/Test/TestGeomNamingPlacement.py new file mode 100644 index 000000000..254bf50ad --- /dev/null +++ b/src/ModelAPI/Test/TestGeomNamingPlacement.py @@ -0,0 +1,89 @@ +## 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 +## + +# -*- coding: utf-8 -*- + +from SketchAPI import * + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +param = model.addParameter(Part_1_doc, "p", "60") +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ")) +SketchLine_1 = Sketch_1.addLine(30, 30, -20, 30) +SketchLine_2 = Sketch_1.addLine(-20, 30, -20, -20) +SketchLine_3 = Sketch_1.addLine(-20, -20, 30, -20) +SketchLine_4 = Sketch_1.addLine(30, -20, 30, 30) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint()) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result()) +SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result()) +SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result()) +SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_1.startPoint(), SketchLine_2.startPoint(), 50) +SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.endPoint(), SketchLine_3.endPoint(), 50) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintDistanceHorizontal_2 = Sketch_1.setHorizontalDistance(SketchLine_2.startPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20) +SketchConstraintDistanceVertical_2 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 10, 0) +Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face")) +SketchLine_5 = Sketch_2.addLine(19.58333333333334, 17.27351642784226, -0.4166666666666646, 17.27351642784226) +SketchLine_6 = Sketch_2.addLine(-0.4166666666666646, 17.27351642784226, -0.4166666666794808, -42.72648357216971) +SketchLine_7 = Sketch_2.addLine(-0.4166666666794808, -42.72648357216971, 19.58333333332052, -42.72648357216971) +SketchLine_8 = Sketch_2.addLine(19.58333333332052, -42.72648357216971, 19.58333333333334, 17.27351642784226) +SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_8.endPoint(), SketchLine_5.startPoint()) +SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint()) +SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint()) +SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint()) +SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_5.result()) +SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_6.result()) +SketchConstraintHorizontal_4 = Sketch_2.setHorizontal(SketchLine_7.result()) +SketchConstraintVertical_4 = Sketch_2.setVertical(SketchLine_8.result()) +SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_2][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3][Extrusion_1_1/To_Face]"), False) +SketchPoint_2 = SketchProjection_2.createdFeature() +SketchConstraintDistance_1 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_7.startPoint(), 30, True) +SketchProjection_3 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1/To_Face]"), False) +SketchPoint_3 = SketchProjection_3.createdFeature() +SketchConstraintDistance_2 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_3).coordinates(), SketchLine_7.endPoint(), 25, True) +SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_7.result(), 20) +SketchConstraintLength_2 = Sketch_2.setLength(SketchLine_8.result(), "p") +model.do() +Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_5r-SketchLine_6f-SketchLine_7f-SketchLine_8f")], model.selection(), -5, -2) +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], [model.selection("SOLID", "Extrusion_2_1")]) +Box_1 = model.addBox(Part_1_doc, 50, 50, 30) +Placement_1 = model.addPlacement(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Cut_1_1/Modified_Face&Extrusion_1_1/To_Face"), False, True) +model.do() +# change parameter to split extrusion top face to two +param.setValue(100) +model.end() + +# check that placement is valid +from ModelAPI import * +aFactory = ModelAPI_Session.get().validators() +assert(aFactory.validate(Placement_1.feature())) + +assert(model.checkPythonDump(model.ModelHighAPI.CHECK_NAMING)) diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.cpp b/src/ModelHighAPI/ModelHighAPI_Tools.cpp index cf9fcc35a..a8a2ffcf3 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Tools.cpp @@ -377,7 +377,7 @@ std::string strByValueType(const ModelAPI_AttributeTables::ValueType theType) return ""; // bad case } -/// stores the features information, recoursively stores sub-documetns features +/// stores the features information, recursively stores sub-documents features std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc, std::map >& theStore, const bool theCompare) // if false => store @@ -390,7 +390,7 @@ std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc, } } // store the model features information: iterate all features - int anObjectsCount = 0; // stores the number of compared features for this document to compate + int anObjectsCount = 0; // stores the number of compared features for this document to compare std::set aProcessed; // processed features names (that are in the current document) // process all objects (features and folders) @@ -422,7 +422,7 @@ std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc, ModelAPI_Tools::allResults(aFeature, allResults); std::list::iterator aRes = allResults.begin(); for(; aRes != allResults.end(); aRes++) { - // recoursively store features of sub-documents + // recursively store features of sub-documents if ((*aRes)->groupName() == ModelAPI_ResultPart::group()) { DocumentPtr aDoc = std::dynamic_pointer_cast(*aRes)->partDoc(); if (aDoc.get()) { @@ -511,7 +511,7 @@ static bool checkDump(SessionPtr theSession, return true; } -bool checkPythonDump(const bool theWeakNameCheck) +bool checkPythonDump(const checkDumpType theCheckType) { static const std::string anErrorByNaming("checkPythonDump by naming"); static const std::string anErrorByGeometry("checkPythonDump by geometry"); @@ -522,14 +522,17 @@ bool checkPythonDump(const bool theWeakNameCheck) static char aFileForWeakDump[] = "./check_dump_weak.py"; SessionPtr aSession = ModelAPI_Session::get(); - if (!theWeakNameCheck) { + if (theCheckType & CHECK_NAMING) { // dump with the selection by names if (!dumpToPython(aSession, aFileForNamingDump, "topological_naming", anErrorByNaming)) return false; + } + if (theCheckType & CHECK_GEOMETRICAL) { // dump with the selection by geometry if (!dumpToPython(aSession, aFileForGeometryDump, "geometric_selection", anErrorByGeometry)) return false; - } else { + } + if (theCheckType & CHECK_WEAK) { // dump with the selection by weak naming if (!dumpToPython(aSession, aFileForWeakDump, "weak_naming", anErrorByWeak)) return false; @@ -546,13 +549,16 @@ bool checkPythonDump(const bool theWeakNameCheck) } bool isOk; - if (!theWeakNameCheck) { + if (theCheckType & CHECK_NAMING) { // check dump with the selection by names isOk = checkDump(aSession, aFileForNamingDump, aStore, anErrorByNaming); + } + if (theCheckType & CHECK_GEOMETRICAL) { // check dump with the selection by geometry isOk = isOk && checkDump(aSession, aFileForGeometryDump, aStore, anErrorByGeometry); - } else { - isOk = checkDump(aSession, aFileForWeakDump, aStore, anErrorByWeak); + } + if (theCheckType & CHECK_WEAK) { + isOk = isOk && checkDump(aSession, aFileForWeakDump, aStore, anErrorByWeak); } return isOk; diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.h b/src/ModelHighAPI/ModelHighAPI_Tools.h index a3f5293bf..8da24a0e5 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.h +++ b/src/ModelHighAPI/ModelHighAPI_Tools.h @@ -168,11 +168,19 @@ ModelAPI_AttributeTables::ValueType valueTypeByStr(const std::string& theValueTy MODELHIGHAPI_EXPORT std::string strByValueType(const ModelAPI_AttributeTables::ValueType theType); +/// Enumeration to manage the check python dump modes. +enum checkDumpType { + CHECK_NAMING = 1, ///< check topological naming only + CHECK_GEOMETRICAL = 2, ///< check geometrical naming only + CHECK_NAMING_AND_GEOMETRICAL = 3, ///< default option, check topological and geometrical dumps + CHECK_WEAK = 4, ///< check weak naming only +}; + /// Performs the high level API dump, then closes all and executes the script: /// model must be recreated fully, with all attributes /// \returns true if check is well done MODELHIGHAPI_EXPORT -bool checkPythonDump(const bool theWeakNameCheck = false); +bool checkPythonDump(const checkDumpType theCheckType = CHECK_NAMING_AND_GEOMETRICAL); //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- diff --git a/src/Selector/Selector_Selector.cpp b/src/Selector/Selector_Selector.cpp index a184f6aad..b0cc3a1f5 100644 --- a/src/Selector/Selector_Selector.cpp +++ b/src/Selector/Selector_Selector.cpp @@ -197,7 +197,7 @@ static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theV /// Returns true if the given shapes are based on the same geometry static bool sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) { - if (!theShape1.IsNull() && theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType()) + if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType()) { if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces TopLoc_Location aLoc1, aLoc2; @@ -942,7 +942,7 @@ bool Selector_Selector::solve(const TopoDS_Shape& theContext) break; } case SELTYPE_MODIFICATION: { - if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index + if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index TopoDS_ListOfShape aCommon; Handle(TNaming_NamedShape) aNS; if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { @@ -959,7 +959,7 @@ bool Selector_Selector::solve(const TopoDS_Shape& theContext) findModificationResult(aFinalsCommon); if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape aResult = aFinalsCommon.First(); - } else if (aFinalsCommon.Extent() > 1 && myWeakIndex) { + } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) { Selector_NExplode aNExp(aFinalsCommon); aResult = aNExp.shape(myWeakIndex); } else if (aFinalsCommon.Extent() > 1 && myGeometricalNaming) {// if same geometry - compound -- 2.39.2