From bad8dbf3aac92f2f845f4a4d397a06be7458a60b Mon Sep 17 00:00:00 2001 From: mpv Date: Mon, 19 Oct 2015 15:42:47 +0300 Subject: [PATCH] Fix and unit test for the issue #1064 --- .../ConstructionPlugin_Plane.cpp | 42 ++++--- src/Model/Model_AttributeSelection.cpp | 22 +++- src/Model/Model_AttributeSelectionList.cpp | 6 +- src/Model/Model_AttributeSelectionList.h | 4 +- src/Model/Model_Objects.cpp | 36 +++++- src/Model/Model_ResultPart.cpp | 27 ++++- src/Model/Model_ResultPart.h | 6 +- src/ModelAPI/CMakeLists.txt | 3 +- .../ModelAPI_AttributeSelectionList.h | 4 +- src/ModelAPI/ModelAPI_ResultPart.h | 7 +- src/ModelAPI/Test/Test1064.py | 104 ++++++++++++++++++ 11 files changed, 225 insertions(+), 36 deletions(-) create mode 100644 src/ModelAPI/Test/Test1064.py diff --git a/src/ConstructionPlugin/ConstructionPlugin_Plane.cpp b/src/ConstructionPlugin/ConstructionPlugin_Plane.cpp index adcd4c122..07a223b44 100644 --- a/src/ConstructionPlugin/ConstructionPlugin_Plane.cpp +++ b/src/ConstructionPlugin/ConstructionPlugin_Plane.cpp @@ -113,24 +113,32 @@ std::shared_ptr ConstructionPlugin_Plane::createPlaneByFaceAndDi double aXmin, aYmin, Zmin, aXmax, aYmax, Zmax; aShape->computeSize(aXmin, aYmin, Zmin, aXmax, aYmax, Zmax); - std::shared_ptr aPnt1 = std::shared_ptr( - new GeomAPI_Pnt(aXmin, aYmin, Zmin)); - std::shared_ptr aPnt2 = std::shared_ptr( - new GeomAPI_Pnt(aXmax, aYmax, Zmax)); - - std::shared_ptr aPnt2d1 = aPnt1->to2D(aNewPln); - std::shared_ptr aPnt2d2 = aPnt2->to2D(aNewPln); - - double aWidth = aPnt2d2->x() - aPnt2d1->x(); - double aHeight = aPnt2d2->y() - aPnt2d1->y(); - double aWgap = aWidth * 0.1; - double aHgap = aHeight * 0.1; - + // use all 8 points of the bounding box to find the 2D bounds + bool isFirst = true; + double aMinX2d, aMaxX2d, aMinY2d, aMaxY2d; + for(int aXIsMin = 0; aXIsMin < 2; aXIsMin++) { + for(int aYIsMin = 0; aYIsMin < 2; aYIsMin++) { + for(int aZIsMin = 0; aZIsMin < 2; aZIsMin++) { + std::shared_ptr aPnt = std::shared_ptr(new GeomAPI_Pnt( + aXIsMin ? aXmin : aXmax, aYIsMin ? aYmin : aYmax, aZIsMin ? Zmin : Zmax)); + std::shared_ptr aPnt2d = aPnt->to2D(aNewPln); + if (isFirst || aPnt2d->x() < aMinX2d) + aMinX2d = aPnt2d->x(); + if (isFirst || aPnt2d->y() < aMinY2d) + aMinY2d = aPnt2d->y(); + if (isFirst || aPnt2d->x() > aMaxX2d) + aMaxX2d = aPnt2d->x(); + if (isFirst || aPnt2d->y() > aMaxY2d) + aMaxY2d = aPnt2d->y(); + if (isFirst) + isFirst = !isFirst; + } + } + } + double aWgap = (aMaxX2d - aMinX2d) * 0.1; + double aHgap = (aMaxY2d - aMinY2d) * 0.1; aPlane = GeomAlgoAPI_FaceBuilder::planarFace(aNewPln, - aPnt2d1->x() - aWgap, - aPnt2d1->y() - aHgap, - aWidth + 2 * aWgap, - aHeight + 2 * aHgap); + aMinX2d - aWgap, aMinY2d - aHgap, aMaxX2d - aMinX2d + 2. * aWgap, aMaxY2d - aMinY2d + 2. * aHgap); } } return aPlane; diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 7bc7217dc..232ff61b5 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -200,7 +200,6 @@ std::shared_ptr Model_AttributeSelection::value() return aResult; // empty result } if (aSelLab.IsAttribute(kPART_REF_ID)) { - /* TODO: implement used text here ResultPartPtr aPart = std::dynamic_pointer_cast(context()); if (!aPart.get() || !aPart->isActivated()) return std::shared_ptr(); // postponed naming needed @@ -208,11 +207,12 @@ std::shared_ptr Model_AttributeSelection::value() if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) { return aPart->selectionValue(anIndex->Get()); } + /* Handle(TDataStd_Name) aName; if (!selectionLabel().FindAttribute(TDataStd_Name::GetID(), aName)) { return std::shared_ptr(); // something is wrong } - return aPart->shapeInPart(TCollection_AsciiString(aName).ToCString()); + return aPart->shapeInPart(TCollection_AsciiString(aName->Get()).ToCString()); */ } @@ -873,6 +873,24 @@ void Model_AttributeSelection::selectSubShape( { if(theSubShapeName.empty() || theType.empty()) return; + // check this is Part-name: 2 delimiters in the name + std::size_t aPartEnd = theSubShapeName.find('/'); + if (aPartEnd != string::npos && aPartEnd != theSubShapeName.rfind('/')) { + std::string aPartName = theSubShapeName.substr(0, aPartEnd); + ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName); + if (aFound.get()) { // found such part, so asking it for the name + ResultPartPtr aPart = std::dynamic_pointer_cast(aFound); + string aNameInPart = theSubShapeName.substr(aPartEnd + 1); + int anIndex; + std::shared_ptr aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex); + if (aSelected.get()) { + setValue(aPart, aSelected); + TDataStd_Integer::Set(selectionLabel(), anIndex); + return; + } + } + } + Model_SelectionNaming aSelNaming(selectionLabel()); std::shared_ptr aDoc = std::dynamic_pointer_cast(owner()->document()); diff --git a/src/Model/Model_AttributeSelectionList.cpp b/src/Model/Model_AttributeSelectionList.cpp index 07e62e2bc..f762ebaf3 100644 --- a/src/Model/Model_AttributeSelectionList.cpp +++ b/src/Model/Model_AttributeSelectionList.cpp @@ -50,7 +50,8 @@ void Model_AttributeSelectionList::append( owner()->data()->sendAttributeUpdated(this); } -void Model_AttributeSelectionList::append(std::string theNamingName) +void Model_AttributeSelectionList::append( + const std::string theNamingName, const std::string& theType) { int aNewTag = mySize->Get() + 1; TDF_Label aNewLab = mySize->Label().FindChild(aNewTag); @@ -60,8 +61,9 @@ void Model_AttributeSelectionList::append(std::string theNamingName) if (owner()) { aNewAttr->setObject(owner()); } + aNewAttr->setID(id()); mySize->Set(aNewTag); - aNewAttr->selectSubShape(selectionType(), theNamingName); + aNewAttr->selectSubShape(theType.empty() ? selectionType() : theType, theNamingName); owner()->data()->sendAttributeUpdated(this); } diff --git a/src/Model/Model_AttributeSelectionList.h b/src/Model/Model_AttributeSelectionList.h index 55dad109f..6721dd8ad 100644 --- a/src/Model/Model_AttributeSelectionList.h +++ b/src/Model/Model_AttributeSelectionList.h @@ -36,8 +36,8 @@ public: const bool theTemporarily = false); /// Adds the new reference to the end of the list by the naming name of the selected shape - /// The type of shape is taken from the current selection type - MODEL_EXPORT virtual void append(std::string theNamingName); + /// The type of shape is taken from the current selection type if the given is empty + MODEL_EXPORT virtual void append(const std::string theNamingName, const std::string& theType=""); /// Removes the last element in the list MODEL_EXPORT virtual void removeLast(); diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 601e0c1b7..0d1021820 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -445,11 +445,37 @@ std::shared_ptr Model_Objects::objectByName( const std::string& theGroupID, const std::string& theName) { createHistory(theGroupID); - std::list > allObjs = allFeatures(); - std::list >::iterator anObjIter = allObjs.begin(); - for(; anObjIter != allObjs.end(); anObjIter++) { - if ((*anObjIter)->data()->name() == theName) - return *anObjIter; + if (theGroupID == ModelAPI_Feature::group()) { // searching among features (in history or not) + std::list > allObjs = allFeatures(); + std::list >::iterator anObjIter = allObjs.begin(); + for(; anObjIter != allObjs.end(); anObjIter++) { + if ((*anObjIter)->data()->name() == theName) + return *anObjIter; + } + } else { // searching among results (concealed or not) + std::list > allObjs = allFeatures(); + std::list >::iterator anObjIter = allObjs.begin(); + for(; anObjIter != allObjs.end(); anObjIter++) { + const std::list >& aResults = (*anObjIter)->results(); + std::list >::const_iterator aRIter = aResults.cbegin(); + for (; aRIter != aResults.cend(); aRIter++) { + if (aRIter->get() && (*aRIter)->groupName() == theGroupID) { + if ((*aRIter)->data()->name() == theName) + return *aRIter; + ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast(*aRIter); + if (aCompRes.get()) { + int aNumSubs = aCompRes->numberOfSubs(); + for(int a = 0; a < aNumSubs; a++) { + ResultPtr aSub = aCompRes->subResult(a); + if (aSub.get() && aSub->groupName() == theGroupID) { + if (aSub->data()->name() == theName) + return aSub; + } + } + } + } + } + } } // not found return ObjectPtr(); diff --git a/src/Model/Model_ResultPart.cpp b/src/Model/Model_ResultPart.cpp index bb12b1075..124fecd49 100644 --- a/src/Model/Model_ResultPart.cpp +++ b/src/Model/Model_ResultPart.cpp @@ -285,12 +285,33 @@ bool Model_ResultPart::updateInPart(const int theIndex) return false; // something is wrong } -std::shared_ptr Model_ResultPart::shapeInPart(const std::string& theName) +std::shared_ptr Model_ResultPart::shapeInPart( + const std::string& theName, const std::string& theType, int& theIndex) { - /// TODO: not implemented yet - return std::shared_ptr(); + theIndex = 0; // not found yet + std::shared_ptr aResult; + std::shared_ptr aDoc = std::dynamic_pointer_cast(partDoc()); + if (!aDoc.get()) // the part document is not presented for the moment + return aResult; + + AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature(); + aSelAttr->append(theName, theType); + theIndex = aSelAttr->size(); + aResult = aSelAttr->value(theIndex - 1)->value(); + return aResult; } +std::shared_ptr Model_ResultPart::selectionValue(const int theIndex) +{ + std::shared_ptr aResult; + std::shared_ptr aDoc = std::dynamic_pointer_cast(partDoc()); + if (!aDoc.get()) // the part document is not presented for the moment + return aResult; + + AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature(); + aResult = aSelAttr->value(theIndex - 1)->value(); + return aResult; +} void Model_ResultPart::colorConfigInfo(std::string& theSection, std::string& theName, std::string& theDefault) diff --git a/src/Model/Model_ResultPart.h b/src/Model/Model_ResultPart.h index f53ac5e85..220e1b408 100644 --- a/src/Model/Model_ResultPart.h +++ b/src/Model/Model_ResultPart.h @@ -61,7 +61,8 @@ class Model_ResultPart : public ModelAPI_ResultPart /// Updates the selection inside of the part by the selection index MODEL_EXPORT virtual bool updateInPart(const int theIndex); /// Returns the shape by the name in the part - MODEL_EXPORT virtual std::shared_ptr shapeInPart(const std::string& theName); + MODEL_EXPORT virtual std::shared_ptr shapeInPart( + const std::string& theName, const std::string& theType, int& theIndex); /// Updates the shape-result of the part (called on Part feature execution) MODEL_EXPORT virtual void updateShape(); /// Applies the additional transformation of the part @@ -72,6 +73,9 @@ class Model_ResultPart : public ModelAPI_ResultPart MODEL_EXPORT virtual void colorConfigInfo(std::string& theSection, std::string& theName, std::string& theDefault); + /// Returns the shape selected in the selection index + MODEL_EXPORT virtual std::shared_ptr selectionValue(const int theIndex); + protected: /// makes a result on a temporary feature (an action) Model_ResultPart(); diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 70d61ff25..15686873f 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -124,4 +124,5 @@ INSTALL(FILES ${SWIG_SCRIPTS} DESTINATION swig) ADD_UNIT_TESTS(TestConstants.py TestUndoRedo.py - TestDocument.py) + TestDocument.py + Test1064.py) diff --git a/src/ModelAPI/ModelAPI_AttributeSelectionList.h b/src/ModelAPI/ModelAPI_AttributeSelectionList.h index b12aa518d..e2cad1e1f 100644 --- a/src/ModelAPI/ModelAPI_AttributeSelectionList.h +++ b/src/ModelAPI/ModelAPI_AttributeSelectionList.h @@ -29,8 +29,8 @@ class ModelAPI_AttributeSelectionList : public ModelAPI_Attribute const bool theTemporarily = false) = 0; /// Adds the new reference to the end of the list by the naming name of the selected shape - /// The type of shape is taken from the current selection type - virtual void append(std::string theNamingName) = 0; + /// The type of shape is taken from the current selection type if the given is empty + virtual void append(const std::string theNamingName, const std::string& theType = "") = 0; /// Removes the last element in the list virtual void removeLast() = 0; diff --git a/src/ModelAPI/ModelAPI_ResultPart.h b/src/ModelAPI/ModelAPI_ResultPart.h index b06c3f2ac..1d66dba18 100644 --- a/src/ModelAPI/ModelAPI_ResultPart.h +++ b/src/ModelAPI/ModelAPI_ResultPart.h @@ -73,7 +73,12 @@ class ModelAPI_ResultPart : public ModelAPI_Result const std::shared_ptr& theTransformation) = 0; /// Returns the shape by the name in the part - virtual std::shared_ptr shapeInPart(const std::string& theName) = 0; + virtual std::shared_ptr shapeInPart( + const std::string& theName, const std::string& theType, int& theIndex) = 0; + + /// Returns the shape selected in the selection index + virtual std::shared_ptr selectionValue(const int theIndex) = 0; + /// Updates the shape-result of the part (called on Part feature execution) virtual void updateShape() = 0; }; diff --git a/src/ModelAPI/Test/Test1064.py b/src/ModelAPI/Test/Test1064.py new file mode 100644 index 000000000..e4fb9291c --- /dev/null +++ b/src/ModelAPI/Test/Test1064.py @@ -0,0 +1,104 @@ +""" + Test1064.py + Unit test for testing the Part sub-shapes naming, described in the issue 1064 + +""" +#========================================================================= +# Initialization of the test +#========================================================================= +from ModelAPI import * +from GeomDataAPI import * +from GeomAlgoAPI import * + +__updated__ = "2015-10-16" + +aSession = ModelAPI_Session.get() + +#========================================================================= +# Create a sketch triangle in PartSet +#========================================================================= +aPartSet = aSession.moduleDocument() +aSession.startOperation() +aSketchFeature = featureToCompositeFeature(aPartSet.addFeature("Sketch")) +origin = geomDataAPI_Point(aSketchFeature.attribute("Origin")) +origin.setValue(0, 0, 0) +dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX")) +dirx.setValue(1, 0, 0) +norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm")) +norm.setValue(0, 0, 1) +# Create lines +aLine1 = aSketchFeature.addFeature("SketchLine") +geomDataAPI_Point2D(aLine1.attribute("StartPoint")).setValue(0, 0) +geomDataAPI_Point2D(aLine1.attribute("EndPoint")).setValue(200, 0) +aLine2 = aSketchFeature.addFeature("SketchLine") +geomDataAPI_Point2D(aLine2.attribute("StartPoint")).setValue(200, 0) +geomDataAPI_Point2D(aLine2.attribute("EndPoint")).setValue(0, 200) +aLine3 = aSketchFeature.addFeature("SketchLine") +geomDataAPI_Point2D(aLine3.attribute("StartPoint")).setValue(0, 200) +geomDataAPI_Point2D(aLine3.attribute("EndPoint")).setValue(0, 0) +aSession.finishOperation() + +#========================================================================= +# Create a part +#========================================================================= +aSession.startOperation() +aPartFeature = aPartSet.addFeature("Part") +aSession.finishOperation() +assert (len(aPartFeature.results()) == 1) +aPart = aSession.activeDocument() + +#========================================================================= +# Make extrusion on triangle +#========================================================================= +aSketchResult = aSketchFeature.firstResult() +aSketchEdges = modelAPI_ResultConstruction(aSketchResult).shape() +aSketchFaces = ShapeList() +GeomAlgoAPI_SketchBuilder.createFaces( + origin.pnt(), dirx.dir(), norm.dir(), aSketchEdges, aSketchFaces) +aSession.startOperation() +anExtrusionFt = aPart.addFeature("Extrusion") +anExtrusionFt.selectionList("base").append(aSketchResult, aSketchFaces[0]) +anExtrusionFt.string("CreationMethod").setValue("BySizes") +anExtrusionFt.real("to_size").setValue(50) +anExtrusionFt.real("from_size").setValue(0) +aSession.finishOperation() + + +#========================================================================= +# Make a plane in PartSet on lateral face of the Extrusion +#========================================================================= +aSession.startOperation() +aSession.setActiveDocument(aPartSet) +aPlane = aPartSet.addFeature("Plane") +aPlane.string("CreationMethod").setValue("PlaneByFaceAndDistance") +aPlane.real("distance").setValue(0) +aPlane.selection("planeFace").selectSubShape("face", "Part_1/Extrusion_1_1/LateralFace_3") +aSession.finishOperation() + +#========================================================================= +# Update the sketch edges in order to update the plane on the lateral face automatically +#========================================================================= +aSession.startOperation() +geomDataAPI_Point2D(aLine1.attribute("EndPoint")).setValue(400, 0) +geomDataAPI_Point2D(aLine2.attribute("StartPoint")).setValue(400, 0) +aSession.finishOperation() + +#========================================================================= +# Check that the plane is also updated +#========================================================================= + +assert(len(aPlane.results()) > 0) +aShape = aPlane.firstResult().shape() +aFace = GeomAPI_Face(aShape) +assert(aFace.isPlanar()) +aPln = aFace.getPlane() +# Must be 0.4472135955, 0.894427191, 0.0 +assert(aPln.direction().x() > 0.44) +assert(aPln.direction().x() < 0.45) +assert(aPln.direction().y() > 0.89) +assert(aPln.direction().y() < 0.90) +assert(aPln.direction().z() == 0.) + +#========================================================================= +# End of test +#========================================================================= -- 2.39.2