From 20a4d4c668c7f75553424222dab81569816e548f Mon Sep 17 00:00:00 2001 From: mpv Date: Wed, 10 Aug 2016 13:33:01 +0300 Subject: [PATCH] Reading of the construction naming name support (in the frames of Dump Python issue #1648) --- src/FeaturesAPI/FeaturesAPI_Recover.cpp | 7 + src/Model/Model_AttributeSelection.cpp | 55 +---- src/Model/Model_SelectionNaming.cpp | 300 ++++++++++++++++++------ src/Model/Model_SelectionNaming.h | 14 ++ 4 files changed, 257 insertions(+), 119 deletions(-) diff --git a/src/FeaturesAPI/FeaturesAPI_Recover.cpp b/src/FeaturesAPI/FeaturesAPI_Recover.cpp index 4fdf104f7..30b22e131 100644 --- a/src/FeaturesAPI/FeaturesAPI_Recover.cpp +++ b/src/FeaturesAPI/FeaturesAPI_Recover.cpp @@ -9,12 +9,14 @@ #include #include +//================================================================================================= FeaturesAPI_Recover::FeaturesAPI_Recover(const std::shared_ptr& theFeature) : ModelHighAPI_Interface(theFeature) { initialize(); } +//================================================================================================= FeaturesAPI_Recover::FeaturesAPI_Recover(const std::shared_ptr& theFeature, const ModelHighAPI_Reference& theBaseFeature, const std::list& theRecoveredList, const bool thePersistent) @@ -27,27 +29,32 @@ FeaturesAPI_Recover::FeaturesAPI_Recover(const std::shared_ptr } } +//================================================================================================= FeaturesAPI_Recover::~FeaturesAPI_Recover() {} +//================================================================================================= void FeaturesAPI_Recover::setBaseFeature(const ModelHighAPI_Reference& theBaseFeature) { fillAttribute(theBaseFeature, mybaseFeature); // do not need to execute because on attribute changed it does everything anyway } +//================================================================================================= void FeaturesAPI_Recover::setRecoveredList(const std::list& theRecoverList) { fillAttribute(theRecoverList, myrecoveredList); // do not need to execute because on attribute changed it does everything anyway } +//================================================================================================= void FeaturesAPI_Recover::setIsPersistent(bool thePersistent) { fillAttribute(thePersistent, myisPersistent); // do not need to execute because on attribute changed it does everything anyway } +//================================================================================================= RecoverPtr addRecover(const std::shared_ptr& thePart, const ModelHighAPI_Reference& theBaseFeature, const std::list& theRecoveredList, const bool thePersistent) diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 92b91327c..33326b351 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -373,19 +373,6 @@ TDF_LabelMap& Model_AttributeSelection::scope() return myScope; } -/// produces theEdge orientation relatively to theContext face -int edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge) -{ - if (theContext.ShapeType() != TopAbs_FACE) - return 0; - TopoDS_Face aContext = TopoDS::Face(theContext); - if (theEdge.Orientation() == TopAbs_FORWARD) - return 1; - if (theEdge.Orientation() == TopAbs_REVERSED) - return -1; - return 0; // unknown -} - /// Sets the invalid flag if flag is false, or removes it if "true" /// Returns theFlag static bool setInvalidIfFalse(TDF_Label& theLab, const bool theFlag) { @@ -520,43 +507,7 @@ bool Model_AttributeSelection::update() } } } - int aBestFound = 0; // best number of found edges (not percentage: issue 1019) - int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation - for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) { - int aFound = 0, aNotFound = 0, aSameOrientation = 0; - TopoDS_Face aFace = - TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl()); - TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE); - TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841) - for(; anEdgesExp.More(); anEdgesExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (alreadyProcessed.Contains(aCurve)) - continue; - alreadyProcessed.Add(aCurve); - if (allCurves.IsBound(aCurve)) { - aFound++; - int anOrient = allCurves.Find(aCurve); - if (anOrient != 0) { // extra comparision score is orientation - if (edgeOrientation(aFace, anEdge) == anOrient) - aSameOrientation++; - } - } else { - aNotFound++; - } - } - } - if (aFound + aNotFound != 0) { - if (aFound > aBestFound || - (aFound == aBestFound && aSameOrientation > aBestOrient)) { - aBestFound = aFound; - aBestOrient = aSameOrientation; - aNewSelected = aConstructionContext->face(aFaceIndex); - } - } - } + aNewSelected = Model_SelectionNaming::findAppropriateFace(aContext, allCurves); } if (aNewSelected) { // store this new selection if (aShapeType == TopAbs_WIRE) { // just get a wire from face to have wire @@ -790,7 +741,7 @@ void Model_AttributeSelection::selectConstruction( if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { aRefs->Add(aComposite->subFeatureId(a)); } - } else { // get first or last vertex of the edge: last is stored with negative sign + } else { // get first or last vertex of the edge: last is stored with additional delta const TopoDS_Shape& anEdge = aConstr->shape()->impl(); int aDelta = kSTART_VERTEX_DELTA; for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { @@ -820,7 +771,7 @@ void Model_AttributeSelection::selectConstruction( Standard_Real aFirst, aLast; Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); if (aFaceCurve == aCurve) { - int anOrient = edgeOrientation(aSubShape, anEdge); + int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge); anOrientations[anID] = anOrient; registerSubShape( selectionLabel(), anEdge, anID, aContextFeature, aMyDoc, "", anOrientations, diff --git a/src/Model/Model_SelectionNaming.cpp b/src/Model/Model_SelectionNaming.cpp index c577080b1..6f39a650f 100644 --- a/src/Model/Model_SelectionNaming.cpp +++ b/src/Model/Model_SelectionNaming.cpp @@ -26,11 +26,19 @@ #include #include #include +#include +#include +#include + #ifdef DEB_NAMING #include #endif +/// added to the index in the packed map to signalize that the vertex of edge is selected +/// (multiplied by the index of the edge) +static const int kSTART_VERTEX_DELTA = 1000000; + Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab) { myLab = theSelectionLab; @@ -126,7 +134,7 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext, break; case TopAbs_EDGE: { - // name structure: F1 | F2 [| F3 | F4], where F1 & F2 the faces which gives the Edge in trivial case + // 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"; @@ -455,6 +463,103 @@ std::string getContextName(const std::string& theSubShapeName) return aName; } +/// Parses naming name of sketch sub-elements: takes indices and orientation +/// (if theOriented = true) from this name. Map theIDs constains indices -> +/// orientations (true by default) +bool parseSubIndices(const std::string& theName, const char* theShapeType, + std::map& theIDs, const bool theOriented = false) +{ + // collect all IDs in the name + std::set anIDs; + size_t aPrevPos = theName.find("/") + 1, aLastNamePos; + bool isShape = false; // anyway the first world must be 'Vertex' + do { + aLastNamePos = theName.find('-', aPrevPos); + const std::string anID = theName.substr(aPrevPos, aLastNamePos - aPrevPos); + if (!isShape) { + if (anID != theShapeType) + return false; + isShape = true; + } else { + bool anOrientation = true; // default + if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r' + const char aSymbol = theName.back(); + anOrientation = aSymbol == 'f'; + } + int anInt = 0; + try { + anInt = std::stoi(anID, nullptr); + } catch (const std::invalid_argument&) {} + if (anInt != 0) + theIDs[anInt] = 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) + return 0; + TopoDS_Face aContext = TopoDS::Face(theContext); + if (theEdge.Orientation() == TopAbs_FORWARD) + return 1; + if (theEdge.Orientation() == TopAbs_REVERSED) + return -1; + return 0; // unknown +} + +std::shared_ptr Model_SelectionNaming::findAppropriateFace( + std::shared_ptr& theConstr, + NCollection_DataMap& theCurves) +{ + int aBestFound = 0; // best number of found edges (not percentage: issue 1019) + 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()); + TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE); + TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841) + for(; anEdgesExp.More(); anEdgesExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (alreadyProcessed.Contains(aCurve)) + continue; + alreadyProcessed.Add(aCurve); + if (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 (aFound + aNotFound != 0) { + if (aFound > aBestFound || + (aFound == aBestFound && aSameOrientation > aBestOrient)) { + aBestFound = aFound; + aBestOrient = aSameOrientation; + aResult = aConstructionContext->face(aFaceIndex); + } + } + } + return aResult; +} + // 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, @@ -465,40 +570,22 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, std::string aContName = getContextName(theSubShapeName); if(aContName.empty()) return false; ResultPtr aCont = theDoc->findByName(aContName); - if(!aCont.get() || aCont->shape()->isNull()) return false; - TopoDS_Shape aContext = aCont->shape()->impl(); - TopAbs_ShapeEnum aContType = aContext.ShapeType(); - if(aType <= aContType) return false; // not applicable + //if(!aCont.get() || aCont->shape()->isNull()) return false; + //TopoDS_Shape aContext = aCont->shape()->impl(); + //TopAbs_ShapeEnum aContType = aContext.ShapeType(); + //if(aType <= aContType) return false; // not applicable TopoDS_Shape aSelection; switch (aType) { - case TopAbs_COMPOUND: - break; - case TopAbs_COMPSOLID: - break; - case TopAbs_SOLID: - break; - case TopAbs_SHELL: - break; case TopAbs_FACE: { - const TopoDS_Shape aSelection = findFaceByName(theSubShapeName, theDoc); - if(!aSelection.IsNull()) {// Select it - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); - theShapeToBeSelected = aShapeToBeSelected; - theCont = aCont; - return true; - } + aSelection = findFaceByName(theSubShapeName, theDoc); } break; - case TopAbs_WIRE: - break; case TopAbs_EDGE: { - TopoDS_Shape aSelection;// = findFaceByName(theSubShapeName, aDoc); const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName); if(!aLabel.IsNull()) { Handle(TNaming_NamedShape) aNS; @@ -506,31 +593,10 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, aSelection = getShapeFromNS(theSubShapeName, aNS); } } - if(aSelection.IsNull()) { - std::list aListofNames; - size_t n = ParseName(theSubShapeName, aListofNames); - if(n > 1 && n < 5) { - TopTools_ListOfShape aList; - std::list::iterator it =aListofNames.begin(); - for(;it != aListofNames.end();it++){ - const TopoDS_Shape aFace = findFaceByName(*it, theDoc); - aList.Append(aFace); - } - aSelection = findCommonShape(TopAbs_EDGE, aList); - } - } - if(!aSelection.IsNull()) {// Select it - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); - theShapeToBeSelected = aShapeToBeSelected; - theCont = aCont; - return true; - } } break; case TopAbs_VERTEX: { - TopoDS_Shape aSelection; const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName); if(!aLabel.IsNull()) { Handle(TNaming_NamedShape) aNS; @@ -538,32 +604,132 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, aSelection = getShapeFromNS(theSubShapeName, aNS); } } - if(aSelection.IsNull()) { - std::list aListofNames; - size_t n = ParseName(theSubShapeName, aListofNames); - if(n > 1 && n < 4) { // 2 || 3 - TopTools_ListOfShape aList; - std::list::iterator it = aListofNames.begin(); - for(; it != aListofNames.end(); it++){ - const TopoDS_Shape aFace = findFaceByName(*it, theDoc); - if(!aFace.IsNull()) - aList.Append(aFace); - } - aSelection = findCommonShape(TopAbs_VERTEX, aList); - } - } - if(!aSelection.IsNull()) {// Select it - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); - theShapeToBeSelected = aShapeToBeSelected; - theCont = aCont; - return true; - } } break; + case TopAbs_COMPOUND: + case TopAbs_COMPSOLID: + case TopAbs_SOLID: + case TopAbs_SHELL: + case TopAbs_WIRE: default: //TopAbs_SHAPE return false; } + // another try to find edge or vertex by faces + std::list aListofNames; + size_t aN = aSelection.IsNull() ? ParseName(theSubShapeName, aListofNames) : 0; + if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) { + if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE + TopTools_ListOfShape aList; + std::list::iterator it = aListofNames.begin(); + for(; it != aListofNames.end(); it++){ + const TopoDS_Shape aFace = findFaceByName(*it, theDoc); + if(!aFace.IsNull()) + aList.Append(aFace); + } + aSelection = findCommonShape(aType, aList); + } + } + if (!aSelection.IsNull()) {// Select it + std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); + aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); + theShapeToBeSelected = aShapeToBeSelected; + theCont = aCont; + return true; + } + // 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 (aN == 0) { + size_t aConstrNamePos = theSubShapeName.find("/"); + bool isFullName = aConstrNamePos == std::string::npos; + std::string aContrName = + isFullName ? theSubShapeName : theSubShapeName.substr(0, aConstrNamePos); + ResultPtr aConstr = theDoc->findByName(aContrName); + if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) { + theCont = aConstr; + if (isFullName) { + theShapeToBeSelected = aConstr->shape(); + return true; + } + // for sketch sub-elements selected + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(theDoc->feature(aConstr)); + if (aComposite.get()) { + if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) { + // collect all IDs in the name + std::map anIDs; + if (!parseSubIndices(theSubShapeName, aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs)) + 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); + ResultConstructionPtr aV = std::dynamic_pointer_cast + (*(aSub->results().begin())); + if (aV) { + theShapeToBeSelected = aV->shape(); + return true; + } + } else if (aType == TopAbs_VERTEX && + (anIDs.find(aCompID + kSTART_VERTEX_DELTA) != anIDs.end() || + anIDs.find(aCompID + 2 * kSTART_VERTEX_DELTA) != anIDs.end())) { + 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) + for(; aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aE = + std::dynamic_pointer_cast(*aRes); + if (aE && aE->shape()->isEdge()) { + const TopoDS_Shape& anEdge = aE->shape()->impl(); + TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); // first vertex + if (anIDs.find(aCompID + kSTART_VERTEX_DELTA) == anIDs.end()) + aVExp.Next(); // second vertex + std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); + aShapeToBeSelected->setImpl(new TopoDS_Shape(aVExp.Current())); + theShapeToBeSelected = aShapeToBeSelected; + return true; + } + } + } + } + } else if (aType == TopAbs_FACE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" + std::map anIDs; + if (!parseSubIndices(theSubShapeName, "Face", anIDs, true)) + return false; + + NCollection_DataMap allCurves; // curves and orientations of edges + 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] ? 1 : -1); + } + } + } + } + } + std::shared_ptr aFoundFace = findAppropriateFace(aConstr, allCurves); + if (aFoundFace.get()) { + theShapeToBeSelected = aFoundFace; + return true; + } + } + } + } + } return false; } - diff --git a/src/Model/Model_SelectionNaming.h b/src/Model/Model_SelectionNaming.h index 1ecf4ad42..8a7fbfda0 100644 --- a/src/Model/Model_SelectionNaming.h +++ b/src/Model/Model_SelectionNaming.h @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include /**\class Model_SelectionNaming * \ingroup DataModel @@ -39,6 +42,17 @@ public: 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) + /// \returns faces fron this construction if found + static std::shared_ptr findAppropriateFace( + std::shared_ptr& theConstr, + NCollection_DataMap& theCurves); + + /// Returns orientation of the edge in the context shape + static int edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge); + protected: /// Gets the stored name from the document std::string getShapeName(std::shared_ptr theDoc, const TopoDS_Shape& theShape); -- 2.39.2