From c4b3da21ddaf1e1f1763da7faefe54372aa38325 Mon Sep 17 00:00:00 2001 From: mpv Date: Wed, 17 Oct 2018 13:38:03 +0300 Subject: [PATCH] Debug of the selector filter by neighbors and make sketch results stored in the data tree. --- .../ConstructionPlugin_Point.cpp | 1 + src/GeomAPI/GeomAPI_PlanarEdges.cpp | 2 + src/Model/Model_AttributeSelection.cpp | 154 +-- src/Model/Model_BodyBuilder.cpp | 69 -- src/Model/Model_BodyBuilder.h | 4 - src/Model/Model_Data.h | 4 +- src/Model/Model_Objects.cpp | 11 +- src/Model/Model_ResultBody.cpp | 1 - src/Model/Model_ResultConstruction.cpp | 991 +++++------------- src/Model/Model_ResultConstruction.h | 44 +- src/ModelAPI/ModelAPI_BodyBuilder.h | 4 - src/ModelAPI/ModelAPI_ResultConstruction.h | 4 + src/Selector/CMakeLists.txt | 2 + src/Selector/Selector_NExplode.cpp | 173 +++ src/Selector/Selector_NExplode.h | 49 + src/Selector/Selector_Selector.cpp | 133 ++- src/Selector/Selector_Selector.h | 8 +- src/SketchPlugin/SketchPlugin_Feature.h | 3 - src/SketchPlugin/SketchPlugin_Sketch.h | 3 - 19 files changed, 656 insertions(+), 1004 deletions(-) create mode 100644 src/Selector/Selector_NExplode.cpp create mode 100644 src/Selector/Selector_NExplode.h diff --git a/src/ConstructionPlugin/ConstructionPlugin_Point.cpp b/src/ConstructionPlugin/ConstructionPlugin_Point.cpp index bb59c3d55..8f4f8fc62 100644 --- a/src/ConstructionPlugin/ConstructionPlugin_Point.cpp +++ b/src/ConstructionPlugin/ConstructionPlugin_Point.cpp @@ -143,6 +143,7 @@ void ConstructionPlugin_Point::execute() removeResults(1); // for case the point type was switched from multi-results type std::shared_ptr aConstr = document()->createConstruction(data()); + aConstr->setInfinite(true); aConstr->setShape(aShape); setResult(aConstr); } diff --git a/src/GeomAPI/GeomAPI_PlanarEdges.cpp b/src/GeomAPI/GeomAPI_PlanarEdges.cpp index fa4686de7..dbc6e498a 100644 --- a/src/GeomAPI/GeomAPI_PlanarEdges.cpp +++ b/src/GeomAPI/GeomAPI_PlanarEdges.cpp @@ -122,6 +122,8 @@ bool GeomAPI_PlanarEdges::isEqual(const std::shared_ptr theShape) return false; TopoDS_Shape& aMyShape = const_cast(impl()); TopoDS_Shape aTheShape = theShape->impl(); + if (aMyShape.ShapeType() != aTheShape.ShapeType()) // to don't confuse by the face of same edges + return false; TopExp_Explorer aMyExp(aMyShape, TopAbs_EDGE); TopExp_Explorer aTheExp(aTheShape, TopAbs_EDGE); for (; aMyExp.More() && aTheExp.More(); aMyExp.Next(), aTheExp.Next()) { diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 3aa4ffeaa..b4739045f 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -158,34 +158,36 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext, owner()->data()->blockSendAttributeUpdated(false); return false; } - if (theContext->groupName() == ModelAPI_ResultBody::group()) { - ResultBodyPtr aContextBody = std::dynamic_pointer_cast(theContext); + bool isSelectBody = theContext->groupName() == ModelAPI_ResultBody::group(); + if (!isSelectBody) { + ResultConstructionPtr aContextConstruction = + std::dynamic_pointer_cast(theContext); + isSelectBody = aContextConstruction.get() && !aContextConstruction->isInfinite(); + } + if (isSelectBody) { + ResultPtr aContextResult = std::dynamic_pointer_cast(theContext); + GeomShapePtr aContextShape = aContextResult->shape(); // 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, - if (aContextBody->shape().get() && - (aContextBody->shape()->isEqual(theSubShape) || !theSubShape.get())) { + if (aContextShape.get() && (aContextShape->isEqual(theSubShape) || !theSubShape.get())) { aSelLab.ForgetAllAttributes(true); TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID); } else { - selectBody(aContextBody, theSubShape); + selectBody(aContextResult, theSubShape); } } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) { - ResultConstructionPtr aContextConstruction = - std::dynamic_pointer_cast(theContext); aSelLab.ForgetAllAttributes(true); // to remove old selection data std::shared_ptr aConstruction = std::dynamic_pointer_cast(theContext); std::shared_ptr aSubShape; - if (theSubShape.get() && !aContextConstruction->shape()->isEqual(theSubShape)) + if (theSubShape.get() && !aConstruction->shape()->isEqual(theSubShape)) aSubShape = theSubShape; // the whole context 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. + // It seems sub-shapes are not needed: only this shape is (and can be) selected. TNaming_Builder aBuilder(aSelLab); - aBuilder.Generated(aContextConstruction->shape()->impl()); + aBuilder.Generated(aConstruction->shape()->impl()); } - 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); @@ -422,12 +424,7 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp aResult = std::shared_ptr(new GeomAPI_Shape); aResult->setImpl(new TopoDS_Shape(aSelShape)); } else if (aConstr) { // simple construction element: just shape of this construction element - 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()); - } + aResult = aConstr->shape(); } } return aResult; @@ -455,11 +452,7 @@ bool Model_AttributeSelection::isInitialized() std::shared_ptr aConstr = std::dynamic_pointer_cast(context()); if (aConstr.get()) { - Handle(TDataStd_Integer) anIndex; - if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { - // for the whole shape it may return null, so, if index exists, returns true return true; - } } // for the whole feature, a feature object FeaturePtr aFeat = contextFeature(); @@ -725,22 +718,19 @@ bool Model_AttributeSelection::update() } if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { - 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 (aConstructionContext->isInfinite()) { - // Update the selected shape. - TNaming_Builder aBuilder(aSelLab); - aBuilder.Generated(aConstructionContext->shape()->impl()); + bool aResult = true; + std::shared_ptr aConstructionContext = + std::dynamic_pointer_cast(aContext); + if (!aConstructionContext->isInfinite()) { + Selector_Selector aSelector(aSelLab); + aResult = aSelector.restore(); + if (aResult) { + TopoDS_Shape aContextShape = aContext->shape()->impl(); + aResult = aSelector.solve(aContextShape); } - if (aModified) - owner()->data()->sendAttributeUpdated(this); - return aValid; + aResult = setInvalidIfFalse(aSelLab, aResult); } + return aResult; } return setInvalidIfFalse(aSelLab, false); // unknown case } @@ -751,7 +741,7 @@ void Model_AttributeSelection::selectBody( // perform the selection TopoDS_Shape aContext; - ResultBodyPtr aBody = std::dynamic_pointer_cast(theContext);//myRef.value() + ResultPtr aBody = std::dynamic_pointer_cast(theContext);//myRef.value() if (aBody) { aContext = aBody->shape()->impl(); } else { @@ -766,67 +756,8 @@ void Model_AttributeSelection::selectBody( } // 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().IsSame(aNewSub)) { - isFound = true; - break; - } - } - if (!isFound) { // sub-shape is not found in the up-to-date instance of the context shape - // if context is sub-result of compound/compsolid, selection of sub-shape better propagate to - // the main result (which is may be modified); the case is in 1799 - ResultBodyPtr aMain = ModelAPI_Tools::bodyOwner(theContext); - while(ModelAPI_Tools::bodyOwner(aMain).get()) - aMain = ModelAPI_Tools::bodyOwner(theContext); - if (aMain.get()) { - selectBody(aMain, theSubShape); - return; - } - 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 if (!aContext.IsNull()) { @@ -842,10 +773,10 @@ void Model_AttributeSelection::selectBody( Selector_Selector aSel(aSelLab); try { //aSel.Select(aNewSub, aNewContext); - aSelectorOk = aSel.select(aNewContext, aNewSub); + aSelectorOk = aSel.select(aContext, aNewSub); if (aSelectorOk) { aSel.store(); - aSelectorOk = aSel.solve(aNewContext); + aSelectorOk = aSel.solve(aContext); } } catch(...) { aSelectorOk = false; @@ -865,7 +796,7 @@ void Model_AttributeSelection::selectBody( } if (!aSelectorOk) { // weak naming identifier instead GeomShapePtr aContextShape(new GeomAPI_Shape); - aContextShape->setImpl(new TopoDS_Shape(aNewContext)); + aContextShape->setImpl(new TopoDS_Shape(aContext)); GeomShapePtr aValueShape(new GeomAPI_Shape); aValueShape->setImpl(new TopoDS_Shape(aNewSub)); @@ -964,13 +895,25 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa } TDF_Label aSelLab = selectionLabel(); + if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value + return contextName(aCont); + } + Handle(TDataStd_Integer) aWeakId; if (aSelLab.FindAttribute(kWEAK_NAMING, aWeakId)) { // a weak naming is used std::ostringstream aNameStream; - aNameStream<data()->name()<<"/weak_name_"<Get(); + aNameStream<Get(); return aNameStream.str(); } + // whole infinitive construction + if (aCont->groupName() == ModelAPI_ResultConstruction::group()) { + ResultConstructionPtr aConstr = std::dynamic_pointer_cast(aCont); + if (aConstr->isInfinite()) { + return contextName(aCont); + } + } + Selector_Selector aSelector(aSelLab); std::string aResult; if (aSelector.restore()) @@ -1722,8 +1665,17 @@ std::string Model_AttributeSelection::contextName(const TDF_Label theSelectionLa std::shared_ptr aDoc = std::dynamic_pointer_cast(aMyDoc); FeaturePtr aFeatureOwner = aDoc->featureByLab(theSelectionLab); if (aFeatureOwner.get()) { + // if it is sub-element of the sketch, the context name is the name of the sketch // searching also for result - real context - ResultPtr aResult = aDoc->resultByLab(theSelectionLab); + ResultPtr aResult; + FeaturePtr aComposite = ModelAPI_Tools::compositeOwner(aFeatureOwner); + if (aComposite.get() && aComposite->results().size() == 1 && + aComposite->firstResult()->groupName() == ModelAPI_ResultConstruction::group()) { + aFeatureOwner = aComposite; + aResult = aFeatureOwner->firstResult(); + } else { + aResult = aDoc->resultByLab(theSelectionLab); + } if (aResult.get()) { // this is to avoid duplicated names of results problem std::string aContextName = aResult->data()->name(); diff --git a/src/Model/Model_BodyBuilder.cpp b/src/Model/Model_BodyBuilder.cpp index c17c9b8d5..370ce2ad1 100755 --- a/src/Model/Model_BodyBuilder.cpp +++ b/src/Model/Model_BodyBuilder.cpp @@ -133,75 +133,6 @@ Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner) { } -// Converts evolution of naming shape to selection evelution and back to avoid -// naming support on the disabled results. Deeply in the labels tree, recursively. -static void evolutionToSelectionRec(TDF_Label theLab, const bool theFlag) { - std::list > aShapePairs; // to store old and new shapes - Handle(TNaming_NamedShape) aName; - int anEvolution = -1; - if (theLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) { - TNaming_Evolution aNSEvol = aName->Evolution(); - if ((aNSEvol == TNaming_SELECTED && theFlag) || - (aNSEvol != TNaming_SELECTED && !theFlag)) { // nothing to do, it is already correct - return; - } - anEvolution = (int)(aNSEvol); - if (!theFlag) { - Handle(TDataStd_Integer) anAttrEvol; - if (theLab.FindAttribute(TDataStd_Integer::GetID(), anAttrEvol)) { - anEvolution = anAttrEvol->Get(); - } - } else { - TDataStd_Integer::Set(theLab, anEvolution); - } - - for(TNaming_Iterator anIter(aName); anIter.More(); anIter.Next()) { - // iterator goes in reversed order relatively to the Builder, to, make the list reversed - aShapePairs.push_front(std::pair - (anIter.OldShape(), anIter.NewShape())); - } - - // create new - TNaming_Builder aBuilder(theLab); - TNaming_Evolution anEvol = (TNaming_Evolution)(anEvolution); - std::list >::iterator aPairsIter = aShapePairs.begin(); - for(; aPairsIter != aShapePairs.end(); aPairsIter++) { - if (theFlag) { // disabled => make selection - if (anEvolution == TNaming_DELETE) // issue 2274 : don't put too many same null shapes - aBuilder.Select(aPairsIter->first, aPairsIter->first); - else if (anEvolution == TNaming_PRIMITIVE) - aBuilder.Select(aPairsIter->second, aPairsIter->second); - else - aBuilder.Select(aPairsIter->second, aPairsIter->first); - } else if (anEvol == TNaming_GENERATED) { - aBuilder.Generated(aPairsIter->first, aPairsIter->second); - } else if (anEvol == TNaming_MODIFY) { - aBuilder.Modify(aPairsIter->first, aPairsIter->second); - } else if (anEvol == TNaming_DELETE) { - aBuilder.Delete(aPairsIter->first); - } else if (anEvol == TNaming_PRIMITIVE) { - aBuilder.Generated(aPairsIter->second); - } else if (anEvol == TNaming_SELECTED) { - aBuilder.Select(aPairsIter->second, aPairsIter->first); - } - } - } - // recursive call for all sub-labels - TDF_ChildIterator anIter(theLab, Standard_False); - for(; anIter.More(); anIter.Next()) { - evolutionToSelectionRec(anIter.Value(), theFlag); - } -} - -void Model_BodyBuilder::evolutionToSelection(const bool theFlag) -{ - std::shared_ptr aData = std::dynamic_pointer_cast(data()); - if (!aData || !aData->isValid()) // unknown case - return; - TDF_Label& aShapeLab = aData->shapeLab(); - evolutionToSelectionRec(aShapeLab, theFlag); -} - void Model_BodyBuilder::store(const GeomShapePtr& theShape, const bool theIsStoreSameShapes) { diff --git a/src/Model/Model_BodyBuilder.h b/src/Model/Model_BodyBuilder.h index 0217fb3a7..ab82e48b2 100755 --- a/src/Model/Model_BodyBuilder.h +++ b/src/Model/Model_BodyBuilder.h @@ -128,10 +128,6 @@ public: /// Removes the stored builders MODEL_EXPORT virtual ~Model_BodyBuilder(); - /// Converts evolution of sub-shapes stored in naming structure to selection - /// (theFlag = true) and back (theFlag = false) - MODEL_EXPORT virtual void evolutionToSelection(const bool theFlag); - /// Returns true if the latest modification of this body in the naming history // is equal to the given shape MODEL_EXPORT virtual bool isLatestEqual(const GeomShapePtr& theShape); diff --git a/src/Model/Model_Data.h b/src/Model/Model_Data.h index 598193cb8..e2a6a7994 100644 --- a/src/Model/Model_Data.h +++ b/src/Model/Model_Data.h @@ -172,9 +172,9 @@ class Model_Data : public ModelAPI_Data MODEL_EXPORT virtual bool isValid(); /// Returns the label where the shape must be stored (used in ResultBody) - TDF_Label& shapeLab() + TDF_Label shapeLab() { - return myLab; + return myLab.IsNull() ? myLab : myLab.Father().FindChild(2); } /// Initializes object by the attributes: must be called just after the object is created diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 6fc21e71e..dc1067ec6 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -1840,8 +1840,6 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set& t } } - // for not persistent is will be done by parametric updater automatically - //if (!theFeature->isPersistentResult()) return; // check the existing results and remove them if there is nothing on the label std::list::const_iterator aResIter = theFeature->results().cbegin(); while(aResIter != theFeature->results().cend()) { @@ -1881,10 +1879,11 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set& t // create the part result: it is better to restore the previous result if it is possible theFeature->execute(); } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) { - theFeature->execute(); // construction shapes are needed for sketch solver - if (!theFeature->results().empty()) // to fix #2640 : update sketch, but not naming - std::dynamic_pointer_cast(theFeature->firstResult()) - ->facesNum(false); + ResultConstructionPtr aConstr = createConstruction(theFeature->data(), aResIndex); + if (!aConstr->updateShape()) + theFeature->execute(); // not stored shape in the data structure, execute to have it + else + theFeature->setResult(aConstr, aResIndex); // result is ready without execution } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) { aNewBody = createGroup(theFeature->data(), aResIndex); } else if (aGroup->Get() == ModelAPI_ResultField::group().c_str()) { diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index 746bbd792..7c7171ddd 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -124,7 +124,6 @@ bool Model_ResultBody::setDisabled(std::shared_ptr theThis, con { bool aChanged = ModelAPI_ResultBody::setDisabled(theThis, theFlag); if (aChanged) { // state is changed, so modifications are needed - myBuilder->evolutionToSelection(theFlag); updateSubs(shape(), false); // to set disabled/enabled } return aChanged; diff --git a/src/Model/Model_ResultConstruction.cpp b/src/Model/Model_ResultConstruction.cpp index 1d0c715c7..07fa23825 100644 --- a/src/Model/Model_ResultConstruction.cpp +++ b/src/Model/Model_ResultConstruction.cpp @@ -22,16 +22,17 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include +#include #include #include #include @@ -46,12 +47,16 @@ #include #include #include +#include #include #include #include +#include -// identifier that it is full result selected, but in external document (for internal index is 0) -Standard_GUID kFULL_RESULT_ID("ee87e529-da6f-46af-be25-5e0fefde52f7"); +// identifier of the infinite result +Standard_GUID kIS_INFINITE("dea8cc5a-53f2-49c1-94e8-a947bed20a9f"); +// identifier of the result not in history +Standard_GUID kIS_IN_HISTORY("a9aec01c-805e-44d1-b5d2-a63f06522f8a"); void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName, @@ -65,14 +70,10 @@ void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::str void Model_ResultConstruction::setShape(std::shared_ptr theShape) { if (myShape != theShape) { - if (!theShape.get() || !theShape->isEqual(myShape)) { - static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent); - if (theShape.get()) { - myFacesUpToDate = false; - myFaces.clear(); - } - } + if (!isInfinite()) + storeShape(theShape); + static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent); myShape = theShape; } } @@ -82,803 +83,305 @@ std::shared_ptr Model_ResultConstruction::shape() return myShape; } -Model_ResultConstruction::Model_ResultConstruction() -{ - myIsInHistory = true; - myIsInfinite = false; - myFacesUpToDate = false; -} - -void Model_ResultConstruction::setIsInHistory(const bool isInHistory) -{ - myIsInHistory = isInHistory; -} - -int Model_ResultConstruction::facesNum(const bool theUpdateNaming) +bool Model_ResultConstruction::updateShape() { - if (!myFacesUpToDate) { - std::shared_ptr aWirePtr = - std::dynamic_pointer_cast(myShape); - if (aWirePtr.get()) { - std::list > aFaces; - GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(), - aWirePtr->norm(), aWirePtr, aFaces); - std::list >::iterator aFIter = aFaces.begin(); - for(; aFIter != aFaces.end(); aFIter++) { - std::shared_ptr aFace(new GeomAPI_Face(*aFIter)); - if (aFace.get() && !aFace->isNull()) - myFaces.push_back(aFace); - } - } - myFacesUpToDate = true; - - // update all the faces and sub-elements in the naming structure - if (theUpdateNaming) { - DocumentPtr anEmptyExt; - bool aNotExt = false; - TDF_Label aDataLab = startLabel(anEmptyExt, aNotExt); - 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)) { - update(aLab.Tag() - 1, anEmptyExt, aNotExt); - } + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData && aData->isValid()) { + TDF_Label& aShapeLab = aData->shapeLab(); + Handle(TNaming_NamedShape) aNS; + if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + TopoDS_Shape aShape = aNS->Get(); + if (!aShape.IsNull()) { + GeomShapePtr aGShape(new GeomAPI_Shape); + aGShape->setImpl(new TopoDS_Shape(aShape)); + myShape = aGShape; // restore the sketch sub-components + return true; } } } - return int(myFaces.size()); + return false; } -std::shared_ptr Model_ResultConstruction::face(const int theIndex) +Model_ResultConstruction::Model_ResultConstruction() { - return myFaces[theIndex]; } -bool Model_ResultConstruction::isInfinite() -{ - return myIsInfinite; -} -void Model_ResultConstruction::setInfinite(const bool theInfinite) +bool Model_ResultConstruction::isInHistory() { - myIsInfinite = theInfinite; + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData.get() && aData->isValid()) { + return !aData->label().IsAttribute(kIS_IN_HISTORY); // by default no attribute, but in history + } + return true; // unknown case } -void Model_ResultConstruction::setIsConcealed(const bool theValue) +void Model_ResultConstruction::setIsInHistory(const bool isInHistory) { - // do nothing: the construction element is never concealed + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData.get() && aData->isValid()) { + if (!isInHistory) + TDataStd_UAttribute::Set(aData->label(), kIS_IN_HISTORY); + else + aData->label().ForgetAttribute(kIS_IN_HISTORY); + } } -static const int kSTART_VERTEX_DELTA = 1000000; - -static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, std::string theFullName, - const int theID, std::shared_ptr theDoc, - bool theSelectionMode) +bool Model_ResultConstruction::isInfinite() { - TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID); - TNaming_Builder aBuilder(aLab); - // wire never happens as sub, it must be generated to be found - // by SelectionNaming TNaming_Tool::NamedShape - if (theSelectionMode && theShape.ShapeType() != TopAbs_WIRE) - aBuilder.Select(theShape, theShape); - else - aBuilder.Generated(theShape); - - theDoc->addNamingName(aLab, theFullName); - TDataStd_Name::Set(aLab, theFullName.c_str()); + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData.get() && aData->isValid()) { + return aData->label().IsAttribute(kIS_INFINITE); + } + return false; // unknown case } -#include - -// generates a full-name for sub-element of the composite feature (sketch) -std::string fullName(CompositeFeaturePtr theComposite, const TopoDS_Shape& theSubShape, - Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)()) +void Model_ResultConstruction::setInfinite(const bool theInfinite) { - TopAbs_ShapeEnum aShapeType = theSubShape.ShapeType(); - gp_Pnt aVertexPos; - NCollection_Map allExactEdges; - NCollection_DataMap allEdges; - NCollection_DataMap allCurves; - /// map from edges from theSubShape to the found corresponded indices of the sub-components - NCollection_DataMap, TopTools_OrientedShapeMapHasher> - anEdgesCorrespondence; - if (aShapeType == TopAbs_VERTEX) { // compare positions - aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(theSubShape)); - } else { - for(TopExp_Explorer anEdgeExp(theSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); - allExactEdges.Add(anEdge); - allEdges.Bind(anEdge, anEdge); - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - allCurves.Bind(aCurve, anEdge); - anEdgesCorrespondence.Bind(anEdge, NCollection_List()); - } - } - 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 - TColStd_PackedMapOfInteger aRefs; // indixes of sub-elements in composite - - - const int aSubNum = theComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - FeaturePtr aSub = theComposite->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(theComposite->subFeatureId(a)); - aSubNames[theComposite->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 + theComposite->subFeatureId(a)); - aSubNames[aDelta + theComposite->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()) - continue; - if (allEdges.IsBound(anEdge)) { - anEdgesCorrespondence.ChangeFind(allEdges.Find(anEdge)).Append(a); - } else { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (allCurves.IsBound(aCurve)) { - anEdgesCorrespondence.ChangeFind(allCurves.Find(aCurve)).Append(a); - } - } - } - } - } - } - - if (aShapeType != TopAbs_VERTEX) { // get best candidates from the correspondances - NCollection_DataMap, TopTools_OrientedShapeMapHasher> - ::Iterator aCorIter(anEdgesCorrespondence); - for(; aCorIter.More(); aCorIter.Next()) { - TopoDS_Edge anOrig = aCorIter.Key(); - NCollection_List::Iterator aCandidate(aCorIter.Value()); - int aBestScore = 0; - int aBestIndex = -1; - ResultConstructionPtr aBestConstr; - for(; aCandidate.More(); aCandidate.Next()) { - FeaturePtr aSub = theComposite->subFeature(aCandidate.Value()); - 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() || !aConstr->shape()->isEdge()) - continue; - const TopoDS_Shape& aResShape = aConstr->shape()->impl(); - TopoDS_Edge anEdge = TopoDS::Edge(aResShape); - if (anEdge.IsNull()) - continue; - // detect score of the candidate - int aScore = 0; - if (anEdge.IsEqual(anOrig)) - aScore = 10; - else if (anEdge.IsSame(anOrig)) - aScore = 9; - else { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) anOrigCurve = BRep_Tool::Curve(anOrig, aFirst, aLast); - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (anOrigCurve == aCurve) { - if (Model_EdgesHasher::IsEqual(anEdge, anOrig)) { - aScore = 8; - } else { - aScore = 6; - } - } else { - if (Model_EdgesHasher::IsEqual(anEdge, anOrig)) { - aScore = 7; - } else if (Model_CurvesHasher::IsEqual(aCurve, anOrigCurve)) { - aScore = 5; - } - } - } - if (aScore > aBestScore) { - aBestIndex = aCandidate.Value(); - aBestScore = aScore; - aBestConstr = aConstr; - } - } - } - if (aBestIndex >= 0) { - int anID = theComposite->subFeatureId(aBestIndex); - aRefs.Add(anID); - aSubNames[anID] = Model_SelectionNaming::shortName(aBestConstr); - if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels - // add edges to sub-label to support naming for edges selection - int anOrient = Model_SelectionNaming::edgeOrientation(theSubShape, anOrig); - anOrientations[anID] = anOrient; - } - } - } + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData.get() && aData->isValid()) { + if (theInfinite) + TDataStd_UAttribute::Set(aData->label(), kIS_INFINITE); + else + aData->label().ForgetAttribute(kIS_INFINITE); } - std::stringstream aName; - // #1839 : do not store name of the feature in the tree, since this name could be changed - if (theSubShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole construction result - if (theSubShape.ShapeType() == TopAbs_FACE) aName<<"Face"; - else if (theSubShape.ShapeType() == TopAbs_WIRE) aName<<"Wire"; - else if (theSubShape.ShapeType() == TopAbs_EDGE) aName<<"Edge"; - else if (theSubShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex"; +} - // make a composite name from all sub-elements indexes: "1_2_3_4" - TColStd_MapIteratorOfPackedMapOfInteger aRef(aRefs); - for(; aRef.More(); aRef.Next()) { - aName<<"-"< aData = std::dynamic_pointer_cast(data()); + if (aData.get() && aData->isValid()) { + TDF_Label& aShapeLab = aData->shapeLab(); + TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID()); + for (; anOldIter.More(); anOldIter.Next()) { + aResult++; } } - if (!theRefs.IsNull()) { - Handle(TColStd_HPackedMapOfInteger) aMap = new TColStd_HPackedMapOfInteger(aRefs); - theRefs->ChangeMap(aMap); - } - return aName.str(); + return aResult; } -// stores shape and name on sub-label of the main stored shape -static void saveSubName(CompositeFeaturePtr theComposite, - TDF_Label& theLab, const bool isSelectionMode, TopoDS_Shape aSub, - std::shared_ptr theDoc, std::string theFullName) +std::shared_ptr Model_ResultConstruction::face(const int theIndex) { - // trying to store the edge of composite result, not sketch sub as it is - if (aSub.ShapeType() == TopAbs_EDGE) { - ResultPtr aRes = theComposite->firstResult(); - ResultConstructionPtr aConstr = std::dynamic_pointer_cast(aRes); - if (aConstr.get()) { - Standard_Real aSubFirst, aSubLast; - TopoDS_Edge aSubEdge = TopoDS::Edge(aSub); - Handle(Geom_Curve) aSubCurve = BRep_Tool::Curve(aSubEdge, aSubFirst, aSubLast); - for(int aFaceIndex = 0; aFaceIndex < aConstr->facesNum(); aFaceIndex++) { - GeomShapePtr aGFace = aConstr->face(aFaceIndex); - TopoDS_Shape aFace = aGFace->impl(); - for(TopExp_Explorer anExp(aFace, TopAbs_EDGE); anExp.More(); anExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current()); - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (Model_CurvesHasher::IsEqual(aCurve, aSubCurve) && - ((fabs(aFirst - aSubFirst) < 1.e-9 && fabs(aLast - aSubLast) < 1.e-9)) || - (fabs(aFirst - aSubLast) < 1.e-9 && fabs(aLast - aSubFirst) < 1.e-9)) { - aSub = anEdge; - break; - } - } + std::shared_ptr aResult; + int anIndex = 0; + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData.get() && aData->isValid()) { + TDF_Label& aShapeLab = aData->shapeLab(); + TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID()); + for (; anOldIter.More(); anOldIter.Next()) { + if (anIndex == theIndex) { + Handle(TNaming_NamedShape) aNS; + anOldIter.Value()->Label().FindAttribute(TNaming_NamedShape::GetID(), aNS); + aResult.reset(new GeomAPI_Face); + aResult->setImpl(new TopoDS_Shape(aNS->Get())); + break; } + anIndex++; } } - - TNaming_Builder aBuilder(theLab); - if (isSelectionMode) - aBuilder.Select(aSub, aSub); - else - aBuilder.Generated(aSub); - theDoc->addNamingName(theLab, theFullName.c_str()); - TDataStd_Name::Set(theLab, theFullName.c_str()); + return aResult; } - -TDF_Label Model_ResultConstruction::startLabel( - const std::shared_ptr theExtDoc, bool& theExternal) +void Model_ResultConstruction::setIsConcealed(const bool theValue) { - 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(); + // do nothing: the construction element is never concealed } -int Model_ResultConstruction::select(const std::shared_ptr& theSubShape, - const std::shared_ptr theExtDoc, const int theIndex) +void Model_ResultConstruction::storeShape(std::shared_ptr theShape) { - 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 + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData && aData->isValid()) { + TDF_Label& aShapeLab = aData->shapeLab(); + if (!theShape.get() || theShape->isNull()) { + aShapeLab.ForgetAllAttributes(); + return; } - } else { - anIndex = theIndex + 1; - } - - // set the naming structure at index - TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True); - - // if the subshape is part of a result face, select the whole face (#1997) - bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label - if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) { - // but before check that sub-vertex correctly detected as intersection of sketch edges (#2389) - int anEdgesNum = 2; - if (aSubShape.ShapeType() == TopAbs_VERTEX) { - anEdgesNum = 0; + std::shared_ptr aMyDoc = + std::dynamic_pointer_cast(document()); + const TopoDS_Shape& aShape = theShape->impl(); + if (aShape.ShapeType() == TopAbs_VERTEX) { + aShapeLab.ForgetAllAttributes(); // clear all previously stored + TNaming_Builder aBuilder(aShapeLab); + aBuilder.Generated(aShape); + std::string aMyName = data()->name(); + TDataStd_Name::Set(aShapeLab, aMyName.c_str()); + aMyDoc->addNamingName(aShapeLab, aMyName); + } else if (aShape.ShapeType() == TopAbs_EDGE) { // store sub-vertices on sub-labels + aShapeLab.ForgetAllAttributes(); // clear all previously stored + TNaming_Builder aBuilder(aShapeLab); + aBuilder.Generated(aShape); + + TopExp_Explorer anExp(aShape, TopAbs_VERTEX); + for(int anIndex = 1; anExp.More(); anExp.Next(), anIndex++) { + TDF_Label aSubLab = aShapeLab.FindChild(anIndex);; + TNaming_Builder aBuilder(aSubLab); + aBuilder.Generated(anExp.Current()); + std::string aVertexName = anIndex == 1 ? "StartVertex" : "EndVertex"; + TDataStd_Name::Set(aSubLab, aVertexName.c_str()); + aMyDoc->addNamingName(aSubLab, aVertexName); + } + std::string aMyName = data()->name(); + TDataStd_Name::Set(aShapeLab, aMyName.c_str()); + aMyDoc->addNamingName(aShapeLab, aMyName); + } else { // this is probably sketch, so, work with it as with composite + std::shared_ptr aWirePtr = + std::dynamic_pointer_cast(theShape); + if (!aWirePtr.get()) + return; // unknown case ResultPtr aThisPtr = std::dynamic_pointer_cast(data()->owner()); - FeaturePtr aThisFeature = document()->feature(aThisPtr); + FeaturePtr aThisFeature = aMyDoc->feature(aThisPtr); CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aThisFeature); - if (aComposite.get()) { - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - int aSubID = aComposite->subFeatureId(a); - 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()) { - TopoDS_Shape aResShape = aConstr->shape()->impl(); - for(TopExp_Explorer anExp(aResShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) { - if (aSubShape.IsSame(anExp.Current())) { - anEdgesNum++; - break; - } - } - } - } - } - } - } - if (anEdgesNum > 1) { - for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) { - TopExp_Explorer anExp(face(aFaceIndex)->impl(), aSubShape.ShapeType()); - for(; anExp.More(); anExp.Next()) { - if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face - // here just store the face index (to update face if update of edge is needed) - TNaming_Builder aBuilder(aLab); - aBuilder.Select(aSubShape, aSubShape); - int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1); - TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID)); - isSelectionMode = true; - break; + if (!aComposite || aComposite->numberOfSubs() == 0) + return; // unknown case + // collect indices of curves of current composite + NCollection_DataMap aCurvesIndices; + NCollection_DataMap anEdgeIndices; + std::map aComponentsNames; // names of components that lay on index + 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(); + for (; aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + if (aConstr->shape() && aConstr->shape()->isEdge()) { + TopoDS_Edge anEdge = TopoDS::Edge(aConstr->shape()->impl()); + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + aCurvesIndices.Bind(aCurve, a); + anEdgeIndices.Bind(a, anEdge); + aComponentsNames[a] = Model_SelectionNaming::shortName(aConstr); } } } - } - } - - // external full result is not identified by index == 0, so, add here the ID - if (!theSubShape.get()) { - TDataStd_UAttribute::Set(aLab, kFULL_RESULT_ID); - // empty NS - TNaming_Builder aBuilder(aLab); - // store all sub-faces naming since faces may be used for extrusion, where all edges are needed - Handle(TDataStd_IntPackedMap) anIndices = TDataStd_IntPackedMap::Set(aLab); - std::list aFacesIndexes; - for(int a = 0; a < facesNum(); a++) { - anIndices->Add(select(face(a), theExtDoc, -1)); - } - return anIndex - 1; - } - { // this to have erased Builder after the shape was generated (NS on this label may be changed) - TNaming_Builder aBuilder(aLab); - if (aSubShape.IsNull()) { - return anIndex - 1; // just keep empty named shape - } - // wire never happens as sub, it must be generated to be found - // by SelectionNaming TNaming_Tool::NamedShape - if (isSelectionMode && aSubShape.ShapeType() != TopAbs_WIRE) { - aBuilder.Select(aSubShape, aSubShape); - } else { - 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; - // curves of the sketch sub-elements are used, so, edges are not equal - 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); - const int aSubNum = aComposite->numberOfSubs(); - // subs are placed on unique labels because of #2248: sketch curve may produce several edges, - // but #2401 - on stable labels - NCollection_Map aUsedIDMap; // already used lab tags for placement of shapes - - 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()->isEdge()) { - const TopoDS_Shape& aResShape = aConstr->shape()->impl(); - TopoDS_Edge anEdge = TopoDS::Edge(aResShape); - if (!anEdge.IsNull()) { + std::list > aFaces; + GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(), + aWirePtr->norm(), aWirePtr, aFaces); + NCollection_DataMap aNewIndices; // edges indices + std::list >::iterator aFIter = aFaces.begin(); + for (; aFIter != aFaces.end(); aFIter++) { + std::shared_ptr aFace(new GeomAPI_Face(*aFIter)); + // put them to a label, trying to keep the same faces on the same labels + if (aFace.get() && !aFace->isNull()) { + TopoDS_Face aTopoFace = TopoDS::Face(aFace->impl()); + aNewIndices.Bind(aTopoFace, TColStd_ListOfInteger()); + // keep new indices of sub-elements used in this face + for (TopExp_Explorer anEdges(aTopoFace, TopAbs_EDGE); anEdges.More(); anEdges.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdges.Current()); Standard_Real aFirst, aLast; Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (allCurves.Contains(aCurve)) { - int anID = aComposite->subFeatureId(a); - 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 (Model_CurvesHasher::IsEqual(aFaceCurve, aCurve)) { - while(aUsedIDMap.Contains(anID)) - anID += 100000; - aUsedIDMap.Add(anID); - TDF_Label aSubLab = aLab.FindChild(anID); - std::string aFullNameSub = fullName(aComposite, anEdge); - saveSubName(aComposite, aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub); - - int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge); - 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 - for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX); - anEdgeExp.More(); anEdgeExp.Next()) { - TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current()); - while(aUsedIDMap.Contains(anID)) - anID += 100000; - aUsedIDMap.Add(anID); - TDF_Label aSubLab = aLab.FindChild(anID); - std::string aFullNameSub = fullName(aComposite, aV); - saveSubName(aComposite, aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub); - } - } + if (aCurvesIndices.IsBound(aCurve)) { + int anIndex = aCurvesIndices.Find(aCurve); + if ((aFirst > aLast) != (anEdge.Orientation() == TopAbs_REVERSED)) + anIndex = -anIndex; + aNewIndices.ChangeFind(aTopoFace).Append(anIndex); } } } } - } - } - std::string aFullName = fullName(aComposite, aSubShape, aRefs); - // store the selected as primitive - registerSubShape(aLab, aSubShape, aFullName, 0, aMyDoc, isSelectionMode); - 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(); - if (aSelShape.IsNull()) - return aResult; // shape equal to context => null - 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 || aLab.IsAttribute(kFULL_RESULT_ID)) { // full for external same as index == 0 - // it is just reference to construction, not sub-shape - // if there is a sketch, the sketch-naming must be updated - if (!isInfinite()) { - // update all faces named by the whole result - bool aRes = true; - Handle(TDataStd_IntPackedMap) anIndices; - if (aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), anIndices)) { - NCollection_Map aFaces; // collect faces, updated in the tree - TColStd_MapIteratorOfPackedMapOfInteger anIndexIter(anIndices->GetMap()); - Handle(TColStd_HPackedMapOfInteger) aNewPackedMap = - new TColStd_HPackedMapOfInteger; // with only faces that are ok - // iterate to find existing faces, updated - for(; anIndexIter.More(); anIndexIter.Next()) { - if (update(anIndexIter.Key(), theExtDoc, theModified)) { - GeomShapePtr aFace = shape(anIndexIter.Key(), theExtDoc); - if (!aFaces.Contains(aFace->impl())) { - aNewPackedMap->ChangeMap().Add(anIndexIter.Key()); - aFaces.Add(aFace->impl()); + NCollection_DataMap aFacesOrder; // faces -> tag where they must be set + NCollection_List anUnorderedFaces; // faces that may be located at any index + // searching for the best new candidate to old location + NCollection_DataMap::Iterator aNewIter(aNewIndices); + for (; aNewIter.More(); aNewIter.Next()) { + double aBestFound = 0, aBestNotFound = 1.e+100; + int aBestTag = 0; + const TColStd_ListOfInteger& aNewInd = aNewIter.Value(); + // old faces indices where they where located + TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID()); + for (; anOldIter.More(); anOldIter.Next()) { + int aTag = anOldIter.Value()->Label().Tag(); + if (aFacesOrder.IsBound(aTag)) + continue; // already found a best candidate + Handle(TDataStd_IntPackedMap) anOldIndices = + Handle(TDataStd_IntPackedMap)::DownCast(anOldIter.Value()); + double aFound = 0, aNotFound = 0; + TColStd_ListOfInteger::Iterator aNewIndIter(aNewInd); + for (; aNewIndIter.More(); aNewIndIter.Next()) { + if (anOldIndices->Contains(aNewIndIter.Value())) { + aFound += 1.; + } + else if (anOldIndices->Contains(-aNewIndIter.Value())) { // different orientation + aFound += 0.001; + } + else { + aNotFound += 1.; } } - } - // then iterate all existing faces to find new faces - int aCurrentFacesNum = facesNum(); - for(int a = 0; a < aCurrentFacesNum; a++) { - GeomShapePtr aFace = face(a); - if (!aFaces.Contains(aFace->impl())) { - // add this one - int aNewFaceIndex = select(aFace, theExtDoc, -1); - if (aNewFaceIndex > 0) { - aNewPackedMap->ChangeMap().Add(aNewFaceIndex); + if (aNotFound < aBestNotFound) { + if (aFound > aBestFound) { + aBestNotFound = aNotFound; + aBestFound = aFound; + aBestTag = aTag; } } } - anIndices->ChangeMap(aNewPackedMap); - } - return aRes; - } else { - // check is this modified or not - std::shared_ptr aNewShape = shape(); - TopoDS_Shape anOldSh; - Handle(TNaming_NamedShape) aNS; - if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - anOldSh = aNS->Get(); - } - if (aNewShape.get()) { - if (anOldSh.IsNull()) - theModified = true; - else { - std::shared_ptr anOldShape(new GeomAPI_Shape); - anOldShape->setImpl(new TopoDS_Shape(anOldSh)); - theModified = !anOldShape->isEqual(aNewShape); + if (aBestTag != 0) { // found an appropriate face + aFacesOrder.Bind(aBestTag, aNewIter.Key()); + } else { + anUnorderedFaces.Append(aNewIter.Key()); } } - else if (!anOldSh.IsNull()) { - theModified = true; - } - - // 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(aNewShape->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); + aShapeLab.ForgetAllAttributes(); // clear all previously stored + TNaming_Builder aBuilder(aShapeLab); // store the compound to get it ready on open of document + aBuilder.Generated(aShape); + // set new faces to the labels + int aCurrentTag = 1; + NCollection_List::Iterator anUnordered(anUnorderedFaces); + for(int aCurrentTag = 1; !aFacesOrder.IsEmpty() || anUnordered.More(); aCurrentTag++) { + TopoDS_Face aFaceToPut; + if (aFacesOrder.IsBound(aCurrentTag)) { + aFaceToPut = aFacesOrder.Find(aCurrentTag); + aFacesOrder.UnBind(aCurrentTag); + } else if (anUnordered.More()){ + aFaceToPut = anUnordered.Value(); + anUnordered.Next(); + } - // sketch sub-element - if (std::dynamic_pointer_cast(aContextFeature).get()) - { - // update the referenced object if it is sub - Handle(TDF_Reference) aRef; - if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) { - int aFaceIndex = aRef->Get().Tag(); - // don't check selection since face may disappear, but the shape stays correct - Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified); - } - // 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 (!aFaceToPut.IsNull()) { + TopTools_MapOfShape aFaceEdges; + for(TopExp_Explorer anEdges(aFaceToPut, TopAbs_EDGE); anEdges.More(); anEdges.Next()) { + aFaceEdges.Add(anEdges.Current()); + } - 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); - } + TDF_Label aLab = aShapeLab.FindChild(aCurrentTag); + TNaming_Builder aFaceBuilder(aLab); + aFaceBuilder.Generated(aFaceToPut); + // store also indices of the new face edges + Handle(TDataStd_IntPackedMap) aNewMap = TDataStd_IntPackedMap::Set(aLab); + const TColStd_ListOfInteger& aNewInd = aNewIndices.Find(aFaceToPut); + std::stringstream aName; + aName<<"Face"; + TopExp_Explorer aPutEdges(aFaceToPut, TopAbs_EDGE); + TNaming_Builder* anEdgesBuilder = 0; + for(TColStd_ListOfInteger::Iterator anIter(aNewInd); anIter.More(); anIter.Next()) { + int anIndex = anIter.Value(); + aNewMap->Add(anIndex); + aName<<"-"< 0 ? anIndex : -anIndex]; + if (anIter.Value() > 0) + aName<<"f"; + else + aName<<"r"; + // collect all edges of the face which are modified in sub-label of the face + if (anEdgeIndices.IsBound(anIndex) && + !aFaceEdges.Contains(anEdgeIndices.Find(anIndex))) { + if (!anEdgesBuilder) { + TDF_Label anEdgesLabel = aLab.FindChild(1); + anEdgesBuilder = new TNaming_Builder(anEdgesLabel); + TDataStd_Name::Set(anEdgesLabel, "SubEdge"); } + anEdgesBuilder->Modify(anEdgeIndices.Find(anIndex), aPutEdges.Current()); } + aPutEdges.Next(); } - } - 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++; - } - } - } - } + TDataStd_Name::Set(aLab, TCollection_ExtendedString(aName.str().c_str())); + aMyDoc->addNamingName(aLab, aName.str()); } } } - } 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 b5ea41cd9..3ba48777f 100644 --- a/src/Model/Model_ResultConstruction.h +++ b/src/Model/Model_ResultConstruction.h @@ -39,22 +39,13 @@ class Model_ResultConstruction : public ModelAPI_ResultConstruction { std::shared_ptr myOwner; ///< owner of this result std::shared_ptr myShape; ///< shape of this result created "on the fly" - bool myFacesUpToDate; ///< is true if faces in myuFaces are computed and up to date - /// stores the up to date faces if they exist - std::vector > myFaces; - bool myIsInHistory; - bool myIsInfinite; public: /// Retuns the parameters of color definition in the resources config manager MODEL_EXPORT virtual void colorConfigInfo(std::string& theSection, std::string& theName, std::string& theDefault); /// By default object is displayed in the object browser. - MODEL_EXPORT virtual bool isInHistory() - { - return myIsInHistory; - } - + MODEL_EXPORT virtual bool isInHistory(); /// Sets the result MODEL_EXPORT virtual void setShape(std::shared_ptr theShape); /// Returns the shape-result produced by this feature @@ -76,39 +67,16 @@ 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); + /// Updates the shape taking the current value from the data structure, returns true + /// if update has been correctly done + MODEL_EXPORT virtual bool updateShape(); 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); + /// Stores shape in the data structure to allow identification it by the naming + void storeShape(std::shared_ptr theShape); friend class Model_Objects; }; diff --git a/src/ModelAPI/ModelAPI_BodyBuilder.h b/src/ModelAPI/ModelAPI_BodyBuilder.h index 6edfd2c00..bd252e8d7 100755 --- a/src/ModelAPI/ModelAPI_BodyBuilder.h +++ b/src/ModelAPI/ModelAPI_BodyBuilder.h @@ -117,10 +117,6 @@ public: const std::string& theName, int& theTag) = 0; - /// Converts evolution of sub-shapes stored in naming structure to selection - /// (theFlag = true) and back (theFlag = false) - virtual void evolutionToSelection(const bool theFlag) = 0; - /// Returns true if the latest modification of this body in the naming history // is equal to the given shape virtual bool isLatestEqual(const GeomShapePtr& theShape) = 0; diff --git a/src/ModelAPI/ModelAPI_ResultConstruction.h b/src/ModelAPI/ModelAPI_ResultConstruction.h index ff637277d..225102be5 100644 --- a/src/ModelAPI/ModelAPI_ResultConstruction.h +++ b/src/ModelAPI/ModelAPI_ResultConstruction.h @@ -63,6 +63,10 @@ class ModelAPI_ResultConstruction : public ModelAPI_Result /// Sets the result virtual void setShape(std::shared_ptr theShape) = 0; + /// Updates the shape taking the current value from the data structure, returns true + /// if update has been correctly done + virtual bool updateShape() = 0; + /// Sets the flag that it must be displayed in history (default is true) virtual void setIsInHistory(const bool isInHistory) = 0; diff --git a/src/Selector/CMakeLists.txt b/src/Selector/CMakeLists.txt index f3bf654ea..38af7997f 100644 --- a/src/Selector/CMakeLists.txt +++ b/src/Selector/CMakeLists.txt @@ -24,11 +24,13 @@ SET(PROJECT_HEADERS Selector.h Selector_Selector.h Selector_NameGenerator.h + Selector_NExplode.h ) SET(PROJECT_SOURCES Selector_Selector.cpp Selector_NameGenerator.cpp + Selector_NExplode.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/Selector/Selector_NExplode.cpp b/src/Selector/Selector_NExplode.cpp new file mode 100644 index 000000000..018f6b438 --- /dev/null +++ b/src/Selector/Selector_NExplode.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2017 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or +// email : webmaster.salome@opencascade.com +// + +#include "Selector_NExplode.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static std::pair ShapeToDouble (const TopoDS_Shape& S) +{ + // Computing of CentreOfMass + gp_Pnt GPoint; + double Len; + + if (S.ShapeType() == TopAbs_VERTEX) { + GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); + Len = (double)S.Orientation(); + } + else { + GProp_GProps GPr; + if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { + BRepGProp::LinearProperties(S, GPr); + } + else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { + BRepGProp::SurfaceProperties(S, GPr); + } + else { + BRepGProp::VolumeProperties(S, GPr); + } + GPoint = GPr.CentreOfMass(); + Len = GPr.Mass(); + } + + double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9; + return std::make_pair(dMidXYZ, Len); +} + +/*! +* \brief Sort shapes in the list by their coordinates. +*/ +struct CompareShapes : public std::binary_function +{ + typedef NCollection_DataMap > DataMapOfShapeDouble; + + CompareShapes(DataMapOfShapeDouble* theCashMap) : myMap(theCashMap) {} + + bool operator() (const TopoDS_Shape& lhs, const TopoDS_Shape& rhs); + + DataMapOfShapeDouble* myMap; +}; + +bool CompareShapes::operator() (const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2) +{ + if (!myMap->IsBound(theShape1)) { + myMap->Bind(theShape1, ShapeToDouble(theShape1)); + } + + if (!myMap->IsBound(theShape2)) { + myMap->Bind(theShape2, ShapeToDouble(theShape2)); + } + + std::pair val1 = myMap->Find(theShape1); + std::pair val2 = myMap->Find(theShape2); + + double tol = Precision::Confusion(); + bool exchange = Standard_False; + + double dMidXYZ = val1.first - val2.first; + if (dMidXYZ >= tol) { + exchange = Standard_True; + } + else if (Abs(dMidXYZ) < tol) { + double dLength = val1.second - val2.second; + if (dLength >= tol) { + exchange = Standard_True; + } + else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) { + // equal values possible on shapes such as two halves of a sphere and + // a membrane inside the sphere + Bnd_Box box1,box2; + BRepBndLib::Add(theShape1, box1); + if (!box1.IsVoid()) { + BRepBndLib::Add(theShape2, box2); + Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent(); + if (dSquareExtent >= tol) { + exchange = Standard_True; + } + else if (Abs(dSquareExtent) < tol) { + Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2; + box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; + box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; + if ((val1 - val2) >= tol) { + exchange = Standard_True; + } + } + } + } else // compare adresses if shapes are geometrically equal + return theShape1.TShape().get() > theShape2.TShape().get(); + } + + //return val1 < val2; + return !exchange; +} + +Selector_NExplode::Selector_NExplode(const TopoDS_ListOfShape& theShapes) +{ + std::vector aShapesVec; + + for(TopoDS_ListOfShape::Iterator anIter(theShapes); anIter.More(); anIter.Next()) { + aShapesVec.push_back(anIter.Value()); + } + + CompareShapes::DataMapOfShapeDouble aCash; + CompareShapes shComp(&aCash); + std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp); + + std::vector::const_iterator anIter = aShapesVec.begin(); + for (; anIter != aShapesVec.end(); ++anIter) { + mySorted.Append(*anIter); + } +} + +int Selector_NExplode::index(const TopoDS_Shape& theSubShape) +{ + TopoDS_ListOfShape::Iterator anIter(mySorted); + for(int anIndex = 1; anIter.More(); anIter.Next(), anIndex++) { + if (anIter.Value().IsSame(theSubShape)) + return anIndex; + } + return -1; // not found +} + +TopoDS_Shape Selector_NExplode::shape(const int theIndex) +{ + TopoDS_ListOfShape::Iterator anIter(mySorted); + for(int anIndex = 1; anIter.More(); anIter.Next(), anIndex++) { + if (anIndex == theIndex) + return anIter.Value(); + } + return TopoDS_Shape(); // not found +} diff --git a/src/Selector/Selector_NExplode.h b/src/Selector/Selector_NExplode.h new file mode 100644 index 000000000..4e020c1a9 --- /dev/null +++ b/src/Selector/Selector_NExplode.h @@ -0,0 +1,49 @@ +// Copyright (C) 2017 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or +// email : webmaster.salome@opencascade.com +// + +#ifndef Selector_NExplode_H_ +#define Selector_NExplode_H_ + +#include "Selector.h" + +#include +#include + +/// \class Selector_NExplode +/// \ingroup DataModel +/// \brief Sort shapes by their centers of mass, using formula X*999 + Y*99 + Z*0.9. +/// Algorithm is copied from GEOM module, which uses nexplode Draw command from OCCT. +/// Used for getting index of sub0shape in WeakNaming algorithm. +class Selector_NExplode +{ + public: + /// \brief Initializes the sorted list of shapes by the context shape and type of sub-shapes. + SELECTOR_EXPORT Selector_NExplode(const TopoDS_ListOfShape& theShapes); + + /// Returns an index (started from one) of sub-shape in the sorted list. Returns 0 if not found. + SELECTOR_EXPORT int index(const TopoDS_Shape& theSubShape); + /// Returns a shape by an index (started from one). Returns null if not found. + SELECTOR_EXPORT TopoDS_Shape shape(const int theIndex); + +protected: + TopoDS_ListOfShape mySorted; ///< keepthe the ordered list of shapes +}; + +#endif diff --git a/src/Selector/Selector_Selector.cpp b/src/Selector/Selector_Selector.cpp index f97d20c8c..2d8089485 100644 --- a/src/Selector/Selector_Selector.cpp +++ b/src/Selector/Selector_Selector.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -50,9 +51,12 @@ static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171"); static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f"); // array of the neighbor levels static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f"); +// weak index (integer) of the sub-shape +static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87"); Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab) { + myWeakIndex = -1; } TDF_Label Selector_Selector::label() @@ -127,10 +131,15 @@ static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theV aNBConnectors.Add(aValExp.Current()); } + TopTools_MapOfShape alreadyProcessed; + alreadyProcessed.Add(theValue); + for(int aLevel = 1; aLevel <= theLevel; aLevel++) { TopoDS_ListOfShape aGoodCandidates; TopExp_Explorer aCandidate(theContext, theValue.ShapeType()); for(; aCandidate.More(); aCandidate.Next()) { + if (alreadyProcessed.Contains(aCandidate.Current())) + continue; TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType); for(; aCandConnector.More(); aCandConnector.Next()) { if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor @@ -150,6 +159,7 @@ static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theV for(; aGoodConnector.More(); aGoodConnector.Next()) { aNBConnectors.Add(aGoodConnector.Current()); } + alreadyProcessed.Add(aGood.Value()); } } } @@ -189,6 +199,7 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext, } } } + aFirst = false; } } if (aMatches.IsEmpty()) @@ -258,7 +269,9 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape // try to find the shape of the higher level type in the context shape bool aFacesTried = false; // for identification of vertices, faces are tried, then edges while(aSelectionType != TopAbs_FACE || !aFacesTried) { - if (aSelectionType == TopAbs_FACE && theValue.ShapeType() == TopAbs_VERTEX) { + if (aSelectionType == TopAbs_FACE) { + if (theValue.ShapeType() != TopAbs_VERTEX) + break; aFacesTried = true; aSelectionType = TopAbs_EDGE; } else @@ -318,7 +331,7 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape if (!aResult.IsNull() && aResult.IsSame(theValue)) { std::list >::iterator aNBIter = aNBs.begin(); for(; aNBIter != aNBs.end(); aNBIter++) { - if (!selectBySubSelector(theContext, aNBIter->first)) { + if (!selectBySubSelector(theContext, aNBIter->first, false)) { return false; // something is wrong because before this selection was ok } myNBLevel.push_back(aNBIter->second); @@ -385,9 +398,55 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape findBases(aModifList.First(), theValue, true, myBases); if (!myBases.IsEmpty()) { myFinal = aModifList.First()->Label(); - myType = SELTYPE_MODIFICATION; - return !myBases.IsEmpty(); + TopoDS_ListOfShape aCommon; + findModificationResult(aCommon); + // trying to search by neighbours + if (aCommon.Extent() > 1) { // more complicated selection + if (!theUseNeighbors) + return false; + + // searching by neighbours + std::list > aNBs; /// neighbor sub-shape -> level of neighborhood + for(int aLevel = 1; true; aLevel++) { + TopTools_MapOfShape aNewNB; + findNeighbors(theContext, theValue, aLevel, aNewNB); + if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration + break; + } + // check which can be named correctly, without by neighbors type + for(TopTools_MapOfShape::Iterator aNBIter(aNewNB); aNBIter.More(); ) { + Selector_Selector aSelector(myLab.FindChild(1)); + if (aSelector.select(theContext, aNBIter.Value(), false)) { // add to the list of good NBs + aNBs.push_back(std::pair(aNBIter.Value(), aLevel)); + } + aNewNB.Remove(aNBIter.Key()); + aNBIter.Initialize(aNewNB); + } + TopoDS_Shape aResult = findNeighbor(theContext, aNBs); + if (!aResult.IsNull() && aResult.IsSame(theValue)) { + std::list >::iterator aNBIter = aNBs.begin(); + for(; aNBIter != aNBs.end(); aNBIter++) { + if (!selectBySubSelector(theContext, aNBIter->first)) { + return false; // something is wrong because before this selection was ok + } + myNBLevel.push_back(aNBIter->second); + + } + myType = SELTYPE_FILTER_BY_NEIGHBOR; + return true; + } + } + // filter by neighbours did not help + if (aCommon.Extent() > 1) { // weak naming between the common results + Selector_NExplode aNexp(aCommon); + myWeakIndex = aNexp.index(theValue); + if (myWeakIndex == -1) + return false; + } + } } + myType = SELTYPE_MODIFICATION; + return !myBases.IsEmpty(); } // not found a good result @@ -423,6 +482,9 @@ void Selector_Selector::store() anArray->SetValue(anIndex, aBIter.Value()); } anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array + if (myWeakIndex != -1) { + TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex); + } break; } case SELTYPE_FILTER_BY_NEIGHBOR: { @@ -485,6 +547,10 @@ bool Selector_Selector::restore() myBases.Append(anArray->Value(anIndex)); } myFinal = anArray->Value(anUpper); + Handle(TDataStd_Integer) aWeakInt; + if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) { + myWeakIndex = aWeakInt->Get(); + } return true; } return false; @@ -531,7 +597,29 @@ static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal, } } } +} +void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) { + for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) { + TopTools_MapOfShape aFinals; + for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) + findFinals(aBaseShape.NewShape(), myFinal, aFinals); + if (!aFinals.IsEmpty()) { + if (theCommon.IsEmpty()) { // just copy all to common + for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) { + theCommon.Append(aFinal.Key()); + } + } else { // keep only shapes presented in both lists + for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) { + if (aFinals.Contains(aCommon.Value())) { + aCommon.Next(); + } else { // common is not found, remove it + theCommon.Remove(aCommon); + } + } + } + } + } } bool Selector_Selector::solve(const TopoDS_Shape& theContext) @@ -599,28 +687,14 @@ bool Selector_Selector::solve(const TopoDS_Shape& theContext) } case SELTYPE_MODIFICATION: { TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases - for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) { - TopTools_MapOfShape aFinals; - for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) - findFinals(aBaseShape.NewShape(), myFinal, aFinals); - if (!aFinals.IsEmpty()) { - if (aFinalsCommon.IsEmpty()) { // just copy all to common - for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) { - aFinalsCommon.Append(aFinal.Key()); - } - } else { // keep only shapes presented in both lists - for(TopoDS_ListOfShape::Iterator aCommon(aFinalsCommon); aCommon.More(); ) { - if (aFinals.Contains(aCommon.Value())) { - aCommon.Next(); - } else { // common is not found, remove it - aFinalsCommon.Remove(aCommon); - } - } - } - } - } + findModificationResult(aFinalsCommon); if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape aResult = aFinalsCommon.First(); + else if (aFinalsCommon.Extent() > 1 && myWeakIndex) { + Selector_NExplode aNExp(aFinalsCommon); + aResult = aNExp.shape(myWeakIndex); + + } break; } case SELTYPE_FILTER_BY_NEIGHBOR: { @@ -687,10 +761,15 @@ std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) { for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) { if (aBase != myBases.begin()) aResult += "&"; - if (aBase->FindAttribute(TDataStd_Name::GetID(), aName)) + if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName)) return ""; aResult += theNameGenerator->contextName(*aBase) + "/" + std::string(TCollection_AsciiString(aName->Get()).ToCString()); + if (myWeakIndex != -1) { + std::ostringstream aWeakStr; + aWeakStr<<"&weak_name_"< mySubSelList; ///< list of sub-selectors if needed TDF_Label myFinal; ///< final label of the primitive or generation, where the value is TDF_LabelList myBases; ///< initial labels that contain shapes that produce the modification + int myWeakIndex; ///< index of the shape among commons for the modification type (-1 - not set) std::list myNBLevel; ///< list of integers corresponding to subsellist neighborhood level @@ -66,7 +67,7 @@ class Selector_Selector /// Initializes the selector structure on the label. /// Stores the name data to restore after modification. SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue, - const bool theUseNeighbors = false); + const bool theUseNeighbors = true); /// Stores the name to the label and sub-labels tree SELECTOR_EXPORT void store(); @@ -88,7 +89,10 @@ private: /// Create and keep in the list the sub-sulector that select the given value. /// Returns true if selection is correct. - bool selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue); + bool selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue, + const bool theUseNeighbors = true); + /// Searches the final shapes presented in all results from bases basing on the modification fields + void findModificationResult(TopoDS_ListOfShape& theCommon); }; #endif diff --git a/src/SketchPlugin/SketchPlugin_Feature.h b/src/SketchPlugin/SketchPlugin_Feature.h index a98238307..20a98e327 100644 --- a/src/SketchPlugin/SketchPlugin_Feature.h +++ b/src/SketchPlugin/SketchPlugin_Feature.h @@ -65,9 +65,6 @@ class SketchPlugin_Feature : public ModelAPI_Feature return true; } - /// Construction result is allways recomuted on the fly - SKETCHPLUGIN_EXPORT virtual bool isPersistentResult() {return false;} - /// Returns true is sketch element is under the rigid constraint SKETCHPLUGIN_EXPORT virtual bool isFixed() {return false;} diff --git a/src/SketchPlugin/SketchPlugin_Sketch.h b/src/SketchPlugin/SketchPlugin_Sketch.h index 3e7328e77..57dde7c5c 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.h +++ b/src/SketchPlugin/SketchPlugin_Sketch.h @@ -204,9 +204,6 @@ class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICu /// Returns true if feature or reuslt belong to this composite feature as subs SKETCHPLUGIN_EXPORT virtual bool isSub(ObjectPtr theObject) const; - /// Construction result is allways recomuted on the fly - SKETCHPLUGIN_EXPORT virtual bool isPersistentResult() {return false;} - SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); /// Exchanges IDs of two given features: needed for fillet feature better naming (issue 769) -- 2.39.2