X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=d35ea9cee6f24cfb6bf52730b097b95c56fcd824;hb=471cc7b52168016a3b6fff7e64cdd800cd7d8f91;hp=f3f4d27a3c46d34ea92dfa5c3577716004bee615;hpb=5c95c92510111cb79b244390964240d966efb1c4;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index f3f4d27a3..d35ea9cee 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -15,9 +15,10 @@ #include #include #include +#include #include #include -#include +#include #include #include @@ -54,12 +55,15 @@ #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 @@ -68,6 +72,8 @@ Standard_GUID kSIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb29"); 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 +Standard_GUID kINVALID_SELECTION("bce47fd7-80fa-4462-9d63-2f58acddd49d"); // on this label is stored: // TNaming_NamedShape - selected shape @@ -76,21 +82,33 @@ Standard_GUID kPART_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb27"); // TDataStd_Integer - type of the selected shape (for construction) // TDF_Reference - from ReferenceAttribute, the context void Model_AttributeSelection::setValue(const ResultPtr& theContext, - const std::shared_ptr& theSubShape) + const std::shared_ptr& theSubShape, const bool theTemporarily) { + if (theTemporarily) { // just keep the stored without DF update + myTmpContext = theContext; + myTmpSubShape = theSubShape; + owner()->data()->sendAttributeUpdated(this); + return; + } else { + myTmpContext.reset(); + myTmpSubShape.reset(); + } + const std::shared_ptr& anOldShape = value(); bool isOldContext = theContext == myRef.value(); bool isOldShape = isOldContext && (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(); aSelLab.ForgetAttribute(kSIMPLE_REF_ID); aSelLab.ForgetAttribute(kCONSTUCTION_SIMPLE_REF_ID); + aSelLab.ForgetAttribute(kINVALID_SELECTION); bool isDegeneratedEdge = false; // do not use the degenerated edge as a shape, a null context and shape is used in the case @@ -109,7 +127,6 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, if (theContext->groupName() == ModelAPI_ResultBody::group()) { // do not select the whole shape for body:it is already must be in the data framework // equal and null selected objects mean the same: object is equal to context, - // TODO: synchronize with GUI later that it must be null always if (theContext->shape().get() && (theContext->shape()->isEqual(theSubShape) || !theSubShape.get())) { aSelLab.ForgetAllAttributes(true); @@ -122,6 +139,31 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, // 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); } @@ -142,9 +184,21 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, std::shared_ptr Model_AttributeSelection::value() { - std::shared_ptr aResult; + GeomShapePtr aResult; + if (myTmpContext.get() || myTmpSubShape.get()) { + ResultConstructionPtr aResulConstruction = std::dynamic_pointer_cast(myTmpContext); + if(aResulConstruction.get()) { + // it is just reference to construction. + return myTmpSubShape; + } + return myTmpSubShape.get() ? myTmpSubShape : myTmpContext->shape(); + } + + TDF_Label aSelLab = selectionLabel(); + if (aSelLab.IsAttribute(kINVALID_SELECTION)) + return aResult; + if (myRef.isInitialized()) { - TDF_Label aSelLab = selectionLabel(); if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape ResultPtr aContext = context(); if (!aContext.get()) @@ -155,20 +209,27 @@ 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 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).ToCString()); - */ } Handle(TNaming_NamedShape) aSelection; @@ -187,9 +248,14 @@ std::shared_ptr Model_AttributeSelection::value() return aResult; } +bool Model_AttributeSelection::isInvalid() +{ + return selectionLabel().IsAttribute(kINVALID_SELECTION) == Standard_True; +} + 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(); @@ -229,6 +295,10 @@ void Model_AttributeSelection::setID(const std::string theID) } ResultPtr Model_AttributeSelection::context() { + if (myTmpContext.get() || myTmpSubShape.get()) { + return myTmpContext; + } + ResultPtr aResult = std::dynamic_pointer_cast(myRef.value()); // for parts there could be same-data result, so take the last enabled if (aResult.get() && aResult->groupName() == ModelAPI_ResultPart::group()) { @@ -258,13 +328,39 @@ 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(); + bool aMePassed = false; + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(owner()); + FeaturePtr aFeature = std::dynamic_pointer_cast(owner()); + CompositeFeaturePtr aCompositeOwner, aCompositeOwnerOwner; + if (aFeature.get()) { + aCompositeOwner = ModelAPI_Tools::compositeOwner(aFeature); + if (aCompositeOwner.get()) { + aCompositeOwnerOwner = ModelAPI_Tools::compositeOwner(aCompositeOwner); + } + } + // for group Scope is not limitet: this is always up to date objects + bool isGroup = aFeature.get() && aFeature->getKind() == "Group"; for(; aFIter != allFeatures.end(); aFIter++) { - if (*aFIter == owner()) break; // the left features are created later - if (aFIter->get() && (*aFIter)->data()->isValid()) { + if (*aFIter == owner()) { // the left features are created later (except subs of composite) + aMePassed = true; + continue; + } + if (isGroup) aMePassed = false; + bool isInScope = !aMePassed; + if (!isInScope && aComposite.get()) { // try to add sub-elements of composite if this is composite + if (aComposite->isSub(*aFIter)) + isInScope = true; + } + // remove the composite-owner of this feature (sketch in extrusion-cut) + if (isInScope && (aCompositeOwner == *aFIter || aCompositeOwnerOwner == *aFIter)) + isInScope = false; + + 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); @@ -280,40 +376,70 @@ 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) { + if (theFlag) { + theLab.ForgetAttribute(kINVALID_SELECTION); + } else { + TDataStd_UAttribute::Set(theLab, kINVALID_SELECTION); + } + return theFlag; } bool Model_AttributeSelection::update() { - ResultPtr aContext = context(); - if (!aContext.get()) return false; TDF_Label aSelLab = selectionLabel(); + ResultPtr aContext = context(); + if (!aContext.get()) + return setInvalidIfFalse(aSelLab, false); if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape - return aContext->shape() && !aContext->shape()->isNull(); + return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull()); } if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { // it is just reference to construction, not sub-shape - return aContext->shape() && !aContext->shape()->isNull(); + // 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()); + 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 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); bool aResult = aSelector.Solve(scope()) == Standard_True; + aResult = setInvalidIfFalse(aSelLab, aResult); // must be before sending of updated attribute (1556) owner()->data()->sendAttributeUpdated(this); return aResult; } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { @@ -330,7 +456,7 @@ bool Model_AttributeSelection::update() // getting a type of selected shape Handle(TDataStd_Integer) aTypeAttr; if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) { - return false; + return setInvalidIfFalse(aSelLab, false); } TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get()); // selected indexes will be needed in each "if" @@ -342,19 +468,19 @@ bool Model_AttributeSelection::update() CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aContextFeature); if (!aComposite.get() || aComposite->numberOfSubs() == 0) { - return false; + 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 false; + 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 resut for the fast searching + // prepare edges of the current result for the fast searching NCollection_DataMap allCurves; // curves and orientations of edges const int aSubNum = aComposite->numberOfSubs(); for(int a = 0; a < aSubNum; a++) { @@ -384,51 +510,23 @@ bool Model_AttributeSelection::update() } } } - double aBestFound = 0; // best percentage of found edges - 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) { - double aSum = aFound + aNotFound; - // aSameOrientation: if edges are same, take where orientation is better - double aPercentage = double(aFound) / double(aFound + aNotFound); - if (aPercentage > aBestFound || - (aPercentage == aBestFound && aSameOrientation > aBestOrient)) { - aBestFound = aPercentage; - aBestOrient = aSameOrientation; - aNewSelected = aConstructionContext->face(aFaceIndex); - } - } - } + aNewSelected = Model_SelectionNaming::findAppropriateFace(aContext, allCurves); } if (aNewSelected) { // store this new selection + if (aShapeType == TopAbs_WIRE) { // just get a wire from face to have wire + TopExp_Explorer aWireExp(aNewSelected->impl(), TopAbs_WIRE); + if (aWireExp.More()) { + aNewSelected.reset(new GeomAPI_Shape); + aNewSelected->setImpl(new TopoDS_Shape(aWireExp.Current())); + } + } 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 @@ -445,6 +543,7 @@ 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 true; } @@ -474,6 +573,7 @@ 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 true; } else if (aRes->shape()->isEdge() && aVertexNum > 0) { @@ -484,6 +584,7 @@ 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 true; } @@ -497,11 +598,12 @@ 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 true; } } - return false; // unknown case + return setInvalidIfFalse(aSelLab, false); // unknown case } @@ -521,17 +623,15 @@ 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; /// 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); } @@ -545,6 +645,7 @@ void Model_AttributeSelection::selectBody( 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& theSubNames, // name of sub-elements by ID to be exported instead of indexes Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)(), const int theOrientation = 0) { @@ -555,28 +656,44 @@ 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<<"-"<document()) { + if (theContextFeature->document() == ModelAPI_Session::get()->moduleDocument()) { + aName<document()->kind()<<"/"; + } else { + ResultPtr aDocRes = ModelAPI_Tools::findPartResult( + ModelAPI_Session::get()->moduleDocument(), theContextFeature->document()); + if (aDocRes.get()) { + aName<data()->name()<<"/"; + } + } + } + aName<name(); + if (theShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction + aName<<"/"; + if (!theAdditionalName.empty()) + 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); @@ -623,6 +741,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++) { @@ -642,14 +761,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; @@ -665,7 +787,8 @@ void Model_AttributeSelection::selectConstruction( if (allCurves.Contains(aCurve)) { int anID = aComposite->subFeatureId(a); aRefs->Add(anID); - if (aShapeType != TopAbs_EDGE) { // face nneds the sub-edges on sub-labels + 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()) { @@ -673,11 +796,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); + aSubNames, Handle(TDataStd_IntPackedMap)(), anOrient); } } } else { // put vertices of the selected edge to sub-labels @@ -689,7 +812,8 @@ void Model_AttributeSelection::selectConstruction( std::stringstream anAdditionalName; registerSubShape( - selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc, "", anOrientations); + selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc, "", anOrientations, + aSubNames); } } } @@ -702,7 +826,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( @@ -724,10 +848,10 @@ 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->isNull()) {// the whole part shape is selected + if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected aShape = theContext->shape()->impl(); } else { aShape = theSubShape->impl(); @@ -771,6 +895,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()); @@ -783,17 +925,87 @@ void Model_AttributeSelection::selectSubShape( int Model_AttributeSelection::Id() { + int anID = 0; std::shared_ptr aSelection = value(); std::shared_ptr aContext = context()->shape(); - const TopoDS_Shape& aMainShape = aContext->impl(); + // 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(); - int anID = 0; + // searching for the latest main shape if (aSelection && !aSelection->isNull() && aContext && !aContext->isNull()) { + std::shared_ptr aDoc = + std::dynamic_pointer_cast(context()->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); anID = aSubShapesMap.FindIndex(aSubShape); } 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; +}