X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=54b3d0f834a54e4f83c83a9228a1fc661e05cfb3;hb=176403004ff97696f3c0b5f8bdf48692177fb34a;hp=bdc924e2766a9535110372d85243134f768a584c;hpb=cc171413e851e053de99dee13870d2c1cab0327e;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index bdc924e27..54b3d0f83 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -10,6 +10,7 @@ #include "Model_Data.h" #include "Model_Document.h" #include "Model_SelectionNaming.h" +#include #include #include #include @@ -17,14 +18,18 @@ #include #include #include +#include #include -#include +#include #include #include #include #include #include +#include +#include +#include #include #include #include @@ -54,14 +59,14 @@ #include #include #include -#include #include + using namespace std; //#define DEB_NAMING 1 #ifdef DEB_NAMING #include #endif -/// adeed to the index in the packed map to signalize that the vertex of edge is seleted +/// added to the index in the packed map to signalize that the vertex of edge is selected /// (multiplied by the index of the edge) static const int kSTART_VERTEX_DELTA = 1000000; // identifier that there is simple reference: selection equals to context @@ -98,8 +103,9 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape))); if (isOldShape) return; // shape is the same, so context is also unchanged // update the referenced object if needed - if (!isOldContext) - myRef.setValue(theContext); + if (!isOldContext) { + myRef.setValue(theContext); + } // do noth use naming if selected shape is result shape itself, but not sub-shape TDF_Label aSelLab = selectionLabel(); @@ -145,9 +151,10 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, aBuilder.Generated(theContext->shape()->impl()); std::shared_ptr aMyDoc = std::dynamic_pointer_cast(owner()->document()); - std::string aName = theContext->data()->name(); - aMyDoc->addNamingName(aSelLab, aName); - TDataStd_Name::Set(aSelLab, aName.c_str()); + //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; @@ -172,19 +179,29 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, //myIsInitialized = true; owner()->data()->sendAttributeUpdated(this); +} - std::string aSelName = namingName(); - if(!aSelName.empty()) - TDataStd_Name::Set(selectionLabel(), aSelName.c_str()); //set name +void Model_AttributeSelection::removeTemporaryValues() +{ + if (myTmpContext.get() || myTmpSubShape.get()) { + myTmpContext.reset(); + myTmpSubShape.reset(); + } } std::shared_ptr Model_AttributeSelection::value() { + GeomShapePtr aResult; if (myTmpContext.get() || myTmpSubShape.get()) { - return myTmpSubShape; + ResultConstructionPtr aResulConstruction = + std::dynamic_pointer_cast(myTmpContext); + if(aResulConstruction.get()) { + // it is just reference to construction. + return myTmpSubShape; + } + return myTmpSubShape.get() ? myTmpSubShape : myTmpContext->shape(); } - std::shared_ptr aResult; TDF_Label aSelLab = selectionLabel(); if (aSelLab.IsAttribute(kINVALID_SELECTION)) return aResult; @@ -196,7 +213,8 @@ 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 + 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)) { @@ -205,15 +223,22 @@ std::shared_ptr Model_AttributeSelection::value() return std::shared_ptr(); // postponed naming needed Handle(TDataStd_Integer) anIndex; 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 + 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)) { + std::string aSubShapeName(TCollection_AsciiString(aName->Get()).ToCString()); + std::size_t aPartEnd = aSubShapeName.find('/'); + if (aPartEnd != string::npos && aPartEnd != aSubShapeName.rfind('/')) { + string aNameInPart = aSubShapeName.substr(aPartEnd + 1); + int anIndex; + std::string aType; // to reuse already existing selection the type is not needed + return aPart->shapeInPart(aNameInPart, aType, anIndex); + } + } + } } - return aPart->shapeInPart(TCollection_AsciiString(aName->Get()).ToCString()); - */ } Handle(TNaming_NamedShape) aSelection; @@ -239,7 +264,7 @@ bool Model_AttributeSelection::isInvalid() bool Model_AttributeSelection::isInitialized() { - if (ModelAPI_AttributeSelection::isInitialized()) { // additional checkings if it is initialized + if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized std::shared_ptr aResult; if (myRef.isInitialized()) { TDF_Label aSelLab = selectionLabel(); @@ -247,7 +272,8 @@ 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 + if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { + // it is just reference to construction, nothing is in value return true; } @@ -312,7 +338,7 @@ void Model_AttributeSelection::setObject(const std::shared_ptr& TDF_LabelMap& Model_AttributeSelection::scope() { if (myScope.IsEmpty()) { // create a new scope if not yet done - // gets all featueres with named shapes that are bofore this feature label (before in history) + // gets all features with named shapes that are before this feature label (before in history) DocumentPtr aMyDoc = owner()->document(); std::list > allFeatures = aMyDoc->allFeatures(); std::list >::iterator aFIter = allFeatures.begin(); @@ -336,7 +362,8 @@ TDF_LabelMap& Model_AttributeSelection::scope() } if (isGroup) aMePassed = false; bool isInScope = !aMePassed; - if (!isInScope && aComposite.get()) { // try to add sub-elements of composite if this is composite + if (!isInScope && aComposite.get()) { + // try to add sub-elements of composite if this is composite if (aComposite->isSub(*aFIter)) isInScope = true; } @@ -360,19 +387,6 @@ TDF_LabelMap& Model_AttributeSelection::scope() return myScope; } -/// produces theEdge orientation relatively to theContext face -int edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge) -{ - if (theContext.ShapeType() != TopAbs_FACE) - return 0; - TopoDS_Face aContext = TopoDS::Face(theContext); - if (theEdge.Orientation() == TopAbs_FORWARD) - return 1; - if (theEdge.Orientation() == TopAbs_REVERSED) - return -1; - return 0; // unknown -} - /// Sets the invalid flag if flag is false, or removes it if "true" /// Returns theFlag static bool setInvalidIfFalse(TDF_Label& theLab, const bool theFlag) { @@ -393,7 +407,8 @@ 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 (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); @@ -408,21 +423,48 @@ bool Model_AttributeSelection::update() 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()); + //std::string aName = contextName(aContext); + //aMyDoc->addNamingName(aSelLab, aName); + //TDataStd_Name::Set(aSelLab, aName.c_str()); } 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; - return setInvalidIfFalse(aSelLab, selectPart(aContext, aNoSelection, true)); + bool aResult = selectPart(aContext, aNoSelection, true); + aResult = setInvalidIfFalse(aSelLab, aResult); + if (aResult) { + owner()->data()->sendAttributeUpdated(this); + } + return aResult; } if (aContext->groupName() == ModelAPI_ResultBody::group()) { // body: just a named shape, use selection mechanism from OCCT TNaming_Selector aSelector(aSelLab); + TopoDS_Shape anOldShape; + if (!aSelector.NamedShape().IsNull()) { + anOldShape = aSelector.NamedShape()->Get(); + } bool aResult = aSelector.Solve(scope()) == Standard_True; - owner()->data()->sendAttributeUpdated(this); - return setInvalidIfFalse(aSelLab, aResult); + // must be before sending of updated attribute (1556) + aResult = setInvalidIfFalse(aSelLab, aResult); + TopoDS_Shape aNewShape; + if (!aSelector.NamedShape().IsNull()) { + aNewShape = aSelector.NamedShape()->Get(); + } + if (anOldShape.IsNull() || aNewShape.IsNull() || + !anOldShape.IsEqual(aSelector.NamedShape()->Get())) // send updated if shape is changed + owner()->data()->sendAttributeUpdated(this); + return aResult; } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { // construction: identification by the results indexes, recompute faces and // take the face that more close by the indexes @@ -452,8 +494,9 @@ bool Model_AttributeSelection::update() return setInvalidIfFalse(aSelLab, false); } - if (aShapeType == TopAbs_FACE) { // compound is for the whole sketch selection - // If this is a wire with plane defined thin it is a sketch-like object + 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 @@ -461,8 +504,9 @@ bool Model_AttributeSelection::update() if (aNoIndexes) { aNewSelected = aConstructionContext->face(0); } else { // searching for most looks-like initial face by the indexes - // prepare edges of the current resut for the fast searching - NCollection_DataMap allCurves; // curves and orientations of edges + // 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); @@ -491,49 +535,17 @@ bool Model_AttributeSelection::update() } } } - int aBestFound = 0; // best number of found edges (not percentage: issue 1019) - int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation - for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) { - int aFound = 0, aNotFound = 0, aSameOrientation = 0; - TopoDS_Face aFace = - TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl()); - TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE); - TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841) - for(; anEdgesExp.More(); anEdgesExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (alreadyProcessed.Contains(aCurve)) - continue; - alreadyProcessed.Add(aCurve); - if (allCurves.IsBound(aCurve)) { - aFound++; - int anOrient = allCurves.Find(aCurve); - if (anOrient != 0) { // extra comparision score is orientation - if (edgeOrientation(aFace, anEdge) == anOrient) - aSameOrientation++; - } - } else { - aNotFound++; - } - } - } - if (aFound + aNotFound != 0) { - if (aFound > aBestFound || - (aFound == aBestFound && aSameOrientation > aBestOrient)) { - aBestFound = aFound; - aBestOrient = aSameOrientation; - aNewSelected = aConstructionContext->face(aFaceIndex); - } - } - } + 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 setInvalidIfFalse(aSelLab, 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 + 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); } @@ -552,8 +564,9 @@ bool Model_AttributeSelection::update() 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 setInvalidIfFalse(aSelLab, true); + return true; } } } @@ -581,8 +594,9 @@ bool Model_AttributeSelection::update() if (aRes && aRes->shape()) { if (aRes->shape()->isVertex() && aVertexNum == 0) { // found! selectConstruction(aContext, aRes->shape()); + setInvalidIfFalse(aSelLab, true); owner()->data()->sendAttributeUpdated(this); - return setInvalidIfFalse(aSelLab, true); + return true; } else if (aRes->shape()->isEdge() && aVertexNum > 0) { const TopoDS_Shape& anEdge = aRes->shape()->impl(); int aVIndex = 1; @@ -591,8 +605,9 @@ bool Model_AttributeSelection::update() 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 setInvalidIfFalse(aSelLab, true); + return true; } aVIndex++; } @@ -604,14 +619,14 @@ bool Model_AttributeSelection::update() } } else { // simple construction element: the selected is that needed selectConstruction(aContext, aContext->shape()); + setInvalidIfFalse(aSelLab, true); owner()->data()->sendAttributeUpdated(this); - return setInvalidIfFalse(aSelLab, true); + return true; } } return setInvalidIfFalse(aSelLab, false); // unknown case } - void Model_AttributeSelection::selectBody( const ResultPtr& theContext, const std::shared_ptr& theSubShape) { @@ -628,17 +643,72 @@ void Model_AttributeSelection::selectBody( if (aResult) { aContext = aResult->shape()->impl(); } else { - Events_Error::send("A result with shape is expected"); + Events_InfoMessage("Model_AttributeSelection", "A result with shape is expected").send(); return; } } - TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl() : aContext; + + // with "recover" feature the selected context may be not up to date (issue 1710) + Handle(TNaming_NamedShape) aResult; + TDF_Label aSelLab = selectionLabel(); + TopoDS_Shape aNewContext = aContext; + bool isUpdated = true; + while(!aNewContext.IsNull() && isUpdated) { + // searching for the very last shape that was produced from this one + isUpdated = false; + if (!TNaming_Tool::HasLabel(aSelLab, aNewContext)) + // to avoid crash of TNaming_SameShapeIterator if pure shape does not exists + break; + for(TNaming_SameShapeIterator anIter(aNewContext, aSelLab); anIter.More(); anIter.Next()) { + TDF_Label aNSLab = anIter.Label(); + if (!scope().Contains(aNSLab)) + continue; + Handle(TNaming_NamedShape) aNS; + if (aNSLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) { + if (aShapesIter.Evolution() == TNaming_SELECTED) + continue; // don't use the selection evolution + if (!aShapesIter.OldShape().IsNull() && aShapesIter.OldShape().IsSame(aNewContext)) { + // found the original shape + aNewContext = aShapesIter.NewShape(); // go to the newer shape + isUpdated = true; + break; + } + } + } + } + } + if (aNewContext.IsNull()) { // a context is already deleted + setInvalidIfFalse(aSelLab, false); + Events_InfoMessage("Model_AttributeSelection", "Failed to select shape already deleted").send(); + return; + } + + TopoDS_Shape aNewSub = theSubShape ? theSubShape->impl() : aContext; + if (!aNewSub.IsEqual(aContext)) { // searching for subshape in the new context + bool isFound = false; + TopExp_Explorer anExp(aNewContext, aNewSub.ShapeType()); + for(; anExp.More(); anExp.Next()) { + if (anExp.Current().IsEqual(aNewSub)) { + isFound = true; + break; + } + } + if (!isFound) { // sub-shape is not found in the up-to-date instance of the context shape + setInvalidIfFalse(aSelLab, false); + Events_InfoMessage("Model_AttributeSelection", + "Failed to select sub-shape already modified").send(); + return; + } + } + + /// fix for issue 411: result modified shapes must not participate in this selection mechanism FeaturePtr aFeatureOwner = std::dynamic_pointer_cast(owner()); if (aFeatureOwner.get()) aFeatureOwner->eraseResults(); if (!aContext.IsNull()) { - aSel.Select(aNewShape, aContext); + aSel.Select(aNewSub, aNewContext); } } @@ -649,7 +719,9 @@ void Model_AttributeSelection::selectBody( /// -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::string theAdditionalName, std::map& theOrientations, + 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) { @@ -660,28 +732,31 @@ static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, TNaming_Builder aBuilder(aLab); aBuilder.Generated(theShape); std::stringstream aName; - aName<name()<<"/"; - if (!theAdditionalName.empty()) - aName<GetMap()); - for(; aRef.More(); aRef.Next()) { - 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(selectionLabel(), theContext->data()->name()); - TDataStd_Name::Set(selectionLabel(), theContext->data()->name().c_str()); + //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 reuslts of sub-object of the composite by edges + // 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); @@ -728,6 +804,7 @@ void Model_AttributeSelection::selectConstruction( // 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++) { @@ -747,14 +824,17 @@ void Model_AttributeSelection::selectConstruction( 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 negative sign + } 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; @@ -770,6 +850,7 @@ void Model_AttributeSelection::selectConstruction( 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); @@ -778,11 +859,11 @@ void Model_AttributeSelection::selectConstruction( Standard_Real aFirst, aLast; Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); if (aFaceCurve == aCurve) { - int anOrient = edgeOrientation(aSubShape, anEdge); + int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge); anOrientations[anID] = anOrient; registerSubShape( - selectionLabel(), anEdge, anID, aContextFeature, aMyDoc, "", anOrientations, - Handle(TDataStd_IntPackedMap)(), anOrient); + selectionLabel(), anEdge, anID, aContextFeature, aMyDoc, anOrientations, + aSubNames, Handle(TDataStd_IntPackedMap)(), anOrient); } } } else { // put vertices of the selected edge to sub-labels @@ -794,7 +875,8 @@ void Model_AttributeSelection::selectConstruction( std::stringstream anAdditionalName; registerSubShape( - selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc, "", anOrientations); + selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc, anOrientations, + aSubNames); } } } @@ -807,7 +889,7 @@ void Model_AttributeSelection::selectConstruction( TNaming_Builder aBuilder(selectionLabel()); aBuilder.Generated(aSubShape); registerSubShape( - selectionLabel(), aSubShape, 0, aContextFeature, aMyDoc, "", anOrientations, aRefs); + selectionLabel(), aSubShape, 0, aContextFeature, aMyDoc, anOrientations, aSubNames, aRefs); } bool Model_AttributeSelection::selectPart( @@ -819,7 +901,8 @@ bool Model_AttributeSelection::selectPart( return true; // postponed naming if (theUpdate) { Handle(TDataStd_Integer) anIndex; - if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) { // by internal selection + if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + // by internal selection if (anIndex->Get() > 0) { // update the selection by index return aPart->updateInPart(anIndex->Get()); @@ -829,7 +912,7 @@ bool Model_AttributeSelection::selectPart( } return true; // nothing to do, referencing just by name } - // store the shape (in case part is not loaded it should be usefull + // store the shape (in case part is not loaded it should be useful TopoDS_Shape aShape; std::string aName = theContext->data()->name(); if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected @@ -857,17 +940,13 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa std::string aName(""); if(!this->isInitialized()) return !theDefaultName.empty() ? theDefaultName : aName; - Handle(TDataStd_Name) anAtt; - if(selectionLabel().FindAttribute(TDataStd_Name::GetID(), anAtt)) { - aName = TCollection_AsciiString(anAtt->Get()).ToCString(); - return aName; - } std::shared_ptr aSubSh = value(); ResultPtr aCont = context(); Model_SelectionNaming aSelNaming(selectionLabel()); - return aSelNaming.namingName(aCont, aSubSh, theDefaultName); + return aSelNaming.namingName( + aCont, aSubSh, theDefaultName, owner()->document() != aCont->document()); } // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT @@ -900,6 +979,28 @@ void Model_AttributeSelection::selectSubShape( std::shared_ptr aShapeToBeSelected; ResultPtr aCont; if (aSelNaming.selectSubShape(theType, theSubShapeName, aDoc, aShapeToBeSelected, aCont)) { + // try to find the last context to find the up to date shape + if (aCont->shape().get() && !aCont->shape()->isNull() && + aCont->groupName() == ModelAPI_ResultBody::group() && aDoc == owner()->document()) { + const TopoDS_Shape aConShape = aCont->shape()->impl(); + if (!aConShape.IsNull()) { + Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aConShape, selectionLabel()); + if (!aNS.IsNull()) { + aNS = TNaming_Tool::CurrentNamedShape(aNS); + if (!aNS.IsNull()) { + TDF_Label aLab = aNS->Label(); + while(aLab.Depth() != 7 && aLab.Depth() > 5) + aLab = aLab.Father(); + ObjectPtr anObj = aDoc->objects()->object(aLab); + if (anObj.get()) { + ResultPtr aRes = std::dynamic_pointer_cast(anObj); + if (aRes) + aCont = aRes; + } + } + } + } + } setValue(aCont, aShapeToBeSelected); } } @@ -909,6 +1010,11 @@ int Model_AttributeSelection::Id() int anID = 0; std::shared_ptr aSelection = value(); std::shared_ptr aContext = context()->shape(); + // support for compsolids: + if (context().get() && ModelAPI_Tools::compSolidOwner(context()).get()) + aContext = ModelAPI_Tools::compSolidOwner(context())->shape(); + + TopoDS_Shape aMainShape = aContext->impl(); const TopoDS_Shape& aSubShape = aSelection->impl(); // searching for the latest main shape @@ -930,3 +1036,202 @@ int Model_AttributeSelection::Id() } return anID; } + +void Model_AttributeSelection::setId(int theID) +{ + const ResultPtr& aContext = context(); + std::shared_ptr aSelection; + + std::shared_ptr aContextShape = aContext->shape(); + // support for compsolids: + if (aContext.get() && ModelAPI_Tools::compSolidOwner(aContext).get()) + aContextShape = ModelAPI_Tools::compSolidOwner(aContext)->shape(); + + TopoDS_Shape aMainShape = aContextShape->impl(); + // searching for the latest main shape + if (theID > 0 && + aContextShape && !aContextShape->isNull()) + { + std::shared_ptr aDoc = + std::dynamic_pointer_cast(aContext->document()); + if (aDoc.get()) { + Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel()); + if (!aNS.IsNull()) { + aMainShape = TNaming_Tool::CurrentShape(aNS); + } + } + + TopTools_IndexedMapOfShape aSubShapesMap; + TopExp::MapShapes(aMainShape, aSubShapesMap); + const TopoDS_Shape& aSelShape = aSubShapesMap.FindKey(theID); + + std::shared_ptr aResult(new GeomAPI_Shape); + aResult->setImpl(new TopoDS_Shape(aSelShape)); + + aSelection = aResult; + } + + setValue(aContext, aSelection); +} + +std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const +{ + std::string aResult; + if (owner()->document() != theContext->document()) { + if (theContext->document() == ModelAPI_Session::get()->moduleDocument()) { + aResult = theContext->document()->kind() + "/"; + } else { + ResultPtr aDocRes = ModelAPI_Tools::findPartResult( + ModelAPI_Session::get()->moduleDocument(), theContext->document()); + if (aDocRes.get()) { + aResult = aDocRes->data()->name() + "/"; + } + } + } + aResult += theContext->data()->name(); + return aResult; +} + +void Model_AttributeSelection::updateInHistory() +{ + ResultPtr aContext = std::dynamic_pointer_cast(myRef.value()); + // only bodies may be modified later in the history, don't do anything otherwise + if (!aContext.get() || aContext->groupName() != ModelAPI_ResultBody::group()) + return; + std::shared_ptr aContData = std::dynamic_pointer_cast(aContext->data()); + if (!aContData.get() || !aContData->isValid()) + return; + TDF_Label aContLab = aContData->label(); // named shape where the selected context is located + Handle(TNaming_NamedShape) aContNS; + if (!aContLab.FindAttribute(TNaming_NamedShape::GetID(), aContNS)) + return; + std::shared_ptr aDoc = + std::dynamic_pointer_cast(aContext->document()); + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + FeaturePtr aCurrentModifierFeat = aDoc->feature(aContext); + // iterate the context shape modifications in order to find a feature that is upper in history + // that this one and is really modifies the referenced result to refer to it + ResultPtr aModifierResFound; + TNaming_Iterator aPairIter(aContNS); + TopoDS_Shape aNewShape = aPairIter.NewShape(); + bool anIterate = true; + // trying to update also the sub-shape selected + GeomShapePtr aSubShape = value(); + if (aSubShape.get() && aSubShape->isEqual(aContext->shape())) + aSubShape.reset(); + + while(anIterate) { + anIterate = false; + TNaming_SameShapeIterator aModifIter(aNewShape, aContLab); + for(; aModifIter.More(); aModifIter.Next()) { + ResultPtr aModifierObj = std::dynamic_pointer_cast + (aDoc->objects()->object(aModifIter.Label().Father())); + if (!aModifierObj.get()) + break; + FeaturePtr aModifierFeat = aDoc->feature(aModifierObj); + if (!aModifierFeat.get()) + break; + if (aModifierFeat == aThisFeature || aDoc->objects()->isLater(aModifierFeat, aThisFeature)) + continue; // the modifier feature is later than this, so, should not be used + if (aCurrentModifierFeat == aModifierFeat || + aDoc->objects()->isLater(aCurrentModifierFeat, aModifierFeat)) + continue; // the current modifier is later than the found, so, useless + Handle(TNaming_NamedShape) aNewNS; + aModifIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNewNS); + if (aNewNS->Evolution() == TNaming_MODIFY || aNewNS->Evolution() == TNaming_GENERATED) { + aModifierResFound = aModifierObj; + aCurrentModifierFeat = aModifierFeat; + TNaming_Iterator aPairIter(aNewNS); + aNewShape = aPairIter.NewShape(); + /* + // searching for sub-shape equivalent on the sub-label of the new context result + TDF_ChildIDIterator aNSIter(aNewNS->Label(), TNaming_NamedShape::GetID()); + for(; aNSIter.More(); aNSIter.Next()) { + TNaming_Iterator aPairsIter(aNSIter.Value()->Label()); + for(; aPairsIter.More(); aPairsIter.Next()) { + if (aSubShape->impl().IsEqual() + } + }*/ + anIterate = true; + break; + } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is null + ResultPtr anEmptyContext; + std::shared_ptr anEmptyShape; + setValue(anEmptyContext, anEmptyShape); // nullify the selection + return; + } else { // not-precessed modification => don't support it + continue; + } + } + + /* + TNaming_NewShapeIterator aModifIter(aPairIter.NewShape(), aContLab); + if (aModifIter.More()) aModifIter.Next(); // skip this shape result + for(; aModifIter.More(); aModifIter.Next()) { + ResultPtr aModifierObj = std::dynamic_pointer_cast + (aDoc->objects()->object(aModifIter.Label().Father())); + if (!aModifierObj.get()) + break; + FeaturePtr aModifierFeat = aDoc->feature(aModifierObj); + if (!aModifierFeat.get()) + break; + if (aModifierFeat == aThisFeature || aDoc->objects()->isLater(aModifierFeat, aThisFeature)) + break; // the modifier feature is later than this, so, should not be used + Handle(TNaming_NamedShape) aNewNS = aModifIter.NamedShape(); + if (aNewNS->Evolution() == TNaming_MODIFY || aNewNS->Evolution() == TNaming_GENERATED) { + aModifierResFound = aModifierObj; + } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is null + ResultPtr anEmptyContext; + std::shared_ptr anEmptyShape; + setValue(anEmptyContext, anEmptyShape); // nullify the selection + return; + } else { // not-precessed modification => don't support it + break; + } + } + // already found what is needed, don't iterate the next pair since normally + if (aModifierResFound.get()) // there must be only one pair in the result-shape + break; + */ + } + if (aModifierResFound.get()) { + // update scope to reset to a new one + myScope.Clear(); + myRef.setValue(aModifierResFound); + update(); // it must recompute a new sub-shape automatically + } + /* + if (aModifierResFound.get()) { + // update scope to reset to a new one + myScope.Clear(); + if (!aSubShape.get() || aSubShape->isNull()) { // no sub-shape, so, just update a context + setValue(aModifierResFound, aSubShape); + return; + } + // seaching for the same sub-shape: the old topology stays the same + TopoDS_Shape anOldShape = aSubShape->impl(); + TopAbs_ShapeEnum aSubType = anOldShape.ShapeType(); + TopoDS_Shape aNewContext = aModifierResFound->shape()->impl(); + TopExp_Explorer anExp(aNewContext, aSubType); + for(; anExp.More(); anExp.Next()) { + if (anExp.Current().IsEqual(anOldShape)) + break; + } + if (anExp.More()) { // found + setValue(aModifierResFound, aSubShape); + return; + } + // seaching for the same sub-shape: equal geometry + for(anExp.Init(aNewContext, aSubType); anExp.More(); anExp.Next()) { + if (aSubType == TopAbs_VERTEX) { + + } + } + }*/ + // if sub-shape selection exists, search also sub-shape new instance + /* + GeomShapePtr aSubShape = value(); + if (aSubShape.get() && aSubShape != aContext->shape()) { + + }*/ +}