From 9d0074305685b0a8b14a446ab7405308fc82006b Mon Sep 17 00:00:00 2001 From: mpv Date: Fri, 17 Mar 2017 10:19:27 +0300 Subject: [PATCH] Issue #1995, issue #1996, issue #1997 fixes. Change the way of construction naming structures are stored to keep correctly the parametrical naming update in cases same construction sub-elements are selected in several places. For that store the selection naming structures in one place of the document, not in every selection attributes storage places. --- src/GeomAPI/GeomAPI_Trsf.cpp | 1 - .../GeomValidators_ShapeType.cpp | 1 + src/Model/Model_AttributeSelection.cpp | 504 ++---------------- src/Model/Model_AttributeSelection.h | 4 - src/Model/Model_Data.h | 1 + src/Model/Model_Document.cpp | 7 + src/Model/Model_Document.h | 4 + src/Model/Model_ResultConstruction.cpp | 465 ++++++++++++++++ src/Model/Model_ResultConstruction.h | 33 ++ src/Model/Model_SelectionNaming.cpp | 1 - src/ModelAPI/CMakeLists.txt | 1 + src/ModelAPI/Test/Test1995.py | 38 ++ src/SketchPlugin/SketchPlugin_Sketch.cpp | 7 +- 13 files changed, 603 insertions(+), 464 deletions(-) create mode 100644 src/ModelAPI/Test/Test1995.py diff --git a/src/GeomAPI/GeomAPI_Trsf.cpp b/src/GeomAPI/GeomAPI_Trsf.cpp index 7246364f1..f0df9471f 100644 --- a/src/GeomAPI/GeomAPI_Trsf.cpp +++ b/src/GeomAPI/GeomAPI_Trsf.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #define MY_TRSF implPtr() diff --git a/src/GeomValidators/GeomValidators_ShapeType.cpp b/src/GeomValidators/GeomValidators_ShapeType.cpp index 6c0077c6a..6371c1a46 100755 --- a/src/GeomValidators/GeomValidators_ShapeType.cpp +++ b/src/GeomValidators/GeomValidators_ShapeType.cpp @@ -90,6 +90,7 @@ bool GeomValidators_ShapeType::isValid(const AttributePtr& theAttribute, for (; anIt != aLast; anIt++) { if (!aTypes.empty()) aTypes += ", "; + aTypes += *anIt; } theError = "It does not contain element with acceptable shape type. " "The type should be one of the next: %1"; diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 83c61b4e3..7af146794 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -12,55 +12,33 @@ #include "Model_SelectionNaming.h" #include #include +#include #include #include #include #include #include #include -#include #include -#include #include #include #include #include #include -#include #include #include -#include -#include -#include -#include #include #include #include -#include -#include -#include #include -#include #include -#include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include #include -#include //#define DEB_NAMING 1 #ifdef DEB_NAMING @@ -71,8 +49,6 @@ static const int kSTART_VERTEX_DELTA = 1000000; // identifier that there is simple reference: selection equals to context Standard_GUID kSIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb29"); -// simple reference in the construction -Standard_GUID kCONSTUCTION_SIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb28"); // reference to Part sub-object Standard_GUID kPART_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb27"); // selection is invalid after recomputation @@ -110,7 +86,6 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, // do noth use naming if selected shape is result shape itself, but not sub-shape TDF_Label aSelLab = selectionLabel(); aSelLab.ForgetAttribute(kSIMPLE_REF_ID); - aSelLab.ForgetAttribute(kCONSTUCTION_SIMPLE_REF_ID); aSelLab.ForgetAttribute(kINVALID_SELECTION); bool isDegeneratedEdge = false; @@ -138,45 +113,19 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, selectBody(theContext, theSubShape); } } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) { - if (!theSubShape.get()) { - // to sub, so the whole result is selected - aSelLab.ForgetAllAttributes(true); - TDataStd_UAttribute::Set(aSelLab, kCONSTUCTION_SIMPLE_REF_ID); - ResultConstructionPtr aConstruction = - std::dynamic_pointer_cast(theContext); - if (aConstruction->isInfinite()) { - // For correct naming selection, put the shape into the naming structure. - // It seems sub-shapes are not needed: only this shape is (and can be ) selected. - TNaming_Builder aBuilder(aSelLab); - aBuilder.Generated(theContext->shape()->impl()); - std::shared_ptr aMyDoc = - std::dynamic_pointer_cast(owner()->document()); - //std::string aName = contextName(theContext); - // for selection in different document, add the document name - //aMyDoc->addNamingName(aSelLab, aName); - //TDataStd_Name::Set(aSelLab, aName.c_str()); - } else { // for sketch the naming is needed in DS - BRep_Builder aCompoundBuilder; - TopoDS_Compound aComp; - aCompoundBuilder.MakeCompound(aComp); - for(int a = 0; a < aConstruction->facesNum(); a++) { - TopoDS_Shape aFace = aConstruction->face(a)->impl(); - aCompoundBuilder.Add(aComp, aFace); - } - std::shared_ptr aShape(new GeomAPI_Shape); - aShape->setImpl(new TopoDS_Shape(aComp)); - selectConstruction(theContext, aShape); - } - } else { - selectConstruction(theContext, theSubShape); - } + aSelLab.ForgetAllAttributes(true); // to remove old selection data + std::shared_ptr aConstruction = + std::dynamic_pointer_cast(theContext); + std::shared_ptr aSubShape; + if (theSubShape.get() && !theContext->shape()->isEqual(theSubShape)) + aSubShape = theSubShape; // the whole context + int anIndex = aConstruction->select(theSubShape, owner()->document()); + TDataStd_Integer::Set(aSelLab, anIndex); } else if (theContext->groupName() == ModelAPI_ResultPart::group()) { aSelLab.ForgetAllAttributes(true); TDataStd_UAttribute::Set(aSelLab, kPART_REF_ID); selectPart(theContext, theSubShape); } - //the attribute initialized state should be changed by sendAttributeUpdated only - //myIsInitialized = true; owner()->data()->sendAttributeUpdated(this); } @@ -213,21 +162,17 @@ std::shared_ptr Model_AttributeSelection::value() return aResult; // empty result return aContext->shape(); } - if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { - // it is just reference to construction, nothing is in value - return aResult; // empty result - } if (aSelLab.IsAttribute(kPART_REF_ID)) { ResultPartPtr aPart = std::dynamic_pointer_cast(context()); if (!aPart.get() || !aPart->isActivated()) return std::shared_ptr(); // postponed naming needed Handle(TDataStd_Integer) anIndex; - if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { if (anIndex->Get()) { // special selection attribute was created, use it return aPart->selectionValue(anIndex->Get()); } else { // face with name is already in the data model, so try to take it by name Handle(TDataStd_Name) aName; - if (selectionLabel().FindAttribute(TDataStd_Name::GetID(), aName)) { + if (aSelLab.FindAttribute(TDataStd_Name::GetID(), aName)) { std::string aSubShapeName(TCollection_AsciiString(aName->Get()).ToCString()); std::size_t aPartEnd = aSubShapeName.find('/'); if (aPartEnd != std::string::npos && aPartEnd != aSubShapeName.rfind('/')) { @@ -242,15 +187,20 @@ std::shared_ptr Model_AttributeSelection::value() } Handle(TNaming_NamedShape) aSelection; - if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { + if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { TopoDS_Shape aSelShape = aSelection->Get(); aResult = std::shared_ptr(new GeomAPI_Shape); aResult->setImpl(new TopoDS_Shape(aSelShape)); } else { // for simple construction element: just shape of this construction element - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(context()); + std::shared_ptr aConstr = + std::dynamic_pointer_cast(context()); if (aConstr) { - return aConstr->shape(); + Handle(TDataStd_Integer) anIndex; + if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + if (anIndex->Get() == 0) // it is just reference to construction, nothing is in value + return aResult; + return aConstr->shape(anIndex->Get(), owner()->document()); + } } } } @@ -272,19 +222,19 @@ bool Model_AttributeSelection::isInitialized() ResultPtr aContext = context(); return aContext.get() != NULL; } - if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { - // it is just reference to construction, nothing is in value - return true; - } - Handle(TNaming_NamedShape) aSelection; if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { return !aSelection->Get().IsNull(); } else { // for simple construction element: just shape of this construction element - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(context()); + std::shared_ptr aConstr = + std::dynamic_pointer_cast(context()); if (aConstr.get()) { - return aConstr->shape().get() != NULL; + Handle(TDataStd_Integer) anIndex; + if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + if (anIndex->Get() == 0) // it is just reference to construction, nothing is in value + return true; + return aConstr->shape(anIndex->Get(), owner()->document()).get() != NULL; + } } } } @@ -375,7 +325,7 @@ TDF_LabelMap& Model_AttributeSelection::scope() if (isInScope && aFIter->get() && (*aFIter)->data()->isValid()) { TDF_Label aFeatureLab = std::dynamic_pointer_cast( (*aFIter)->data())->label().Father(); - TDF_ChildIDIterator aNSIter(aFeatureLab, TNaming_NamedShape::GetID(), 1); + TDF_ChildIDIterator aNSIter(aFeatureLab, TNaming_NamedShape::GetID(), true); for(; aNSIter.More(); aNSIter.Next()) { Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) { @@ -384,6 +334,16 @@ TDF_LabelMap& Model_AttributeSelection::scope() } } } + // also add all naming labels created for external constructions + std::shared_ptr aDoc = std::dynamic_pointer_cast(aMyDoc); + TDF_Label anExtDocLab = aDoc->extConstructionsLabel(); + TDF_ChildIDIterator aNSIter(anExtDocLab, TNaming_NamedShape::GetID(), true); + for(; aNSIter.More(); aNSIter.Next()) { + Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); + if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) { + myScope.Add(aNS->Label()); + } + } } return myScope; } @@ -434,32 +394,6 @@ bool Model_AttributeSelection::update() if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull()); } - if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { - // it is just reference to construction, not sub-shape - // if there is a sketch, the sketch-naming must be updated - ResultConstructionPtr aConstruction = - std::dynamic_pointer_cast(aContext); - if (!aConstruction->isInfinite()) { - BRep_Builder aCompoundBuilder; - TopoDS_Compound aComp; - aCompoundBuilder.MakeCompound(aComp); - for(int a = 0; a < aConstruction->facesNum(); a++) { - TopoDS_Shape aFace = aConstruction->face(a)->impl(); - aCompoundBuilder.Add(aComp, aFace); - } - std::shared_ptr aShape(new GeomAPI_Shape); - aShape->setImpl(new TopoDS_Shape(aComp)); - selectConstruction(aContext, aShape); - } else { - // For correct naming selection, put the shape into the naming structure. - // It seems sub-shapes are not needed: only this shape is (and can be ) selected. - TNaming_Builder aBuilder(aSelLab); - aBuilder.Generated(aContext->shape()->impl()); - std::shared_ptr aMyDoc = - std::dynamic_pointer_cast(owner()->document()); - } - return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull()); - } if (aSelLab.IsAttribute(kPART_REF_ID)) { // it is reference to the part object std::shared_ptr aNoSelection; @@ -500,162 +434,16 @@ bool Model_AttributeSelection::update() } if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { - // construction: identification by the results indexes, recompute faces and - // take the face that more close by the indexes - ResultConstructionPtr aConstructionContext = - std::dynamic_pointer_cast(aContext); - FeaturePtr aContextFeature = aContext->document()->feature(aContext); - // sketch sub-element - if (aConstructionContext && - std::dynamic_pointer_cast(aContextFeature).get()) - { - TDF_Label aLab = myRef.myRef->Label(); - // getting a type of selected shape - Handle(TDataStd_Integer) aTypeAttr; - if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) { - return setInvalidIfFalse(aSelLab, false); - } - TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get()); - // selected indexes will be needed in each "if" - Handle(TDataStd_IntPackedMap) aSubIds; - std::shared_ptr aNewSelected; - bool aNoIndexes = - !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0; - // for now working only with composite features - CompositeFeaturePtr aComposite = - std::dynamic_pointer_cast(aContextFeature); - if (!aComposite.get() || aComposite->numberOfSubs() == 0) { - return setInvalidIfFalse(aSelLab, false); - } - - if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) { - // compound is for the whole sketch selection - // If this is a wire with plane defined then it is a sketch-like object - if (!aConstructionContext->facesNum()) // no faces, update can not work correctly - return setInvalidIfFalse(aSelLab, false); - // if there is no edges indexes, any face can be used: take the first - std::shared_ptr aNewSelected; - if (aNoIndexes) { - aNewSelected = aConstructionContext->face(0); - } else { // searching for most looks-like initial face by the indexes - // prepare edges of the current result for the fast searching - // curves and orientations of edges - NCollection_DataMap allCurves; - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - int aSubID = aComposite->subFeatureId(a); - if (aSubIds->Contains(aSubID)) { - FeaturePtr aSub = aComposite->subFeature(a); - const std::list >& aResults = aSub->results(); - std::list >::const_iterator aRes; - for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(*aRes); - if (aConstr->shape() && aConstr->shape()->isEdge()) { - const TopoDS_Shape& aResShape = aConstr->shape()->impl(); - TopoDS_Edge anEdge = TopoDS::Edge(aResShape); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - // searching for orientation information - int anOrient = 0; - Handle(TDataStd_Integer) anInt; - if (aSelLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)){ - anOrient = anInt->Get(); - } - allCurves.Bind(aCurve, anOrient); - } - } - } - } - } - aNewSelected = Model_SelectionNaming::findAppropriateFace( - aContext, allCurves, aShapeType == TopAbs_WIRE); - } - if (aNewSelected) { // store this new selection - selectConstruction(aContext, aNewSelected); - setInvalidIfFalse(aSelLab, true); - owner()->data()->sendAttributeUpdated(this); - return true; - } else { - // if the selection is not found, put the empty shape: - // it's better to have disappeared shape, than the old, the lost one - TNaming_Builder anEmptyBuilder(selectionLabel()); - return setInvalidIfFalse(aSelLab, false); - } - } else if (aShapeType == TopAbs_EDGE) { - // just reselect the edge by the id - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - // if aSubIds take any, the first appropriate - if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) { - // found the appropriate feature - FeaturePtr aFeature = aComposite->subFeature(a); - std::list >::const_iterator aResIter = - aFeature->results().cbegin(); - for(;aResIter != aFeature->results().cend(); aResIter++) { - ResultConstructionPtr aRes = - std::dynamic_pointer_cast(*aResIter); - if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found! - selectConstruction(aContext, aRes->shape()); - setInvalidIfFalse(aSelLab, true); - owner()->data()->sendAttributeUpdated(this); - return true; - } - } - } - } - } else if (aShapeType == TopAbs_VERTEX) { - // just reselect the vertex by the id of edge - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - // if aSubIds take any, the first appropriate - int aFeatureID = aComposite->subFeatureId(a); - if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) || - aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) || - aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) { - // searching for deltas - int aVertexNum = 0; - if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1; - else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2; - // found the feature with appropriate edge - FeaturePtr aFeature = aComposite->subFeature(a); - std::list >::const_iterator aResIter = - aFeature->results().cbegin(); - for(;aResIter != aFeature->results().cend(); aResIter++) { - ResultConstructionPtr aRes = - std::dynamic_pointer_cast(*aResIter); - if (aRes && aRes->shape()) { - if (aRes->shape()->isVertex() && aVertexNum == 0) { // found! - selectConstruction(aContext, aRes->shape()); - setInvalidIfFalse(aSelLab, true); - owner()->data()->sendAttributeUpdated(this); - return true; - } else if (aRes->shape()->isEdge() && aVertexNum > 0) { - const TopoDS_Shape& anEdge = aRes->shape()->impl(); - int aVIndex = 1; - for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { - if (aVIndex == aVertexNum) { // found! - std::shared_ptr aVertex(new GeomAPI_Shape); - aVertex->setImpl(new TopoDS_Shape(aVExp.Current())); - selectConstruction(aContext, aVertex); - setInvalidIfFalse(aSelLab, true); - owner()->data()->sendAttributeUpdated(this); - return true; - } - aVIndex++; - } - } - } - } - } - } - } - } else { // simple construction element: the selected is that needed - selectConstruction(aContext, aContext->shape()); - setInvalidIfFalse(aSelLab, true); - owner()->data()->sendAttributeUpdated(this); - return true; + Handle(TDataStd_Integer) anIndex; + if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + std::shared_ptr aConstructionContext = + std::dynamic_pointer_cast(aContext); + bool aModified = true; + bool aValid = aConstructionContext->update(anIndex->Get(), owner()->document(), aModified); + setInvalidIfFalse(aSelLab, aValid); + if (aModified) + owner()->data()->sendAttributeUpdated(this); + return aValid; } } return setInvalidIfFalse(aSelLab, false); // unknown case @@ -762,200 +550,6 @@ void Model_AttributeSelection::selectBody( } } -/// registers the name of the shape in the label (theID == 0) of sub label (theID is a tag) -/// if theID is zero, -/// theOrientation is additional information about the positioning of edge relatively to face -/// it is stored in the integer attribute of the edge sub-label: -/// -1 is out, 1 is in, 0 is not needed -static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, - const int theID, const FeaturePtr& theContextFeature, std::shared_ptr theDoc, - std::map& theOrientations, - // name of sub-elements by ID to be exported instead of indexes - std::map& theSubNames, - Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)(), - const int theOrientation = 0) -{ - TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID); - if (theOrientation != 0) { // store the orientation of edge relatively to face if needed - TDataStd_Integer::Set(aLab, theOrientation); - } - TNaming_Builder aBuilder(aLab); - aBuilder.Generated(theShape); - std::stringstream aName; - // #1839 : do not store name of the feature in the tree, since this name could be changed - //aName<name(); - if (theShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction - //aName<<"/"; - if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face"; - else if (theShape.ShapeType() == TopAbs_WIRE) aName<<"Wire"; - else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge"; - else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex"; - - if (theRefs.IsNull()) { - aName<GetMap()); - for(; aRef.More(); aRef.Next()) { - aName<<"-"<addNamingName(aLab, aName.str()); - TDataStd_Name::Set(aLab, aName.str().c_str()); -} - -void Model_AttributeSelection::selectConstruction( - const ResultPtr& theContext, const std::shared_ptr& theSubShape) -{ - std::shared_ptr aMyDoc = - std::dynamic_pointer_cast(owner()->document()); - FeaturePtr aContextFeature = theContext->document()->feature(theContext); - CompositeFeaturePtr aComposite = - std::dynamic_pointer_cast(aContextFeature); - const TopoDS_Shape& aSubShape = theSubShape->impl(); - if (!aComposite || aComposite->numberOfSubs() == 0) { - // saving of context is enough: result construction contains exactly the needed shape - TNaming_Builder aBuilder(selectionLabel()); - aBuilder.Generated(aSubShape); - //std::string aName = contextName(theContext); - //aMyDoc->addNamingName(selectionLabel(), aName); - //TDataStd_Name::Set(selectionLabel(), aName.c_str()); - return; - } - std::shared_ptr aData = std::dynamic_pointer_cast(owner()->data()); - TDF_Label aLab = myRef.myRef->Label(); - // identify the results of sub-object of the composite by edges - // save type of the selected shape in integer attribute - TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType(); - TDataStd_Integer::Set(aLab, (int)aShapeType); - gp_Pnt aVertexPos; - TColStd_MapOfTransient allCurves; - if (aShapeType == TopAbs_VERTEX) { // compare positions - aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape)); - } else { - for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - allCurves.Add(aCurve); - } - } - // iterate and store the result ids of sub-elements and sub-elements to sub-labels - Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab); - std::map anOrientations; //map from edges IDs to orientations of these edges in face - std::map aSubNames; //map from edges IDs to names of edges - aRefs->Clear(); - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - FeaturePtr aSub = aComposite->subFeature(a); - const std::list >& aResults = aSub->results(); - std::list >::const_iterator aRes = aResults.cbegin(); - // there may be many shapes (circle and center): register if at least one is in selection - for(; aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(*aRes); - if (!aConstr->shape()) { - continue; - } - if (aShapeType == TopAbs_VERTEX) { - if (aConstr->shape()->isVertex()) { // compare vertices positions - const TopoDS_Shape& aVertex = aConstr->shape()->impl(); - gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex)); - if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { - aRefs->Add(aComposite->subFeatureId(a)); - aSubNames[aComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr); - } - } else { // get first or last vertex of the edge: last is stored with additional delta - const TopoDS_Shape& anEdge = aConstr->shape()->impl(); - int aDelta = kSTART_VERTEX_DELTA; - for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { - gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current())); - if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { - aRefs->Add(aDelta + aComposite->subFeatureId(a)); - aSubNames[aDelta + aComposite->subFeatureId(a)] = - Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA); - break; - } - aDelta += kSTART_VERTEX_DELTA; - } - } - } else { - if (aConstr->shape()->isEdge()) { - const TopoDS_Shape& aResShape = aConstr->shape()->impl(); - TopoDS_Edge anEdge = TopoDS::Edge(aResShape); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (allCurves.Contains(aCurve)) { - int anID = aComposite->subFeatureId(a); - aRefs->Add(anID); - aSubNames[anID] = Model_SelectionNaming::shortName(aConstr); - if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels - // add edges to sub-label to support naming for edges selection - TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); - for(; anEdgeExp.More(); anEdgeExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (aFaceCurve == aCurve) { - int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge); - anOrientations[anID] = anOrient; - - TDF_Label aLab = selectionLabel().FindChild(anID); - std::string aName = "Edge-" + Model_SelectionNaming::shortName(aConstr, 0); - TNaming_Builder aBuilder(aLab); - aBuilder.Generated(anEdge); - aMyDoc->addNamingName(aLab, aName.c_str()); - TDataStd_Name::Set(aLab, aName.c_str()); - - if (anOrient != 0) { - // store the orientation of edge relatively to face if needed - TDataStd_Integer::Set(aLab, anOrient); - } - } - } - } else { // put vertices of the selected edge to sub-labels - // add edges to sub-label to support naming for edges selection - int aDelta = kSTART_VERTEX_DELTA; - int aTagIndex = anID + kSTART_VERTEX_DELTA; - for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX); - anEdgeExp.More(); - anEdgeExp.Next(), - aTagIndex += kSTART_VERTEX_DELTA, - aDelta += kSTART_VERTEX_DELTA) { - TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current()); - - TDF_Label aLab = selectionLabel().FindChild(aTagIndex); - std::string aName = "Vertex-" - + Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA); - TNaming_Builder aBuilder(aLab); - aBuilder.Generated(aV); - aMyDoc->addNamingName(aLab, aName.c_str()); - TDataStd_Name::Set(aLab, aName.c_str()); - } - } - } - } - } - } - } - } - // store the selected as primitive - registerSubShape( - selectionLabel(), aSubShape, 0, aContextFeature, aMyDoc, anOrientations, aSubNames, aRefs); -} - bool Model_AttributeSelection::selectPart( const ResultPtr& theContext, const std::shared_ptr& theSubShape, const bool theUpdate) diff --git a/src/Model/Model_AttributeSelection.h b/src/Model/Model_AttributeSelection.h index 93fb9876e..b387297ef 100644 --- a/src/Model/Model_AttributeSelection.h +++ b/src/Model/Model_AttributeSelection.h @@ -93,10 +93,6 @@ protected: virtual void selectBody( const ResultPtr& theContext, const std::shared_ptr& theSubShape); - /// Performs the selection for the construction result (selection by index) - virtual void selectConstruction( - const ResultPtr& theContext, const std::shared_ptr& theSubShape); - /// Performs the selection for the part result (selection by name of body result inside of part) /// \param theContext the result - owner of the selection /// \param theSubShape selected shape diff --git a/src/Model/Model_Data.h b/src/Model/Model_Data.h index f34306dcb..f31891b8b 100644 --- a/src/Model/Model_Data.h +++ b/src/Model/Model_Data.h @@ -77,6 +77,7 @@ class Model_Data : public ModelAPI_Data friend class Model_AttributeSelectionList; friend class Model_ValidatorsFactory; friend class Model_SelectionNaming; + friend class Model_ResultConstruction; public: /// The simplest constructor. "setLabel" must be called just after to initialize correctly. diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 89c596d6d..805327150 100755 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -73,6 +73,8 @@ static const int TAG_CURRENT_FEATURE = 1; ///< reference to the current feature static const int TAG_CURRENT_TRANSACTION = 2; ///< integer, index of the transaction static const int TAG_SELECTION_FEATURE = 3; ///< integer, tag of the selection feature label static const int TAG_NODES_STATE = 4; ///< array, tag of the Object Browser nodes states +///< naming structures constructions selected from other document +static const int TAG_EXTERNAL_CONSTRUCTIONS = 5; Model_Document::Model_Document(const int theID, const std::string theKind) : myID(theID), myKind(theKind), myIsActive(false), @@ -1329,6 +1331,11 @@ void Model_Document::decrementTransactionID() TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal); } +TDF_Label Model_Document::extConstructionsLabel() const +{ + return myDoc->Main().FindChild(TAG_EXTERNAL_CONSTRUCTIONS); +} + bool Model_Document::isOpened() { return myObjs && !myDoc.IsNull(); diff --git a/src/Model/Model_Document.h b/src/Model/Model_Document.h index 3a031419e..33a3a736b 100644 --- a/src/Model/Model_Document.h +++ b/src/Model/Model_Document.h @@ -288,6 +288,9 @@ class Model_Document : public ModelAPI_Document /// Appends the values to theStates list. virtual void restoreNodesState(std::list& theStates) const; + /// Label that constains structures for selection of constructions of another document + TDF_Label Model_Document::extConstructionsLabel() const; + friend class Model_Application; friend class Model_Session; friend class Model_Update; @@ -298,6 +301,7 @@ class Model_Document : public ModelAPI_Document friend class Model_AttributeSelection; friend class Model_ResultPart; friend class Model_ResultCompSolid; + friend class Model_ResultConstruction; friend class Model_SelectionNaming; friend class DFBrowser; diff --git a/src/Model/Model_ResultConstruction.cpp b/src/Model/Model_ResultConstruction.cpp index d48fd305b..fa2767f9a 100644 --- a/src/Model/Model_ResultConstruction.cpp +++ b/src/Model/Model_ResultConstruction.cpp @@ -6,12 +6,34 @@ #include +#include +#include +#include #include #include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName, std::string& theDefault) { @@ -90,3 +112,446 @@ void Model_ResultConstruction::setIsConcealed(const bool theValue) { // do nothing: the construction element is never consealed } + +static const int kSTART_VERTEX_DELTA = 1000000; + +static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, + const int theID, std::shared_ptr theDoc, + std::map& theOrientations, + // name of sub-elements by ID to be exported instead of indexes + std::map& theSubNames, + Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)(), + const int theOrientation = 0) +{ + TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID); + if (theOrientation != 0) { // store the orientation of edge relatively to face if needed + TDataStd_Integer::Set(aLab, theOrientation); + } + TNaming_Builder aBuilder(aLab); + aBuilder.Generated(theShape); + std::stringstream aName; + // #1839 : do not store name of the feature in the tree, since this name could be changed + //aName<name(); + if (theShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction + //aName<<"/"; + if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face"; + else if (theShape.ShapeType() == TopAbs_WIRE) aName<<"Wire"; + else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge"; + else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex"; + + if (theRefs.IsNull()) { + aName<GetMap()); + for(; aRef.More(); aRef.Next()) { + aName<<"-"<addNamingName(aLab, aName.str()); + TDataStd_Name::Set(aLab, aName.str().c_str()); +} + +TDF_Label Model_ResultConstruction::startLabel( + const std::shared_ptr theExtDoc, bool& theExternal) +{ + theExternal = theExtDoc.get() && theExtDoc != document(); + if (theExternal) { // external document is used + std::shared_ptr aDoc = std::dynamic_pointer_cast(theExtDoc); + return aDoc->extConstructionsLabel(); + } + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + return aData->label(); +} + +int Model_ResultConstruction::select(const std::shared_ptr& theSubShape, + const std::shared_ptr theExtDoc, const int theIndex) +{ + int anIndex; // resulting index of the sub-label + TopoDS_Shape aSubShape; + if (theSubShape.get()) { + aSubShape = theSubShape->impl(); + } else if (shape().get()) { + aSubShape = shape()->impl(); + } + // if external document requires this selection, put the naming structures to this doc + // to support the naming mechanism in this document correctly + bool anExternal; + TDF_Label aDataLab = startLabel(theExtDoc, anExternal); + if (theIndex == -1) { + anIndex = anExternal ? 2 : 1; // for the external doc don't mind about the main shape + + if (theSubShape.get() || anExternal) { // searching for already selected sub (or whole for ext) + // iterate all the already presented shapes to see the same + TDF_ChildIterator aSubsIter(aDataLab, Standard_False); + for(; aSubsIter.More(); aSubsIter.Next()) { + const TDF_Label aLab = aSubsIter.Value(); + if (aLab.Tag() == 1) // skip the root shape label + continue; + Handle(TNaming_NamedShape) aNS; + if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + if (aNS->Get().IsSame(aSubShape)) { + return aLab.Tag() - 1; // found exactly the needed shape, nothing else to do + } + } + anIndex = aLab.Tag(); // searching for the latest index + } + anIndex = (anIndex == 1) ? 2 : (anIndex + 1); // next after 1-root, or next after all + } + } else { + anIndex = theIndex + 1; + } + + // set the naming structure at index + TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True); + TNaming_Builder aBuilder(aLab); + if (aSubShape.IsNull()) + return anIndex - 1; // just keep empty named shape + aBuilder.Generated(aSubShape); + + if (anIndex == 1 && isInfinite()) { // infinitive results has no sub-selection + return anIndex - 1; + } + ResultPtr aThisPtr = std::dynamic_pointer_cast(data()->owner()); + FeaturePtr aThisFeature = document()->feature(aThisPtr); + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(aThisFeature); + if (!aComposite || aComposite->numberOfSubs() == 0) { + // saving of context is enough: result construction contains exactly the needed shape + return anIndex - 1; + } + // identify the results of sub-object of the composite by edges + // save type of the selected shape in integer attribute + TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType(); + TDataStd_Integer::Set(aLab, (int)aShapeType); + gp_Pnt aVertexPos; + TColStd_MapOfTransient allCurves; + if (aShapeType == TopAbs_VERTEX) { // compare positions + aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape)); + } else { + for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + allCurves.Add(aCurve); + } + } + std::shared_ptr aMyDoc = + std::dynamic_pointer_cast(document()); + // iterate and store the result ids of sub-elements and sub-elements to sub-labels + Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab); + std::map anOrientations; //map from edges IDs to orientations of these edges in face + std::map aSubNames; //map from edges IDs to names of edges + aRefs->Clear(); + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + FeaturePtr aSub = aComposite->subFeature(a); + const std::list >& aResults = aSub->results(); + std::list >::const_iterator aRes = aResults.cbegin(); + // there may be many shapes (circle and center): register if at least one is in selection + for(; aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + if (!aConstr->shape()) { + continue; + } + if (aShapeType == TopAbs_VERTEX) { + if (aConstr->shape()->isVertex()) { // compare vertices positions + const TopoDS_Shape& aVertex = aConstr->shape()->impl(); + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex)); + if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { + aRefs->Add(aComposite->subFeatureId(a)); + aSubNames[aComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr); + } + } else { // get first or last vertex of the edge: last is stored with additional delta + const TopoDS_Shape& anEdge = aConstr->shape()->impl(); + int aDelta = kSTART_VERTEX_DELTA; + for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current())); + if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { + aRefs->Add(aDelta + aComposite->subFeatureId(a)); + aSubNames[aDelta + aComposite->subFeatureId(a)] = + Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA); + break; + } + aDelta += kSTART_VERTEX_DELTA; + } + } + } else { + if (aConstr->shape()->isEdge()) { + const TopoDS_Shape& aResShape = aConstr->shape()->impl(); + TopoDS_Edge anEdge = TopoDS::Edge(aResShape); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (allCurves.Contains(aCurve)) { + int anID = aComposite->subFeatureId(a); + aRefs->Add(anID); + aSubNames[anID] = Model_SelectionNaming::shortName(aConstr); + if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels + // add edges to sub-label to support naming for edges selection + TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); + for(; anEdgeExp.More(); anEdgeExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (aFaceCurve == aCurve) { + int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge); + anOrientations[anID] = anOrient; + + TDF_Label aSubLab = aLab.FindChild(anID); + std::string aName = "Edge-" + Model_SelectionNaming::shortName(aConstr, 0); + TNaming_Builder aBuilder(aSubLab); + aBuilder.Generated(anEdge); + aMyDoc->addNamingName(aSubLab, aName.c_str()); + TDataStd_Name::Set(aSubLab, aName.c_str()); + + if (anOrient != 0) { + // store the orientation of edge relatively to face if needed + TDataStd_Integer::Set(aSubLab, anOrient); + } + } + } + } else { // put vertices of the selected edge to sub-labels + // add edges to sub-label to support naming for edges selection + int aDelta = kSTART_VERTEX_DELTA; + int aTagIndex = anID + kSTART_VERTEX_DELTA; + for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX); + anEdgeExp.More(); + anEdgeExp.Next(), + aTagIndex += kSTART_VERTEX_DELTA, + aDelta += kSTART_VERTEX_DELTA) { + TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current()); + + TDF_Label aSubLab = aLab.FindChild(aTagIndex); + std::string aName = "Vertex-" + + Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA); + TNaming_Builder aBuilder(aLab); + aBuilder.Generated(aV); + aMyDoc->addNamingName(aLab, aName.c_str()); + TDataStd_Name::Set(aLab, aName.c_str()); + } + } + } + } + } + } + } + } + // store the selected as primitive + registerSubShape(aLab, aSubShape, 0, aMyDoc, anOrientations, aSubNames, aRefs); + + return anIndex - 1; +} + +std::shared_ptr Model_ResultConstruction::shape(const int theIndex, + const std::shared_ptr theExtDoc) +{ + std::shared_ptr aResult; + if (theIndex == 0) + return aResult; // the whole shape, so, NULL + + bool isExt; + TDF_Label aLab = startLabel(theExtDoc, isExt).FindChild(theIndex + 1); + if (!aLab.IsNull()) { // index is not bad + Handle(TNaming_NamedShape) aSelection; + if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { + TopoDS_Shape aSelShape = aSelection->Get(); + aResult = std::shared_ptr(new GeomAPI_Shape); + aResult->setImpl(new TopoDS_Shape(aSelShape)); + } + } + + return aResult; +} + +bool Model_ResultConstruction::update(const int theIndex, + const std::shared_ptr theExtDoc, bool& theModified) +{ + theModified = false; + bool anExt; + TDF_Label aLab = startLabel(theExtDoc, anExt).FindChild(theIndex + 1, Standard_True); + if (theIndex == 0) { + // it is just reference to construction, not sub-shape + // if there is a sketch, the sketch-naming must be updated + if (!isInfinite()) { + BRep_Builder aCompoundBuilder; + TopoDS_Compound aComp; + aCompoundBuilder.MakeCompound(aComp); + for(int a = 0; a < facesNum(); a++) { + TopoDS_Shape aFace = face(a)->impl(); + aCompoundBuilder.Add(aComp, aFace); + } + std::shared_ptr aShape(new GeomAPI_Shape); + aShape->setImpl(new TopoDS_Shape(aComp)); + select(aShape, theExtDoc, theIndex); + } else { + // For correct naming selection, put the shape into the naming structure. + // It seems sub-shapes are not needed: only this shape is (and can be ) selected. + TNaming_Builder aBuilder(aLab); + aBuilder.Generated(shape()->impl()); + } + return shape() && !shape()->isNull(); + } + // construction: identification by the results indexes, recompute faces and + // take the face that more close by the indexes + ResultPtr aThisPtr = std::dynamic_pointer_cast(data()->owner()); + FeaturePtr aContextFeature = document()->feature(aThisPtr); + // sketch sub-element + if (std::dynamic_pointer_cast(aContextFeature).get()) + { + // getting a type of selected shape + Handle(TDataStd_Integer) aTypeAttr; + if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) { + return false; + } + TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get()); + // selected indexes will be needed in each "if" + Handle(TDataStd_IntPackedMap) aSubIds; + std::shared_ptr aNewSelected; + bool aNoIndexes = + !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0; + // for now working only with composite features + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(aContextFeature); + if (!aComposite.get() || aComposite->numberOfSubs() == 0) { + return false; + } + + if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) { + // compound is for the whole sketch selection + // If this is a wire with plane defined then it is a sketch-like object + if (!facesNum()) // no faces, update can not work correctly + return false; + // if there is no edges indexes, any face can be used: take the first + std::shared_ptr aNewSelected; + if (aNoIndexes) { + aNewSelected = face(0); + } else { // searching for most looks-like initial face by the indexes + // prepare edges of the current result for the fast searching + // curves and orientations of edges + NCollection_DataMap allCurves; + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + int aSubID = aComposite->subFeatureId(a); + if (aSubIds->Contains(aSubID)) { + FeaturePtr aSub = aComposite->subFeature(a); + const std::list >& aResults = aSub->results(); + std::list >::const_iterator aRes; + for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + if (aConstr->shape() && aConstr->shape()->isEdge()) { + const TopoDS_Shape& aResShape = aConstr->shape()->impl(); + TopoDS_Edge anEdge = TopoDS::Edge(aResShape); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + // searching for orientation information + int anOrient = 0; + Handle(TDataStd_Integer) anInt; + if (aLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)) { + anOrient = anInt->Get(); + } + allCurves.Bind(aCurve, anOrient); + } + } + } + } + } + aNewSelected = Model_SelectionNaming::findAppropriateFace( + aThisPtr, allCurves, aShapeType == TopAbs_WIRE); + } + if (aNewSelected) { // store this new selection + select(aNewSelected, theExtDoc, theIndex); + theModified = true; + return true; + } else { + // if the selection is not found, put the empty shape: + // it's better to have disappeared shape, than the old, the lost one + TNaming_Builder anEmptyBuilder(aLab); + return false; + } + } else if (aShapeType == TopAbs_EDGE) { + // just reselect the edge by the id + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + // if aSubIds take any, the first appropriate + if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) { + // found the appropriate feature + FeaturePtr aFeature = aComposite->subFeature(a); + std::list >::const_iterator aResIter = + aFeature->results().cbegin(); + for(;aResIter != aFeature->results().cend(); aResIter++) { + ResultConstructionPtr aRes = + std::dynamic_pointer_cast(*aResIter); + if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found! + select(aRes->shape(), theExtDoc, theIndex); + theModified = true; + return true; + } + } + } + } + } else if (aShapeType == TopAbs_VERTEX) { + // just reselect the vertex by the id of edge + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + // if aSubIds take any, the first appropriate + int aFeatureID = aComposite->subFeatureId(a); + if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) || + aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) || + aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) { + // searching for deltas + int aVertexNum = 0; + if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1; + else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2; + // found the feature with appropriate edge + FeaturePtr aFeature = aComposite->subFeature(a); + std::list >::const_iterator aResIter = + aFeature->results().cbegin(); + for(;aResIter != aFeature->results().cend(); aResIter++) { + ResultConstructionPtr aRes = + std::dynamic_pointer_cast(*aResIter); + if (aRes && aRes->shape()) { + if (aRes->shape()->isVertex() && aVertexNum == 0) { // found! + select(aRes->shape(), theExtDoc, theIndex); + theModified = true; + return true; + } else if (aRes->shape()->isEdge() && aVertexNum > 0) { + const TopoDS_Shape& anEdge = aRes->shape()->impl(); + int aVIndex = 1; + for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { + if (aVIndex == aVertexNum) { // found! + std::shared_ptr aVertex(new GeomAPI_Shape); + aVertex->setImpl(new TopoDS_Shape(aVExp.Current())); + select(aVertex, theExtDoc, theIndex); + theModified = true; + return true; + } + aVIndex++; + } + } + } + } + } + } + } + } else { // simple construction element: the selected is that needed + select(shape(), theExtDoc, theIndex); + theModified = true; + return true; + } + return false; // unknown case +} diff --git a/src/Model/Model_ResultConstruction.h b/src/Model/Model_ResultConstruction.h index 151d8a46a..4efeb0e3e 100644 --- a/src/Model/Model_ResultConstruction.h +++ b/src/Model/Model_ResultConstruction.h @@ -11,6 +11,9 @@ #include #include +class ModelAPI_Document; +class TDF_Label; + /**\class Model_ResultConstruction * \ingroup DataModel * \brief The construction element result of a feature. @@ -58,10 +61,40 @@ class Model_ResultConstruction : public ModelAPI_ResultConstruction /// The construction element is never concealed MODEL_EXPORT virtual void setIsConcealed(const bool theValue); + // methods related to selection of sub-shapes in construction, used by SelectionAttribute + + /// Selects theSubShape in the construction. Returns an index of the selected sub-shape. + /// Puts the selected shape with a needed BRepNaming sub-structure to the data tree of result. + /// If theSubShape is null, it selects the whole construction and returns zero index. + /// If theIndex is not -1, it re-selects over the existing data (used for update selection). + /// If theExtDoc is document where this selection is needed, if it differs from this, + /// naming structures will be located there. + int select(const std::shared_ptr& theSubShape, + const std::shared_ptr theExtDoc, const int theIndex = -1); + + /// Returns already selected shape by the given index. Zero index means the whole construction, + /// so, the returned shape in this case is null. + /// If theExtDoc is document where this selection is needed, if it differs from this, + /// naming structures will be located there. + std::shared_ptr shape(const int theIndex, + const std::shared_ptr theExtDoc); + + /// Updates the existing selection by the index. + /// Returns false if update is failed. Returns theModified true if the selection was updated. + /// If theExtDoc is document where this selection is needed, if it differs from this, + /// naming structures will be updated there. + bool update(const int theIndex, const std::shared_ptr theExtDoc, + bool& theModified); + protected: /// Makes a body on the given feature Model_ResultConstruction(); + /// Searchies for the working label selection/update will start from + /// Returns true if this is label of the external document. + /// theExtDoc is document where this selection is required + TDF_Label startLabel(const std::shared_ptr theExtDoc, bool& theExternal); + friend class Model_Objects; }; diff --git a/src/Model/Model_SelectionNaming.cpp b/src/Model/Model_SelectionNaming.cpp index dac80bb5f..42c97b2a9 100644 --- a/src/Model/Model_SelectionNaming.cpp +++ b/src/Model/Model_SelectionNaming.cpp @@ -55,7 +55,6 @@ std::string Model_SelectionNaming::getShapeName( // add the result name to the name of the shape // (it was in BodyBuilder, but did not work on Result rename) bool isNeedContextName = theContext->shape().get() != NULL; - // && !theContext->shape()->isEqual(theSubSh); // check if the subShape is already in DF Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(theShape, myLab); Handle(TDataStd_Name) anAttr; diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 0e90444bc..198696aef 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -142,4 +142,5 @@ ADD_UNIT_TESTS(TestConstants.py TestDoubleArray.py Test1757.py Test1998.py + Test1995.py ) diff --git a/src/ModelAPI/Test/Test1995.py b/src/ModelAPI/Test/Test1995.py new file mode 100644 index 000000000..9a64c6502 --- /dev/null +++ b/src/ModelAPI/Test/Test1995.py @@ -0,0 +1,38 @@ +# Lighter case to reproduce problem of #1995 +# The problem was in axis that contained sub-shapes naming of the sketch and the extrusion becomes +# use this axis. So, on remove of the axis, the naming is failed. Same for modifications of the sketch 1. + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchLine_1 = Sketch_1.addLine(175.5289977047663, 37.215818549061, -134.623385345167, 37.215818549061) +SketchLine_2 = Sketch_1.addLine(-134.623385345167, 37.215818549061, -134.623385345167, -108.7867760111381) +SketchLine_3 = Sketch_1.addLine(-134.623385345167, -108.7867760111381, 175.5289977047663, -108.7867760111381) +SketchLine_4 = Sketch_1.addLine(175.5289977047663, -108.7867760111381, 175.5289977047663, 37.215818549061) +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()) +model.do() +Axis_4 = model.addAxis(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchLine_2f-SketchLine_3f-SketchLine_4f"), model.selection("VERTEX", "Sketch_1/Vertex-SketchLine_3s-SketchLine_2e")) +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 50, 0) +Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_2")) +SketchCircle_1 = Sketch_2.addCircle(12.88847795756506, 28.93359954982685, 11.55225986344597) +model.do() + +# now remove axis to destroy naming structure if extrusion refers to it +Part_1_doc.removeFeature(Axis_4.feature()) +# also update sketch_1 to launch recomputation of everything +SketchLine_1.setStartPoint(170, -130) +model.end() + +import ModelAPI +assert(ModelAPI.ModelAPI_Session.get().validators().validate(Sketch_2.feature())) diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 9f6b63a77..04cf7331b 100755 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -212,9 +212,10 @@ bool SketchPlugin_Sketch::isSub(ObjectPtr theObject) const void SketchPlugin_Sketch::attributeChanged(const std::string& theID) { if (theID == SketchPlugin_SketchEntity::EXTERNAL_ID()) { - std::shared_ptr aSelection = - data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->value(); - if (aSelection) { // update arguments due to the selection value + AttributeSelectionPtr aSelAttr = selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + if (aSelAttr->context().get()) { // update arguments due to the selection value + std::shared_ptr aSelection = aSelAttr->value(); + if (!aSelection.get()) aSelection = aSelAttr->context()->shape(); // update the sketch plane std::shared_ptr aFace(new GeomAPI_Face(aSelection)); std::shared_ptr aPlane = aFace->getPlane(); -- 2.39.2