From e40b79a40fe27c188aa1c49643559be328bbcb06 Mon Sep 17 00:00:00 2001 From: mpv Date: Fri, 19 Oct 2018 11:46:49 +0300 Subject: [PATCH] Debug of move to the end of history --- src/Model/CMakeLists.txt | 2 - src/Model/Model_AttributeSelection.cpp | 115 +-- src/Model/Model_AttributeSelection.h | 4 - src/Model/Model_Document.cpp | 2 +- src/Model/Model_Objects.cpp | 13 +- src/Model/Model_ResultConstruction.cpp | 38 +- src/Model/Model_SelectionNaming.cpp | 1180 ------------------------ src/Model/Model_SelectionNaming.h | 115 --- src/Selector/Selector_Selector.cpp | 5 +- 9 files changed, 54 insertions(+), 1420 deletions(-) delete mode 100644 src/Model/Model_SelectionNaming.cpp delete mode 100644 src/Model/Model_SelectionNaming.h diff --git a/src/Model/CMakeLists.txt b/src/Model/CMakeLists.txt index 27a8c6eb5..a5138d2fa 100644 --- a/src/Model/CMakeLists.txt +++ b/src/Model/CMakeLists.txt @@ -55,7 +55,6 @@ SET(PROJECT_HEADERS Model_ResultParameter.h Model_FeatureValidator.h Model_AttributeValidator.h - Model_SelectionNaming.h ) SET(PROJECT_SOURCES @@ -92,7 +91,6 @@ SET(PROJECT_SOURCES Model_ResultParameter.cpp Model_FeatureValidator.cpp Model_AttributeValidator.cpp - Model_SelectionNaming.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index b1e9281c8..2bf60811d 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -23,7 +23,6 @@ #include "Model_Events.h" #include "Model_Data.h" #include "Model_Document.h" -#include "Model_SelectionNaming.h" #include #include #include @@ -45,7 +44,6 @@ #include #include -#include #include #include #include @@ -60,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -532,69 +531,6 @@ void Model_AttributeSelection::setObject(const std::shared_ptr& myRef.setObject(theObject); } -TDF_LabelMap& Model_AttributeSelection::scope() -{ - if (myScope.IsEmpty()) { // create a new scope if not yet done - // 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 - // this causes problem in galeries.py - //bool isGroup = aFeature.get() && aFeature->getKind() == "Group"; - for(; aFIter != allFeatures.end(); aFIter++) { - 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(), true); - for(; aNSIter.More(); aNSIter.Next()) { - Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); - if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) { - myScope.Add(aNS->Label()); - } - } - } - } - // also add all naming labels created for external constructions - std::shared_ptr aDoc = std::dynamic_pointer_cast(aMyDoc); - TDF_Label anExtDocLab = aDoc->extConstructionsLabel(); - TDF_ChildIDIterator aNSIter(anExtDocLab, TNaming_NamedShape::GetID(), true); - for(; aNSIter.More(); aNSIter.Next()) { - Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); - if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) { - myScope.Add(aNS->Label()); - } - } - } - return myScope; -} - /// Sets the invalid flag if flag is false, or removes it if "true" /// Returns theFlag static bool setInvalidIfFalse(TDF_Label& theLab, const bool theFlag) { @@ -636,6 +572,7 @@ bool Model_AttributeSelection::update() { FeaturePtr aContextFeature = contextFeature(); if (aContextFeature.get()) { + owner()->data()->sendAttributeUpdated(this); // send updated if "update" called in any way return true; } TDF_Label aSelLab = selectionLabel(); @@ -688,13 +625,7 @@ bool Model_AttributeSelection::update() anOldShape = aNS->Get(); Selector_Selector aSelector(aSelLab); - if (!aSelector.restore()) { // it is stored in old OCCT format, use TNaming_Selector - TNaming_Selector aSelector(aSelLab); - if (!aSelector.NamedShape().IsNull()) { - anOldShape = aSelector.NamedShape()->Get(); - } - aResult = aSelector.Solve(scope()) == Standard_True; - } else { + if (aSelector.restore()) { // it is stored in old OCCT format, use TNaming_Selector TopoDS_Shape aContextShape = aContext->shape()->impl(); aResult = aSelector.solve(aContextShape); } @@ -724,11 +655,16 @@ bool Model_AttributeSelection::update() if (!aConstructionContext->isInfinite()) { Selector_Selector aSelector(aSelLab); aResult = aSelector.restore(); + TopoDS_Shape anOldShape = aSelector.value(); if (aResult) { TopoDS_Shape aContextShape = aContext->shape()->impl(); aResult = aSelector.solve(aContextShape); } aResult = setInvalidIfFalse(aSelLab, aResult); + if (aResult && !anOldShape.IsEqual(aSelector.value())) + owner()->data()->sendAttributeUpdated(this); // send updated if shape is changed + } else { + owner()->data()->sendAttributeUpdated(this); // send updated if "update" called in any way } return aResult; } @@ -759,20 +695,11 @@ void Model_AttributeSelection::selectBody( TDF_Label aSelLab = selectionLabel(); TopoDS_Shape aNewSub = theSubShape ? theSubShape->impl() : aContext; - /// fix for issue 411: result modified shapes must not participate in this selection mechanism if (!aContext.IsNull()) { FeaturePtr aFeatureOwner = std::dynamic_pointer_cast(owner()); - bool aEraseResults = false; - if (aFeatureOwner.get()) { - aEraseResults = !aFeatureOwner->results().empty(); - if (aEraseResults) // erase results without flash deleted and redisplay: do it after Select - aFeatureOwner->removeResults(0, false, false); - } bool aSelectorOk = true; - //TNaming_Selector aSel(aSelLab); Selector_Selector aSel(aSelLab); try { - //aSel.Select(aNewSub, aNewContext); aSelectorOk = aSel.select(aContext, aNewSub); if (aSelectorOk) { aSel.store(); @@ -781,9 +708,6 @@ void Model_AttributeSelection::selectBody( } catch(...) { aSelectorOk = false; } - // face may become divided after the model update, so, new labels may be added to the scope - myScope.Clear(); - // check that selection is correct, otherwise use weak naming solution TDF_Label aSelLab = selectionLabel(); aSelLab.ForgetAttribute(kWEAK_NAMING); @@ -807,12 +731,6 @@ void Model_AttributeSelection::selectBody( TDataStd_Integer::Set(aSelLab, kWEAK_NAMING_SHAPETYPE, int(aValueShape->shapeType())); } } - - if (aEraseResults) { // flash after Select : in Groups it makes selection with shift working - static Events_Loop* aLoop = Events_Loop::loop(); - static const Events_ID kDeletedEvent = aLoop->eventByName(EVENT_OBJECT_DELETED); - aLoop->flush(kDeletedEvent); - } } } @@ -1288,7 +1206,7 @@ void Model_AttributeSelection::computeValues( for(; aNewContIter != aNewToIterate.end(); aNewContIter++) { std::shared_ptr aNewData = std::dynamic_pointer_cast((*aNewContIter)->data()); - TDF_Label aNewLab = aNewData->label(); + TDF_Label aNewLab = aNewData->shapeLab(); // searching for produced sub-shape fully on some label TDF_ChildIDIterator aNSIter(aNewLab, TNaming_NamedShape::GetID(), Standard_True); for(; aNSIter.More(); aNSIter.Next()) { @@ -1382,11 +1300,11 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr if (!aModifierFeat.get()) continue; FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); - if (aModifierFeat == aThisFeature || theDoc->objects()->isLater(aModifierFeat, aThisFeature)) + if (aModifierFeat == aThisFeature || !theDoc->isLaterByDep(aThisFeature, aModifierFeat)) continue; // the modifier feature is later than this, so, should not be used FeaturePtr aCurrentModifierFeat = theDoc->feature(theContext); if (aCurrentModifierFeat == aModifierFeat || - theDoc->objects()->isLater(aCurrentModifierFeat, aModifierFeat)) + !theDoc->isLaterByDep(aModifierFeat, aCurrentModifierFeat)) continue; // the current modifier is later than the found, so, useless Handle(TNaming_NamedShape) aNewNS; aModifIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNewNS); @@ -1397,7 +1315,7 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr aResContShapes.Append(aModifierObj->shape()->impl()); } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is empty aResults.insert(ResultPtr()); - } else { // not-precessed modification => don't support it + } else { // not-processed modification => don't support it continue; } } @@ -1452,7 +1370,7 @@ void Model_AttributeSelection::updateInHistory() std::shared_ptr aContData = std::dynamic_pointer_cast(aContext->data()); if (!aContData.get() || !aContData->isValid()) return; - TDF_Label aContLab = aContData->label(); // named shape where the selected context is located + TDF_Label aContLab = aContData->shapeLab(); // named shape where the selected context is located Handle(TNaming_NamedShape) aContNS; if (!aContLab.FindAttribute(TNaming_NamedShape::GetID(), aContNS)) { bool aFoundNewContext = true; @@ -1475,7 +1393,7 @@ void Model_AttributeSelection::updateInHistory() FeaturePtr aRefFeat = std::dynamic_pointer_cast((*aRef)->owner()); if (aRefFeat.get() && aRefFeat != owner()) { FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); - if (aDoc->objects()->isLater(aThisFeature, aRefFeat)) { // found better feature + if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature aFoundNewContext = true; aNewContext = aRefFeat->firstResult(); } @@ -1512,9 +1430,6 @@ void Model_AttributeSelection::updateInHistory() TopTools_ListOfShape aValShapes; if (searchNewContext(aDoc, aNewCShape, aContext, aValShape, aContLab, aNewContexts, aValShapes)) { - // update scope to reset to a new one - myScope.Clear(); - std::list::iterator aNewCont = aNewContexts.begin(); TopTools_ListIteratorOfListOfShape aNewValues(aValShapes); if (aNewCont == aNewContexts.end()) { // all results were deleted @@ -1780,5 +1695,5 @@ bool Model_AttributeSelection::isLater( FeaturePtr aFeat2 = aDoc->featureByLab(theResult2); if (!aFeat2.get()) return false; - return aDoc->isLater(aFeat1, aFeat2); + return aDoc->isLaterByDep(aFeat1, aFeat2); } diff --git a/src/Model/Model_AttributeSelection.h b/src/Model/Model_AttributeSelection.h index aaf506295..ed233f85f 100644 --- a/src/Model/Model_AttributeSelection.h +++ b/src/Model/Model_AttributeSelection.h @@ -40,7 +40,6 @@ class Model_AttributeSelection : public ModelAPI_AttributeSelection, public Selector_NameGenerator { Model_AttributeReference myRef; ///< The reference functionality reusage - TDF_LabelMap myScope; ///< the map of valid labels for naming selection solving /// temporarily storages to avoid keeping in the data structure if not needed ResultPtr myTmpContext; /// temporarily storages to avoid keeping in the data structure if not needed @@ -175,9 +174,6 @@ protected: /// Note: there must be no attributes stored at the same label because Selector clears this lab TDF_Label selectionLabel(); - /// Returns the prepared map of valid labels for naming selection solving (creates if not exists) - TDF_LabelMap& scope(); - /// Sets the ID of the attribute in Data (called from Data): here it is used for myRef ID setting MODEL_EXPORT virtual void setID(const std::string theID); diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 548e3174b..d71b770c7 100755 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -1494,7 +1494,7 @@ bool Model_Document::isLaterByDep(FeaturePtr theThis, FeaturePtr theOther) { aRefFeat = feature(std::dynamic_pointer_cast(aRefObj)); } if (aRefFeat.get() && aRefFeat == theThis) { - return false; // other references to this, so this later than other + return false; // other references to this, so other later than this } } } diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 8b6d87d57..9d89e5c64 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -1902,9 +1902,16 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set& t if (aResSize > 0) { // check there exist a body that must be updated std::list::const_iterator aRes = theFeature->results().cbegin(); for (; aResSize && aRes != theFeature->results().cend(); aRes++, aResSize++) { - if ((*aRes)->data()->isValid() && (*aRes)->groupName() == ModelAPI_ResultBody::group()) { - ResultBodyPtr aBody = std::dynamic_pointer_cast(*aRes); - aBody->updateSubs(aBody->shape(), false); + if ((*aRes)->data()->isValid()) { + if ((*aRes)->groupName() == ModelAPI_ResultBody::group()) { + ResultBodyPtr aBody = std::dynamic_pointer_cast(*aRes); + aBody->updateSubs(aBody->shape(), false); + } else if ((*aRes)->groupName() == ModelAPI_ResultConstruction::group()) { + // update the cashed myShape presented in construction + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + aConstr->updateShape(); + } } } } diff --git a/src/Model/Model_ResultConstruction.cpp b/src/Model/Model_ResultConstruction.cpp index b60c6f012..87fe4c5ed 100644 --- a/src/Model/Model_ResultConstruction.cpp +++ b/src/Model/Model_ResultConstruction.cpp @@ -23,36 +23,29 @@ #include #include #include -#include #include -#include +#include #include #include #include -#include -#include #include #include #include -#include #include #include #include -#include -#include -#include #include #include -#include #include #include #include #include -#include -#include #include +#include + + // identifier of the infinite result Standard_GUID kIS_INFINITE("dea8cc5a-53f2-49c1-94e8-a947bed20a9f"); // identifier of the result not in history @@ -83,6 +76,26 @@ std::shared_ptr Model_ResultConstruction::shape() return myShape; } +static std::string shortName( + std::shared_ptr& theConstr) +{ + std::string aName = theConstr->data()->name(); + // remove "-", "/" and "&" command-symbols + aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end()); + aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end()); + aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end()); + // remove the last 's', 'e', 'f' and 'r' symbols: + // they are used as markers of start/end/forward/rewersed indicators + static const std::string aSyms("sefr"); + std::string::iterator aSuffix = aName.end() - 1; + while(aSyms.find(*aSuffix) != std::string::npos) { + --aSuffix; + } + aName.erase(aSuffix + 1, aName.end()); + return aName; +} + + bool Model_ResultConstruction::updateShape() { std::shared_ptr aData = std::dynamic_pointer_cast(data()); @@ -106,7 +119,6 @@ Model_ResultConstruction::Model_ResultConstruction() { } - bool Model_ResultConstruction::isInHistory() { std::shared_ptr aData = std::dynamic_pointer_cast(data()); @@ -253,7 +265,7 @@ void Model_ResultConstruction::storeShape(std::shared_ptr theShap Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); aCurvesIndices.Bind(aCurve, a); anEdgeIndices.Bind(a, anEdge); - aComponentsNames[a] = Model_SelectionNaming::shortName(aConstr); + aComponentsNames[a] = shortName(aConstr); } } } diff --git a/src/Model/Model_SelectionNaming.cpp b/src/Model/Model_SelectionNaming.cpp deleted file mode 100644 index 78c167e9f..000000000 --- a/src/Model/Model_SelectionNaming.cpp +++ /dev/null @@ -1,1180 +0,0 @@ -// Copyright (C) 2014-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 "Model_SelectionNaming.h" -#include "Model_Document.h" -#include "Model_Objects.h" -#include "Model_Data.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEB_NAMING -#include -#endif - -Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab) -{ - myLab = theSelectionLab; -} - -// searches named shape by the shape in the given document (identified by the label) -// tries to find s shape nearest to the context-label -static Handle(TNaming_NamedShape) shapeToNS(const TDF_Label theLabAccess, - const TopoDS_Shape& theShape, const TDF_Label& theContextLab) -{ - Handle(TNaming_NamedShape) aResult; - if (!TNaming_Tool::HasLabel(theLabAccess, theShape)) // no shape in the document - return aResult; - int aContextLabDepth = theContextLab.IsNull() ? 100 : theContextLab.Depth(); - TNaming_SameShapeIterator aNSIter(theShape, theLabAccess); - for(; aNSIter.More(); aNSIter.Next()) { - TDF_Label aLabel = aNSIter.Label(); - Handle(TNaming_NamedShape) aNS; - if (aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - if (aNS->Evolution() != TNaming_SELECTED && aNS->Evolution() != TNaming_DELETE) { - // check this is new shape in this named shape - bool aIsNew = false; - for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) - if (!aNSIter.NewShape().IsNull() && aNSIter.NewShape().IsSame(theShape)) - aIsNew = true; - if (!aIsNew) - continue; - // check this is the context-shape - while(aLabel.Depth() > aContextLabDepth) - aLabel = aLabel.Father(); - if (aLabel.IsEqual(theContextLab)) - return aNS; - if (aResult.IsNull()) // take the first, otherwise it will get shapes from results, etc - aResult = aNS; // keep some result anyway - if there are no context labels return any - } - } - } - return aResult; -} - -std::string Model_SelectionNaming::getShapeName( - std::shared_ptr theDoc, const TopoDS_Shape& theShape, - ResultPtr& theContext, const bool theAnotherDoc, const bool theWholeContext) -{ - std::string aName; - // add the result name to the name of the shape - // (it was in BodyBuilder, but did not work on Result rename) - bool isNeedContextName = theContext->shape().get() != NULL; - // check if the subShape is already in DF - std::shared_ptr aData = - std::dynamic_pointer_cast(theContext->data()); - TDF_Label aContextDataLab(aData.get() && aData->isValid() ? aData->label() : TDF_Label()); - Handle(TNaming_NamedShape) aNS = shapeToNS(myLab, theShape, aContextDataLab); - Handle(TDataStd_Name) anAttr; - if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document - if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) { - if (isNeedContextName && aData && aContextDataLab.IsEqual(aNS->Label())) { - // do nothing because this context name will be added later in this method - } else { - aName = TCollection_AsciiString(anAttr->Get()).ToCString(); - // indexes are added to sub-shapes not primitives - // (primitives must not be located at the same label) - if(!aName.empty() && aNS->Evolution() != TNaming_PRIMITIVE && isNeedContextName) { - const TDF_Label& aLabel = aNS->Label(); - static const std::string aPostFix("_"); - TNaming_Iterator anItL(aNS); - for(int i = 1; anItL.More(); anItL.Next(), i++) { - // in #1766 IsEqual produced no index of the face - if(anItL.NewShape().IsSame(theShape)) { - aName += aPostFix; - aName += TCollection_AsciiString (i).ToCString(); - break; - } - } - } - // if a shape is under another context, use this name, not theContext - std::shared_ptr aContextData = - std::dynamic_pointer_cast(theContext->data()); - // for constructions the naming is in arguments and has no evolution, so, apply this only - // for bodies - if (isNeedContextName && theContext->groupName() == ModelAPI_ResultBody::group() && - !aNS->Label().IsDescendant(aContextData->label())) { - isNeedContextName = false; - TDF_Label aNSDataLab = aNS->Label(); - if (aNSDataLab.Depth() % 2 == 0) - aNSDataLab = aNSDataLab.Father(); - ObjectPtr aNewContext = theDoc->objects()->object(aNSDataLab); - while(!aNewContext.get() && aNSDataLab.Depth() > 5) { - aNSDataLab = aNSDataLab.Father().Father(); - aNewContext = theDoc->objects()->object(aNSDataLab); - } - if (aNewContext.get()) { - // this is to avoid duplicated names of results problem - std::string aContextName = aNewContext->data()->name(); - // myLab corresponds to the current time - TDF_Label aCurrentLab = myLab; - while(aCurrentLab.Depth() > 3) - aCurrentLab = aCurrentLab.Father(); - - int aNumInHistoryNames = - theDoc->numberOfNameInHistory(aNewContext, aCurrentLab); - while(aNumInHistoryNames > 1) { // add "_" before name the needed number of times - aContextName = "_" + aContextName; - aNumInHistoryNames--; - } - - aName = aContextName + "/" + aName; - } - } - } - } - } - - // Name is empty and this is full context, it just add the whole context name that must be added - bool isEmptyName = aName.empty(); - if (isNeedContextName && (!isEmptyName || theWholeContext)) { - aName = theContext->data()->name() + (isEmptyName ? "" : ("/" + aName)); - if (theAnotherDoc) - aName = theContext->document()->kind() + "/" + aName; // PartSet - } - return aName; -} - -bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap) -{ - // a trivial case: F1 & F2, aNumber = 1, i.e. intersection gives 1 edge. - TopoDS_Compound aCmp; - BRep_Builder BB; - BB.MakeCompound(aCmp); - TopTools_ListIteratorOfListOfShape it(theAncestors); - for(;it.More();it.Next()) { - if (theSMap.Contains(it.Value())) - continue; - BB.Add(aCmp, it.Value()); - theSMap.Add(it.Value()); - } - int aNumber(0); - TopTools_IndexedDataMapOfShapeListOfShape aMap2; - TopExp::MapShapesAndAncestors(aCmp, TopAbs_EDGE, TopAbs_FACE, aMap2); - for (int i = 1; i <= aMap2.Extent(); i++) { - const TopoDS_Shape& aKey = aMap2.FindKey(i); - const TopTools_ListOfShape& anAncestors = aMap2.FindFromIndex(i); - if(anAncestors.Extent() > 1) aNumber++; - } - if(aNumber > 1) return false; - return true; -} - -const TopoDS_Shape findCommonShape( - const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList) -{ - if(theList.Extent() < 1) { - return TopoDS_Shape(); - } else if (theList.Extent() == 1) { // check that sub-shape is bounded by this alone shape - TopTools_MapOfShape aSubsInShape; - TopExp_Explorer anExp(theList.First(), theType); - for(; anExp.More(); anExp.Next()) { - if (aSubsInShape.Contains(anExp.Current())) { // found duplicate - return anExp.Current(); - } - aSubsInShape.Add(anExp.Current()); - } - } - - // Store in maps sub-shapes from each face. - std::vector aVec; - for(TopTools_ListIteratorOfListOfShape anIt(theList); anIt.More(); anIt.Next()) { - const TopoDS_Shape aFace = anIt.Value(); - TopTools_MapOfShape aMap; - for(TopExp_Explorer anExp(aFace, theType); anExp.More(); anExp.Next()) { - const TopoDS_Shape& aSubShape = anExp.Current(); - aMap.Add(anExp.Current()); - } - aVec.push_back(aMap); - } - - // Find sub-shape shared between all faces. - TopoDS_Shape aSharedShape; - for(TopTools_MapIteratorOfMapOfShape anIt(aVec[0]); anIt.More(); anIt.Next()) { - const TopoDS_Shape& aSubShape = anIt.Value(); - int aSharedNb = 1; - for(int anIndex = 1; anIndex < aVec.size(); ++anIndex) { - if(aVec[anIndex].Contains(aSubShape)) { - ++aSharedNb; - } - } - if(aSharedNb == theList.Extent()) { - if(aSharedShape.IsNull()) { - aSharedShape = aSubShape; - } else { - // More than one shape shared between all faces, return null shape in this case. - return TopoDS_Shape(); - } - } - } - - return aSharedShape; -} - -std::string Model_SelectionNaming::vertexNameByEdges(TopoDS_Shape theContext, TopoDS_Shape theSub, - std::shared_ptr theDoc, ResultPtr& theContextRes, const bool theAnotherDoc) -{ - std::string aResult; - TopTools_IndexedDataMapOfShapeListOfShape aMap; - TopExp::MapShapesAndAncestors(theContext, TopAbs_VERTEX, TopAbs_EDGE, aMap); - const TopTools_ListOfShape& aList22 = aMap.FindFromKey(theSub); - if(aList22.Extent() >= 2) { // regular solution - TopTools_MapOfShape aFMap; - TopTools_ListOfShape aListE; - TopTools_ListIteratorOfListOfShape itl2(aList22); - for (int i = 1;itl2.More();itl2.Next(),i++) { - if(aFMap.Add(itl2.Value())) - aListE.Append(itl2.Value()); - } - TopTools_ListIteratorOfListOfShape itl(aListE); - for (int i = 1;itl.More();itl.Next(),i++) { - const TopoDS_Shape& anEdge = itl.Value(); - std::string anEdgeName = getShapeName(theDoc, anEdge, theContextRes, theAnotherDoc, false); - if (anEdgeName.empty()) { // edge is not in DS - aResult.clear(); - return aResult; - } - if(i == 1) - aResult = anEdgeName; - else - aResult += "&" + anEdgeName; - } - } - return aResult; -} - -std::string Model_SelectionNaming::namingName(ResultPtr& theContext, - std::shared_ptr theSubSh, const std::string& theDefaultName, - const bool theAnotherDoc) -{ - std::string aName("Undefined name"); - if(!theContext.get() - || !theContext->shape().get() - || theContext->shape()->isNull()) { - return !theDefaultName.empty() ? theDefaultName : aName; - } - - // if it is in result of another part - std::shared_ptr aDoc = - std::dynamic_pointer_cast(theContext->document()); - if (theContext->groupName() == ModelAPI_ResultPart::group()) { - ResultPartPtr aPart = std::dynamic_pointer_cast(theContext); - int anIndex; - if (theSubSh.get()) - return aPart->data()->name() + "/" + aPart->nameInPart(theSubSh, anIndex); - else - return aPart->data()->name(); - } - - if (!theSubSh.get() || theSubSh->isNull()) { // no subshape, so just the whole feature name - // but if it is in another Part, add this part name - std::string aPartName; - if (theAnotherDoc) - aPartName = theContext->document()->kind() + "/"; // PartSet - return aPartName + theContext->data()->name(); - } - TopoDS_Shape aSubShape = theSubSh->impl(); - TopoDS_Shape aContext = theContext->shape()->impl(); -#ifdef DEB_NAMING - if(aSubShape.ShapeType() == TopAbs_COMPOUND) { - BRepTools::Write(aSubShape, "Selection.brep"); - BRepTools::Write(aContext, "Context.brep"); - } -#endif - aName = getShapeName(aDoc, aSubShape, theContext, theAnotherDoc, - theContext->shape()->isEqual(theSubSh)); - - if(aName.empty() ) { // not in the document! - TopAbs_ShapeEnum aType = aSubShape.ShapeType(); - switch (aType) { - case TopAbs_FACE: - // the Face should be in DF. If it is not the case, it is an error ==> to be debugged - break; - case TopAbs_EDGE: - { - // name structure: F1 & F2 [& F3 & F4], - // where F1 & F2 the faces which gives the Edge in trivial case - // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces - if (BRep_Tool::Degenerated(TopoDS::Edge(aSubShape))) { - aName = "Degenerated_Edge"; - break; - } - TopTools_IndexedDataMapOfShapeListOfShape aMap; - TopExp::MapShapesAndAncestors(aContext, TopAbs_EDGE, TopAbs_FACE, aMap); - TopTools_IndexedMapOfShape aSMap; // map for ancestors of the sub-shape - bool isTrivialCase(true); - if(aMap.Contains(aSubShape)) { - const TopTools_ListOfShape& anAncestors = aMap.FindFromKey(aSubShape); - // check that it is not a trivial case (F1 & F2: aNumber = 1) - isTrivialCase = isTrivial(anAncestors, aSMap); - if (!isTrivialCase) { // another try: check that common shape can be processed anyway - isTrivialCase = !findCommonShape(TopAbs_EDGE, anAncestors).IsNull(); - } - } else - break; - TopTools_MapOfShape aNbs; - if(!isTrivialCase) { // find Neighbors - TNaming_Localizer aLocalizer; - TopTools_MapOfShape aMap3; - aLocalizer.FindNeighbourg(aContext, aSubShape, aMap3); - //int n = aMap3.Extent(); - TopTools_MapIteratorOfMapOfShape it(aMap3); - for(;it.More();it.Next()) { - const TopoDS_Shape& aNbShape = it.Key(); // neighbor edge - //TopAbs_ShapeEnum aType = aNbShape.ShapeType(); - const TopTools_ListOfShape& aList = aMap.FindFromKey(aNbShape); - TopTools_ListIteratorOfListOfShape it2(aList); - for(;it2.More();it2.Next()) { - if(aSMap.Contains(it2.Value())) continue; // skip this Face - aNbs.Add(it2.Value()); - } - } - } // else a trivial case - - // build name of the sub-shape Edge - // iterate faces of the context to get stable order, not map-order - TopTools_MapOfShape aStoredFaces; // to avoid duplicates - for(TopExp_Explorer aContExp(aContext, TopAbs_FACE); aContExp.More(); aContExp.Next()) { - const TopoDS_Shape& aFace = aContExp.Current(); - if (aStoredFaces.Contains(aFace) || !(aSMap.Contains(aFace) || aNbs.Contains(aFace))) - continue; - aStoredFaces.Add(aFace); - std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false); - if(aName.empty()) - aName = aFaceName; - else - aName += "&" + aFaceName; - } - } - break; - - case TopAbs_VERTEX: - // name structure (Monifold Topology): - // 1) F1 | F2 | F3 - intersection of 3 faces defines a vertex - trivial case. - // 2) F1 | F2 | F3 [|F4 [|Fn]] - redundant definition, - // but it should be kept as is to obtain safe recomputation - // 2) F1 | F2 - intersection of 2 faces definses a vertex - applicable for case - // when 1 faces is cylindrical, conical, spherical or revolution and etc. - // 3) E1 | E2 | E3 - intersection of 3 edges defines a vertex - when we have case of a shell - // or compound of 2 open faces. - // 4) E1 | E2 - intesection of 2 edges defines a vertex - when we have a case of - // two independent edges (wire or compound) - // implemented 2 first cases - { - TopTools_IndexedDataMapOfShapeListOfShape aMap; - TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_FACE, aMap); - TopTools_ListOfShape aList; - TopTools_MapOfShape aFMap; - // simetimes when group is moved in history, naming may be badly updated, so - // avoid crash in FindFromKey (issue 1842) - if (aMap.Contains(aSubShape)) { - const TopTools_ListOfShape& aList2 = aMap.FindFromKey(aSubShape); - // fix is below - TopTools_ListIteratorOfListOfShape itl2(aList2); - for (int i = 1;itl2.More();itl2.Next(),i++) { - if(aFMap.Add(itl2.Value())) - aList.Append(itl2.Value()); - } - } else - break; - int n = aList.Extent(); - bool isByFaces = n >= 3; - if (isByFaces) { // check that by faces vertex is identified uniquly (2317) - TopoDS_Shape aVertex = findCommonShape(TopAbs_VERTEX, aList); - isByFaces = !aVertex.IsNull() && aVertex.ShapeType() == TopAbs_VERTEX; - } - - if(!isByFaces) { // open topology case or Compound case => via edges - aName = vertexNameByEdges(aContext, aSubShape, aDoc, theContext, theAnotherDoc); - isByFaces = aName.empty(); - if (isByFaces) { // try to find a vertex in sketch faces - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(theContext); - if (aConstr.get() && aConstr->facesNum()) { - for(int aFace = aConstr->facesNum() - 1; isByFaces && aFace >= 0; aFace--) { - std::shared_ptr aGFace = aConstr->face(aFace); - aName = vertexNameByEdges(aGFace->impl(), aSubShape, - aDoc, theContext, theAnotherDoc); - isByFaces = aName.empty(); - } - } - } - } - - if (isByFaces) { - TopTools_ListIteratorOfListOfShape itl(aList); - for (int i = 1;itl.More();itl.Next(),i++) { - const TopoDS_Shape& aFace = itl.Value(); - std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false); - if(i == 1) - aName = aFaceName; - else - aName += "&" + aFaceName; - } - } - } - break; - } - } - return aName; -} - -TopAbs_ShapeEnum translateType (const std::string& theType) -{ - // map from the textual shape types to OCCT enumeration - static std::map aShapeTypes; - - if(aShapeTypes.size() == 0) { - aShapeTypes["compound"] = TopAbs_COMPOUND; - aShapeTypes["compounds"] = TopAbs_COMPOUND; - aShapeTypes["compsolid"] = TopAbs_COMPSOLID; - aShapeTypes["compsolids"] = TopAbs_COMPSOLID; - aShapeTypes["solid"] = TopAbs_SOLID; - aShapeTypes["solids"] = TopAbs_SOLID; - aShapeTypes["shell"] = TopAbs_SHELL; - aShapeTypes["shells"] = TopAbs_SHELL; - aShapeTypes["face"] = TopAbs_FACE; - aShapeTypes["faces"] = TopAbs_FACE; - aShapeTypes["wire"] = TopAbs_WIRE; - aShapeTypes["wires"] = TopAbs_WIRE; - aShapeTypes["edge"] = TopAbs_EDGE; - aShapeTypes["edges"] = TopAbs_EDGE; - aShapeTypes["vertex"] = TopAbs_VERTEX; - aShapeTypes["vertices"] = TopAbs_VERTEX; - aShapeTypes["COMPOUND"] = TopAbs_COMPOUND; - aShapeTypes["COMPOUNDS"] = TopAbs_COMPOUND; - aShapeTypes["COMPSOLID"] = TopAbs_COMPSOLID; - aShapeTypes["COMPSOLIDS"] = TopAbs_COMPSOLID; - aShapeTypes["SOLID"] = TopAbs_SOLID; - aShapeTypes["SOLIDS"] = TopAbs_SOLID; - aShapeTypes["SHELL"] = TopAbs_SHELL; - aShapeTypes["SHELLS"] = TopAbs_SHELL; - aShapeTypes["FACE"] = TopAbs_FACE; - aShapeTypes["FACES"] = TopAbs_FACE; - aShapeTypes["WIRE"] = TopAbs_WIRE; - aShapeTypes["WIRES"] = TopAbs_WIRE; - aShapeTypes["EDGE"] = TopAbs_EDGE; - aShapeTypes["EDGES"] = TopAbs_EDGE; - aShapeTypes["VERTEX"] = TopAbs_VERTEX; - aShapeTypes["VERTICES"] = TopAbs_VERTEX; - } - if (aShapeTypes.find(theType) != aShapeTypes.end()) - return aShapeTypes[theType]; - Events_InfoMessage("Model_SelectionNaming", - "Shape type defined in XML is not implemented!").send(); - return TopAbs_SHAPE; -} - -const TopoDS_Shape getShapeFromNS( - const std::string& theSubShapeName, Handle(TNaming_NamedShape) theNS) -{ - TopoDS_Shape aSelection; - std::string::size_type n = theSubShapeName.rfind('/'); - if (n == std::string::npos) n = -1; - std::string aSubString = theSubShapeName.substr(n + 1); - n = aSubString.rfind('_'); - int indx = 1; - if (n != std::string::npos) {// for primitives this is a first - // if we have here the same name as theSubShapeName, there is no index in compound, it is whole - Handle(TDataStd_Name) aName; - if (!theNS->Label().FindAttribute(TDataStd_Name::GetID(), aName) || - aName->Get() != aSubString.c_str()) { - aSubString = aSubString.substr(n+1); - indx = atoi(aSubString.c_str()); - } - } - - TNaming_Iterator anItL(theNS); - for(int i = 1; anItL.More(); anItL.Next(), i++) { - if (i == indx) { - return anItL.NewShape(); - } - } - return aSelection; -} - -const TopoDS_Shape findFaceByName( - const std::string& theSubShapeName, std::shared_ptr theDoc, - const ResultPtr theDetectedContext, bool theContextIsUnique) -{ - TopoDS_Shape aFace; - std::string aSubString = theSubShapeName; - - static const ResultPtr anEmpty; - TDF_Label aLabel = theDoc->findNamingName(aSubString, - theContextIsUnique ? theDetectedContext : anEmpty); - if (aLabel.IsNull()) { // try to remove additional artificial suffix - std::string::size_type n = aSubString.rfind('_'); - if (n != std::string::npos) { - aSubString = aSubString.substr(0, n); - aLabel = theDoc->findNamingName(aSubString, - theContextIsUnique ? theDetectedContext : anEmpty); - } - } - if(aLabel.IsNull()) return aFace; - Handle(TNaming_NamedShape) aNS; - if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aFace = getShapeFromNS(theSubShapeName, aNS); - } - return aFace; -} - -size_t ParseName(const std::string& theSubShapeName, std::list& theList) -{ - std::string aName = theSubShapeName; - std::string aLastName = aName; - size_t n1(0), n2(0); // n1 - start position, n2 - position of the delimiter - while ((n2 = aName.find('&', n1)) != std::string::npos) { - const std::string aName1 = aName.substr(n1, n2 - n1); //name of face - theList.push_back(aName1); - n1 = n2 + 1; - aLastName = aName.substr(n1); - } - if(!aLastName.empty()) - theList.push_back(aLastName); - return theList.size(); -} - -std::string getContextName(const std::string& theSubShapeName) -{ - std::string aName; - std::string::size_type n = theSubShapeName.find('/'); - if (n == std::string::npos) return theSubShapeName; - aName = theSubShapeName.substr(0, n); - return aName; -} - -/// Parses naming name of sketch sub-elements: takes indices and orientation -/// (if theOriented = true) from this name. Map theIDs constains indices -> -/// orientations and start/end vertices: negative is reversed, 2 - start, 3 - end -bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names - const std::string& theName, const char* theShapeType, - std::map& theIDs, const bool theOriented = false) -{ - // collect all IDs in the name - std::map aNames; // short name of sub -> ID of sub of theComp - const int aSubNum = theComp->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - FeaturePtr aSub = theComp->subFeature(a); - const std::list >& aResults = aSub->results(); - std::list >::const_iterator aRes = aResults.cbegin(); - // there may be many shapes (circle and center) - for(; aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(*aRes); - if (aConstr.get()) { - aNames[Model_SelectionNaming::shortName(aConstr)] = theComp->subFeatureId(a); - } - } - } - - size_t aPrevPos = theName.find("/") + 1, aLastNamePos; - bool isShape = false; // anyway the first world must be 'Vertex' - do { - aLastNamePos = theName.find('-', aPrevPos); - std::string anID = theName.substr(aPrevPos, aLastNamePos - aPrevPos); - if (!isShape) { - if (anID != theShapeType) - return false; - isShape = true; - } else { - int anOrientation = 1; // default - if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r' - std::string::iterator aSymbol = anID.end() - 1; - if (*aSymbol == 'r') anOrientation = -1; - anID.erase(aSymbol); // remove last symbol - } - // check start/end symbols - std::string::iterator aBack = anID.end() - 1; - if (*aBack == 's') { - anOrientation *= 2; - anID.erase(aBack); // remove last symbol - } else if (*aBack == 'e') { - anOrientation *= 3; - anID.erase(aBack); // remove last symbol - } - - if (aNames.find(anID) != aNames.end()) { - theIDs[aNames[anID]] = anOrientation; - } - } - aPrevPos = aLastNamePos + 1; - } while (aLastNamePos != std::string::npos); - return true; -} - -/// produces theEdge orientation relatively to theContext face -int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge) -{ - if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE) - return 0; - if (theEdge.Orientation() == TopAbs_FORWARD) - return 1; - if (theEdge.Orientation() == TopAbs_REVERSED) - return -1; - return 0; // unknown -} - -int Model_CurvesHasher::HashCode(const Handle(Geom_Curve)& theCurve, const Standard_Integer Upper) -{ - double aFirstParam = theCurve->FirstParameter(); - if (aFirstParam < -1.e+100 || aFirstParam > 1.e+100) - aFirstParam = 0; - double aLastParam = theCurve->LastParameter(); - if (aLastParam < -1.e+100 || aLastParam > 1.e+100) - aLastParam = 2; - else aLastParam = (aLastParam + aFirstParam) / 2.; // to avoid in periodic same first and last - - gp_XYZ aCoordSum = theCurve->Value(aFirstParam).XYZ() + theCurve->Value(aLastParam).XYZ(); - return ::HashCode(aCoordSum.X() + aCoordSum.Y() / 123. + aCoordSum.Z() / 123456., Upper); -} -bool Model_CurvesHasher::IsEqual(const Handle(Geom_Curve)& theC1, const Handle(Geom_Curve)& theC2) -{ - if (theC1->DynamicType() != theC2->DynamicType()) - return false; - double aFirstParam1 = theC1->FirstParameter(); - if (aFirstParam1 < -1.e+100 || aFirstParam1 > 1.e+100) - aFirstParam1 = 0; - double aFirstParam2 = theC2->FirstParameter(); - if (aFirstParam2 < -1.e+100 || aFirstParam2 > 1.e+100) - aFirstParam2 = 0; - if (fabs(aFirstParam1 - aFirstParam2) > 1.e-9) - return false; - - double aLastParam1 = theC1->LastParameter(); - if (aLastParam1 < -1.e+100 || aLastParam1 > 1.e+100) - aLastParam1 = 2.; - else aLastParam1 = (aLastParam1 + aFirstParam1) / 2.; // to avoid in periodic same first and last - double aLastParam2 = theC2->LastParameter(); - if (aLastParam2 < -1.e+100 || aLastParam2 > 1.e+100) - aLastParam2 = 2.; - else aLastParam2 = (aLastParam2 + aFirstParam2) / 2.; // to avoid in periodic same first and last - - if (fabs(aLastParam1 - aLastParam2) > 1.e-9) - return false; - - return theC1->Value(aFirstParam1).IsEqual(theC2->Value(aFirstParam2), Precision::Confusion()) && - theC1->Value(aLastParam1).IsEqual(theC2->Value(aLastParam2), Precision::Confusion()); -} - -int Model_EdgesHasher::HashCode(const TopoDS_Edge& theEdge, const Standard_Integer Upper) -{ - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast); - return Model_CurvesHasher::HashCode(aCurve, Upper); -} - -bool Model_EdgesHasher::IsEqual(const TopoDS_Edge& theE1, const TopoDS_Edge& theE2) -{ - GeomEdgePtr aSh1(new GeomAPI_Edge); - aSh1->setImpl(new TopoDS_Shape(theE1)); - GeomEdgePtr aSh2(new GeomAPI_Edge); - aSh2->setImpl(new TopoDS_Shape(theE2)); - return aSh1->isEqual(aSh2); -} - -std::shared_ptr Model_SelectionNaming::findAppropriateFace( - std::shared_ptr& theConstr, - NCollection_DataMap& theCurves, const bool theIsWire) -{ - int aBestFound = 0; // best number of found edges (not percentage: issue 1019) - int aBestNotFound = 1000000; // best number of not found edges (must be minimum) - int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation - std::shared_ptr aResult; - ResultConstructionPtr aConstructionContext = - std::dynamic_pointer_cast(theConstr); - if (!aConstructionContext.get()) - return aResult; - for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) { - int aFound = 0, aNotFound = 0, aSameOrientation = 0; - TopoDS_Face aFace = - TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl()); - std::list aFacesWires; // faces or wires to iterate - if (theIsWire) { - for(TopExp_Explorer aWires(aFace, TopAbs_WIRE); aWires.More(); aWires.Next()) { - aFacesWires.push_back(aWires.Current()); - } - } else { - aFacesWires.push_back(aFace); - } - std::list::iterator aFW = aFacesWires.begin(); - for(; aFW != aFacesWires.end(); aFW++) { - TopExp_Explorer anEdgesExp(*aFW, TopAbs_EDGE); - TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curves (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 (theCurves.IsBound(aCurve)) { - aFound++; - int anOrient = theCurves.Find(aCurve); - if (anOrient != 0) { // extra comparision score is orientation - if (edgeOrientation(aFace, anEdge) == anOrient) - aSameOrientation++; - } - } else { - aNotFound++; - } - } - } - if (theIsWire && aFound + aNotFound != 0) { - if (aBestNotFound > aNotFound || (aBestNotFound == aNotFound && aFound > aBestFound) || - (aBestNotFound == aNotFound && aFound == aBestFound && aSameOrientation > aBestOrient)) { - aBestFound = aFound; - aBestOrient = aSameOrientation; - aBestNotFound = aNotFound; - std::shared_ptr aWire(new GeomAPI_Wire); - aWire->setImpl(new TopoDS_Shape(*aFW)); - aResult = aWire; - } - aFound = 0; - aNotFound = 0; - aSameOrientation = 0; - } - } - if (!theIsWire) { - if (aFound + aNotFound != 0) { - if (aBestNotFound > aNotFound || (aBestNotFound == aNotFound && aFound > aBestFound) || - (aBestNotFound == aNotFound && aFound == aBestFound && aSameOrientation > aBestOrient)) { - aBestFound = aFound; - aBestOrient = aSameOrientation; - aBestNotFound = aNotFound; - aResult = aConstructionContext->face(aFaceIndex); - } - } - } - } - return aResult; -} - -std::string Model_SelectionNaming::shortName( - std::shared_ptr& theConstr, const int theEdgeVertexPos) -{ - std::string aName = theConstr->data()->name(); - // remove "-", "/" and "&" command-symbols - aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end()); - aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end()); - aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end()); - if (aName.empty()) - return ""; - // remove the last 's', 'e', 'f' and 'r' symbols: - // they are used as markers of start/end/forward/rewersed indicators - static const std::string aSyms("sefr"); - std::string::iterator aSuffix = aName.end() - 1; - while(aSyms.find(*aSuffix) != std::string::npos) { - --aSuffix; - } - aName.erase(aSuffix + 1, aName.end()); - - if (theEdgeVertexPos == 1) { - aName += "s"; // start - } else if (theEdgeVertexPos == 2) { - aName += "e"; // end - } - return aName; -} - -// type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT -bool Model_SelectionNaming::selectSubShape(const std::string& theType, - const std::string& theSubShapeName, std::shared_ptr theDoc, - std::shared_ptr& theShapeToBeSelected, std::shared_ptr& theCont) -{ - if(theSubShapeName.empty() || theType.empty()) return false; - TopAbs_ShapeEnum aType = translateType(theType); - - // check that it was selected in another document - size_t aSlash = theSubShapeName.find("/"); - std::string aSubShapeName = theSubShapeName; - std::shared_ptr aDoc = theDoc; - if (aSlash != std::string::npos) { - std::string aDocName = theSubShapeName.substr(0, aSlash); - ResultPartPtr aFoundPart; - DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); - if (aDocName == aRootDoc->kind()) { - aDoc = std::dynamic_pointer_cast(aRootDoc); - } else { - for (int a = aRootDoc->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) { - ResultPartPtr aPart = std::dynamic_pointer_cast( - aRootDoc->object(ModelAPI_ResultPart::group(), a)); - if (aPart.get() && aPart->isActivated() && aPart->data()->name() == aDocName) { - aDoc = std::dynamic_pointer_cast(aPart->partDoc()); - aFoundPart = aPart; - break; - } - } - } - if (aDoc != theDoc) { - // so, the first word is the document name => reduce the string for the next manips - aSubShapeName = theSubShapeName.substr(aSlash + 1); - if (aSubShapeName.empty() && aFoundPart.get()) { // the whole Part result - theCont = aFoundPart; - return true; - } - } - } - - std::string aContName = getContextName(aSubShapeName); - if(aContName.empty()) return false; - bool anUniqueContext = false; - ResultPtr aCont = aDoc->findByName(aContName, aSubShapeName, anUniqueContext); - // possible this is body where postfix is added to distinguish several shapes on the same label - int aSubShapeId = -1; // -1 means sub shape not found - // for result body the name wihtout "_" has higher priority than with it: it is always added - if ((!aCont.get()/* || (aCont->groupName() == ModelAPI_ResultBody::group())*/) && - aContName == aSubShapeName) { - size_t aPostIndex = aContName.rfind('_'); - if (aPostIndex != std::string::npos) { - std::string anEmpty, aSubContName = aContName.substr(0, aPostIndex); - ResultPtr aSubCont = aDoc->findByName(aSubContName, anEmpty, anUniqueContext); - if (aSubCont.get()) { - try { - std::string aNum = aContName.substr(aPostIndex + 1); - aSubShapeId = std::stoi(aNum); - } catch (std::invalid_argument&) { - aSubShapeId = -1; - } - if (aSubShapeId > 0) { - aContName = aSubContName; - aCont = aSubCont; - } - } - } - } - - - static const ResultPtr anEmpty; - TopoDS_Shape aSelection; - switch (aType) - { - case TopAbs_FACE: - case TopAbs_WIRE: - { - aSelection = findFaceByName(aSubShapeName, aDoc, aCont, anUniqueContext); - } - break; - case TopAbs_EDGE: - { - const TDF_Label& aLabel = - aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); - if(!aLabel.IsNull()) { - Handle(TNaming_NamedShape) aNS; - if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aSelection = getShapeFromNS(aSubShapeName, aNS); - } - } - } - break; - case TopAbs_VERTEX: - { - const TDF_Label& aLabel = - aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); - if(!aLabel.IsNull()) { - Handle(TNaming_NamedShape) aNS; - if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aSelection = getShapeFromNS(aSubShapeName, aNS); - } - } - } - break; - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - case TopAbs_SOLID: - case TopAbs_SHELL: - default: {//TopAbs_SHAPE - /// case when the whole sketch is selected, so, - /// selection type is compound, but there is no value - if (aCont.get() && aCont->shape().get()) { - if (aCont->shape()->impl().ShapeType() == aType) { - theCont = aCont; - return true; - } else if (aSubShapeId > 0) { // try to find sub-shape by the index - TopExp_Explorer anExp(aCont->shape()->impl(), aType); - for(; aSubShapeId > 1 && anExp.More(); aSubShapeId--) { - anExp.Next(); - } - if (anExp.More()) { - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current())); - theShapeToBeSelected = aShapeToBeSelected; - theCont = aCont; - return true; - } - } - } - return false; - } - } - if (!aSelection.IsNull() && - aSelection.ShapeType() != aType && aSelection.ShapeType() != TopAbs_COMPOUND) - aSelection.Nullify(); // to avoid selection of face instead of edge that is described by face - // another try to find edge or vertex by faces - std::list aListofNames; - size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0; - if ((aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) || - (!aSelection.IsNull() && aSelection.ShapeType() != aType)) { // edge by one face as example - if(aN >= 1) { - TopTools_ListOfShape aList; - std::list::iterator it = aListofNames.begin(); - for(; it != aListofNames.end(); it++) { - ResultPtr aFaceContext = aCont; - if (it != aListofNames.begin()) { // there may be other context for different sub-faces - std::string aContName = getContextName(*it); - if(!aContName.empty()) { - aFaceContext = aDoc->findByName(aContName, *it, anUniqueContext); - } - } - TopoDS_Shape aFace = findFaceByName(*it, aDoc, aFaceContext, anUniqueContext); - if (aFace.IsNull() && aFaceContext.get() && - aFaceContext->groupName() == ModelAPI_ResultConstruction::group() ) { - // search the construction sub-elements for the intersection if they are in the tree - size_t aSlash = it->find("/"); - if (aSlash != std::string::npos) { - std::string aSubShapeName = it->substr(aSlash + 1); - aFace = findFaceByName(aSubShapeName, aDoc, aFaceContext, true); - } - } - if(!aFace.IsNull()) - aList.Append(aFace); - } - aSelection = findCommonShape(aType, aList); - //if (aSelection.IsNull() && aType == TopAbs_EDGE) { // try to find selection by neighbours - // aSelection = findCommonShapeByNB(aType, TopAbs_VERTEX, aList); - //} - } - } - // in case of construction, there is no registered names for all sub-elements, - // even for the main element; so, trying to find them by name (without "&" intersections) - if (aSelection.IsNull() && aN < 2) { - size_t aConstrNamePos = aSubShapeName.find("/"); - bool isFullName = aConstrNamePos == std::string::npos; - std::string anEmpty, aContrName = aContName; - ResultPtr aConstr = aDoc->findByName(aContrName, anEmpty, anUniqueContext); - if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) { - theCont = aConstr; - if (isFullName) { - // For the full construction selection shape must be empty. - //theShapeToBeSelected = aConstr->shape(); - return true; - } - // for sketch sub-elements selected - CompositeFeaturePtr aComposite = - std::dynamic_pointer_cast(aDoc->feature(aConstr)); - if (aComposite.get()) { - if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) { - // collect all IDs in the name - bool isVertexByEdge = false; - std::map anIDs; - if (!parseSubIndices(aComposite, aSubShapeName, - aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs)) { - // there is a case when vertex is identified by one circle-edge (2253) - if (aType == TopAbs_VERTEX && - parseSubIndices(aComposite, aSubShapeName, "Edge", anIDs)) - isVertexByEdge = true; - else - return false; - } - - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - int aCompID = aComposite->subFeatureId(a); - if (anIDs.find(aCompID) != anIDs.end()) { // found the vertex/edge shape - FeaturePtr aSub = aComposite->subFeature(a); - const std::list >& aResults = aSub->results(); - std::list >::const_iterator aRIt = aResults.cbegin(); - // there may be many shapes (circle and center) - for(; aRIt != aResults.cend(); aRIt++) { - ResultConstructionPtr aRes = - std::dynamic_pointer_cast(*aRIt); - if (aRes) { - int anOrientation = abs(anIDs[aCompID]); - TopoDS_Shape aShape = aRes->shape()->impl(); - if (anOrientation == 1) { - if (!isVertexByEdge && aType == aShape.ShapeType()) { - theShapeToBeSelected = aRes->shape(); - return true; - } else if (isVertexByEdge && aType != aShape.ShapeType()) { - // check that there is only one vertex produces by and circular edge - TopoDS_Shape aShape = aRes->shape()->impl(); - TopExp_Explorer anExp(aShape, TopAbs_VERTEX); - if (anExp.More()) - aShape = anExp.Current(); - anExp.Next(); - if (!anExp.More() || anExp.Current().IsSame(aShape)) { - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(aShape)); - theShapeToBeSelected = aShapeToBeSelected; - return true; - } - } - } else { // take first or second vertex of the edge - TopoDS_Shape aShape = aRes->shape()->impl(); - if (aShape.ShapeType() == TopAbs_VERTEX) continue; - TopExp_Explorer anExp(aShape, aType); - for(; anExp.More() && anOrientation != 2; anOrientation--) - anExp.Next(); - if (anExp.More()) { - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current())); - theShapeToBeSelected = aShapeToBeSelected; - return true; - } - } - } - } - } - } - // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" - } else if (aType == TopAbs_FACE || aType == TopAbs_WIRE) { - std::map anIDs; - if (!parseSubIndices(aComposite, aSubShapeName, - aType == TopAbs_FACE ? "Face" : "Wire", anIDs, true)) - return false; - - // 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 (anIDs.find(aSubID) != anIDs.end()) { - 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); - allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1); - } - } - } - } - } - std::shared_ptr aFoundFW = - findAppropriateFace(aConstr, allCurves, aType == TopAbs_WIRE); - if (aFoundFW.get()) { - theShapeToBeSelected = aFoundFW; - return true; - } - } else if (aType == TopAbs_WIRE) { - // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" - std::map anIDs; - if (!parseSubIndices(aComposite, aSubShapeName, "Wire", anIDs)) - return false; - - // 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 (anIDs.find(aSubID) != anIDs.end()) { - 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); - allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1); - } - } - } - } - } - std::shared_ptr aFoundFW = - findAppropriateFace(aConstr, allCurves, aType == TopAbs_WIRE); - if (aFoundFW.get()) { - theShapeToBeSelected = aFoundFW; - return true; - } - } - } - } - } else if (aSelection.IsNull() && aN >= 2 && aType == TopAbs_VERTEX) { - // support of shape name as intersection separated by "&" - static std::string anEdgeType = "edge"; // for now it works only with su-edges - std::list::iterator aSubNames = aListofNames.begin(); - TopTools_ListOfShape aSubsList; - for(; aSubNames != aListofNames.end(); aSubNames++) { - std::string aSubName = *aSubNames; - std::shared_ptr aSubShapeFound; - std::shared_ptr aContextFound; - if (selectSubShape(anEdgeType, aSubName, theDoc, aSubShapeFound, aContextFound)) { - if (aSubShapeFound.get()) - aSubsList.Append(aSubShapeFound->impl()); - } - } - aSelection = findCommonShape(TopAbs_VERTEX, aSubsList); - } - if (!aSelection.IsNull()) { - // Select it (must be after N=0 checking, - // since for simple constructions the shape must be null) - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); - theShapeToBeSelected = aShapeToBeSelected; - theCont = aCont; - return true; - } - - return false; -} diff --git a/src/Model/Model_SelectionNaming.h b/src/Model/Model_SelectionNaming.h deleted file mode 100644 index 3494369df..000000000 --- a/src/Model/Model_SelectionNaming.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2014-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 Model_SelectionNaming_H_ -#define Model_SelectionNaming_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -// class to compare curves in the same way as in GeomAPI_Edge -class Model_CurvesHasher -{ -public: - DEFINE_STANDARD_ALLOC - /// standard hash code - static int HashCode (const Handle(Geom_Curve)& theCurve, const Standard_Integer Upper); - /// comapre curves by parameters and points on them - static bool IsEqual (const Handle(Geom_Curve)& theC1, const Handle(Geom_Curve)& theC2); -}; - -// class to compare edges in the same way as in GeomAPI_Edge -class Model_EdgesHasher -{ -public: - DEFINE_STANDARD_ALLOC - /// standard hash code - static int HashCode (const TopoDS_Edge& theEdge, const Standard_Integer Upper); - /// comapre curves by parameters and points on them - static bool IsEqual (const TopoDS_Edge& theE1, const TopoDS_Edge& theE2); -}; - - -/**\class Model_SelectionNaming - * \ingroup DataModel - * \brief The set of methods that allow to generate a string-name for the selection attribute. - */ -class Model_SelectionNaming -{ - TDF_Label myLab; ///< Selection label of the selection attribute -public: - /// Constructor for the selection attribute by the selection label - Model_SelectionNaming(TDF_Label theSelectionLab); - - /// Produces the string-name for the selected shape - std::string namingName(ResultPtr& theContext, std::shared_ptr theSubSh, - const std::string& theDefaultName, const bool theAnotherDoc); - - /// Makes a selection by the string-name - /// \param theType string of the type of the shape - /// \param theSubShapeName string-identifier of the selected shape - /// \param theDoc document where the selected shape is searched - /// \param theShapeToBeSelected resulting selected shape - /// \param theCont the selection context of the resulting selected shape - bool selectSubShape(const std::string& theType, const std::string& theSubShapeName, - std::shared_ptr theDoc, std::shared_ptr& theShapeToBeSelected, - std::shared_ptr& theCont); - - /// Searches the face more appropriate to the given curves - /// (with higher level of matched parameters) - /// \param theConstr construction result that contains one or several faces - /// \param theCurves map from the face edges curves to orientation - /// (-1 reversed, 0 unknown, 1 forward) - /// \param theIsWire for wire algorithm isquite the same, - /// but if in face several wires, it returns the needed wire - /// \returns faces fron this construction if found - static std::shared_ptr findAppropriateFace( - std::shared_ptr& theConstr, - NCollection_DataMap& theCurves, - const bool theIsWire); - - /// Returns orientation of the edge in the context shape - static int edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge); - - /// Returns the name of sketch sub-element, shortened by exclusion of some symbols and with added - /// the vertex position (if needed) - /// \param theConstr result with name - basis for the name - /// \param theEdgeVertexPos position of the vertex on edge: 1 - first , 2 - second - /// \returns the generated name - static std::string shortName(std::shared_ptr& theConstr, - const int theEdgeVertexPos = 0); - -protected: - /// Gets the stored name from the document - std::string getShapeName(std::shared_ptr theDoc, const TopoDS_Shape& theShape, - ResultPtr& theContext, const bool theAnotherDoc, const bool theWholeContext); - - /// Tries to find the name of the context sub-shape as combination of edges in context - std::string vertexNameByEdges(TopoDS_Shape theContext, TopoDS_Shape theSub, - std::shared_ptr theDoc, ResultPtr& theContextRes, const bool theAnotherDoc); -}; - -#endif diff --git a/src/Selector/Selector_Selector.cpp b/src/Selector/Selector_Selector.cpp index fa1f562b1..c514b8c12 100644 --- a/src/Selector/Selector_Selector.cpp +++ b/src/Selector/Selector_Selector.cpp @@ -805,6 +805,7 @@ TDF_Label Selector_Selector::restoreByName( case TopAbs_WIRE: myType = SELTYPE_CONTAINER; break; + case TopAbs_VERTEX: case TopAbs_EDGE: case TopAbs_FACE: myType = SELTYPE_INTERSECT; @@ -825,7 +826,7 @@ TDF_Label Selector_Selector::restoreByName( if (aSubContext.IsNull()) return aSubContext; // invalid sub-selection parsing if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { - if (theNameGenerator->isLater(aSubContext, aContext)) + if (!theNameGenerator->isLater(aContext, aSubContext)) aContext = aSubContext; } else { aContext = aSubContext; @@ -848,7 +849,7 @@ TDF_Label Selector_Selector::restoreByName( if (aSubContext.IsNull()) return aSubContext; // invalid sub-selection parsing if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { - if (theNameGenerator->isLater(aSubContext, aContext)) + if (!theNameGenerator->isLater(aContext, aSubContext)) aContext = aSubContext; } else { aContext = aSubContext; -- 2.30.2