From f03c02cd62fe508c65818d31fdf9dcf69f8cbf35 Mon Sep 17 00:00:00 2001 From: azv Date: Thu, 22 Aug 2019 16:34:57 +0300 Subject: [PATCH] Issue #2971: Naming issue in a group when loading a dump file Additional dump to change the order of sketch faces if it was changed while editing the model. --- src/FeaturesPlugin/Test/Test2971.py | 9 + src/GeomAPI/GeomAPI_Curve.cpp | 34 +- src/GeomAPI/GeomAPI_Curve.h | 23 ++ src/GeomAPI/GeomAPI_Shape.cpp | 12 - src/GeomAPI/GeomAPI_Shape.h | 3 - src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp | 42 +- src/Model/Model_ResultConstruction.cpp | 391 ++++++++++++------ src/Model/Model_ResultConstruction.h | 3 + src/ModelAPI/ModelAPI_ResultConstruction.h | 2 + src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp | 5 +- src/ModelHighAPI/ModelHighAPI.i | 1 + src/ModelHighAPI/ModelHighAPI_Dumper.cpp | 13 + src/ModelHighAPI/ModelHighAPI_Dumper.h | 4 + src/SketchAPI/CMakeLists.txt | 2 + src/SketchAPI/SketchAPI_Sketch.cpp | 170 ++++++++ src/SketchAPI/SketchAPI_Sketch.h | 4 + 16 files changed, 532 insertions(+), 186 deletions(-) diff --git a/src/FeaturesPlugin/Test/Test2971.py b/src/FeaturesPlugin/Test/Test2971.py index eb880f14d..4116aec42 100644 --- a/src/FeaturesPlugin/Test/Test2971.py +++ b/src/FeaturesPlugin/Test/Test2971.py @@ -291,6 +291,15 @@ SketchLine_33.result().setName("SketchLine_36") model.do() Sketch_3.setName("PHomoProfile") Sketch_3.result().setName("PHomoProfile") +Sketch_3.changeFacesOrder([[SketchLine_25.result(), SketchArc_9.results()[1], SketchLine_27.result(), SketchLine_27.result(), SketchLine_26.result()], + [SketchLine_29.result(), SketchLine_31.result(), SketchArc_9.results()[1], SketchLine_26.result()], + [SketchLine_27.result(), SketchLine_30.result(), SketchLine_29.result(), SketchLine_26.result()], + [SketchArc_9.results()[1], SketchLine_31.result(), SketchLine_30.result(), SketchLine_27.result()], + [SketchLine_33.result(), SketchLine_37.result(), SketchLine_37.result(), SketchArc_10.results()[1], SketchLine_25.result()], + [SketchLine_33.result(), SketchArc_10.results()[1], SketchLine_35.result(), SketchLine_34.result()], + [SketchLine_33.result(), SketchLine_34.result(), SketchLine_36.result(), SketchLine_37.result()], + [SketchArc_10.results()[1], SketchLine_37.result(), SketchLine_36.result(), SketchLine_35.result()] + ]) Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-PHomoProfile")], model.selection(), "ep_homo", 0) Partition_1_objects = [model.selection("SOLID", "Remove_SubShapes_1_1"), model.selection("COMPSOLID", "Recover_1_1"), model.selection("COMPSOLID", "Extrusion_2_1")] Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects) diff --git a/src/GeomAPI/GeomAPI_Curve.cpp b/src/GeomAPI/GeomAPI_Curve.cpp index 07fb93d65..142a9ff5f 100644 --- a/src/GeomAPI/GeomAPI_Curve.cpp +++ b/src/GeomAPI/GeomAPI_Curve.cpp @@ -21,9 +21,10 @@ #include #include +#include #include #include -#include +#include #include #include #include @@ -70,3 +71,34 @@ std::shared_ptr GeomAPI_Curve::getPoint(double theParam) gp_Pnt aPnt = aAdaptor.Value(theParam); return std::shared_ptr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z())); } + +bool GeomAPI_Curve::isEqual(const std::shared_ptr& theOther) const +{ + return MY_CURVE == theOther->impl(); +} + +bool GeomAPI_Curve::isTrimmed() const +{ + return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve); +} + +GeomCurvePtr GeomAPI_Curve::basisCurve() const +{ + Handle(Geom_Curve) aCurve = MY_CURVE; + if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) + aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); + + GeomCurvePtr aNewCurve(new GeomAPI_Curve); + aNewCurve->setImpl(new Handle(Geom_Curve)(aCurve)); + return aNewCurve; +} + +// ================================================================================================ + +bool GeomAPI_Curve::Comparator::operator()(const GeomCurvePtr& theCurve1, + const GeomCurvePtr& theCurve2) const +{ + const Handle(Geom_Curve)& aCurve1 = theCurve1->impl(); + const Handle(Geom_Curve)& aCurve2 = theCurve2->impl(); + return aCurve1.get() < aCurve2.get(); +} diff --git a/src/GeomAPI/GeomAPI_Curve.h b/src/GeomAPI/GeomAPI_Curve.h index d002d4250..30b9bd998 100644 --- a/src/GeomAPI/GeomAPI_Curve.h +++ b/src/GeomAPI/GeomAPI_Curve.h @@ -45,6 +45,10 @@ class GeomAPI_Curve : public GeomAPI_Interface GEOMAPI_EXPORT bool isNull() const; + /// Returns \c true if curves are equal + GEOMAPI_EXPORT + bool isEqual(const std::shared_ptr& theOther) const; + /// Returns whether the curve is linear GEOMAPI_EXPORT virtual bool isLine() const; @@ -61,11 +65,30 @@ class GeomAPI_Curve : public GeomAPI_Interface GEOMAPI_EXPORT double endParam() const { return myEnd; } + /// Returns \c true if the curve is trimmed + GEOMAPI_EXPORT + virtual bool isTrimmed() const; + + /// Returns basis for the trimmed curve + GEOMAPI_EXPORT + virtual std::shared_ptr basisCurve() const; + /// Returns point on the curve by parameter /// \param theParam parameter on the curve GEOMAPI_EXPORT std::shared_ptr getPoint(double theParam); +public: + /// \brief Compare addresses of curves + class Comparator + { + public: + /// Return \c true if the address of the first curve is less than the address of the second + GEOMAPI_EXPORT + bool operator ()(const std::shared_ptr& theCurve1, + const std::shared_ptr& theCurve2) const; + }; + private: double myStart; double myEnd; diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index 511de1a9c..99b27729f 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -715,18 +715,6 @@ bool GeomAPI_Shape::isSelfIntersected(const int theLevelOfCheck) const return false; } -double GeomAPI_Shape::tolerance() const -{ - double aTolerance = 0.0; - for (TopExp_Explorer anExp(*MY_SHAPE, TopAbs_FACE); anExp.More(); anExp.Next()) - aTolerance = Max(aTolerance, BRep_Tool::Tolerance(TopoDS::Face(anExp.Current()))); - for (TopExp_Explorer anExp(*MY_SHAPE, TopAbs_EDGE); anExp.More(); anExp.Next()) - aTolerance = Max(aTolerance, BRep_Tool::Tolerance(TopoDS::Edge(anExp.Current()))); - for (TopExp_Explorer anExp(*MY_SHAPE, TopAbs_VERTEX); anExp.More(); anExp.Next()) - aTolerance = Max(aTolerance, BRep_Tool::Tolerance(TopoDS::Vertex(anExp.Current()))); - return aTolerance; -} - bool GeomAPI_Shape::Comparator::operator()(const std::shared_ptr& theShape1, const std::shared_ptr& theShape2) const { diff --git a/src/GeomAPI/GeomAPI_Shape.h b/src/GeomAPI/GeomAPI_Shape.h index 3e680e527..2202d0226 100644 --- a/src/GeomAPI/GeomAPI_Shape.h +++ b/src/GeomAPI/GeomAPI_Shape.h @@ -223,9 +223,6 @@ public: /// 9 - V/V, V/E, E/E, V/F, E/F, F/F, V/S, E/S, F/S and S/S - all interferences (Default value) GEOMAPI_EXPORT bool isSelfIntersected(const int theLevelOfCheck = 9) const; - /// Returns maximal tolerance of the shape - GEOMAPI_EXPORT double tolerance() const; - public: /// \brief Compare addresses of shapes class Comparator diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp index f7f3b9375..c193b3a83 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp @@ -104,16 +104,8 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Wire& theWire, const TopoDS_Fa return findStartVertex(theWire); } -static double averageValue(const NCollection_Array1& theArray) -{ - double aSum = 0.0; - for (NCollection_Array1::Iterator anIt(theArray); anIt.More(); anIt.Next()) - aSum += (double)anIt.Value(); - return aSum / theArray.Size(); -} - // returns true if the first shape must be located earlier than the second -static bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond, +bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond, NCollection_DataMap >& theAreaToIndex, const NCollection_DataMap& theCurveToIndex) { @@ -147,27 +139,15 @@ static bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond, bool isFirst; bool aGeomCompare = !theAreaToIndex.IsBound(theFirst) || !theAreaToIndex.IsBound(theSecond); if (!aGeomCompare) { - // compare average values of the lists - NCollection_Array1& aFirstList = theAreaToIndex.ChangeFind(theFirst); - NCollection_Array1& aSecondList = theAreaToIndex.ChangeFind(theSecond); - if (aFirstList.Size() > 1 && aSecondList.Size() > 1) { - double aFirstMiddle = averageValue(aFirstList); - double aSecondMiddle = averageValue(aSecondList); - if ((double)aFirstList.Last() < aSecondMiddle) - return true; - else if (aFirstMiddle > (double)aSecondList.Last()) - return false; - } - // compare lists of indices one by one to find which list indices are lower - NCollection_Array1::Iterator aFirstListIt(aFirstList); - NCollection_Array1::Iterator aSecondListIt(aSecondList); - for (; aFirstListIt.More() && aSecondListIt.More(); - aFirstListIt.Next(), aSecondListIt.Next()) { - if (aFirstListIt.Value() < aSecondListIt.Value()) return true; - if (aFirstListIt.Value() > aSecondListIt.Value()) return false; + // compare lists of indices one by one to find chich list indices are lower + NCollection_Array1::Iterator aFirstList(theAreaToIndex.ChangeFind(theFirst)); + NCollection_Array1::Iterator aSecondList(theAreaToIndex.ChangeFind(theSecond)); + for (; aFirstList.More() && aSecondList.More(); aFirstList.Next(), aSecondList.Next()) { + if (aFirstList.Value() < aSecondList.Value()) return true; + if (aFirstList.Value() > aSecondList.Value()) return false; } - aGeomCompare = !aFirstListIt.More() && !aSecondListIt.More(); - isFirst = !aFirstListIt.More(); + aGeomCompare = !aFirstList.More() && !aSecondList.More(); + isFirst = !aFirstList.More(); } else { isFirst = !theAreaToIndex.IsBound(theFirst); } @@ -191,7 +171,7 @@ static void sortFaces(TopTools_ListOfShape& theAreas, // collect indices of all edges to operate them quickly NCollection_DataMap aCurveToIndex; // curve -> index in initial shapes std::list >::const_iterator aFeatIt = theInitialShapes.begin(); - for (int anIndex = 0; aFeatIt != theInitialShapes.end(); ++aFeatIt, ++anIndex) { + for (int anIndex = 0; aFeatIt != theInitialShapes.end(); aFeatIt++) { std::shared_ptr aShape(*aFeatIt); const TopoDS_Edge& anEdge = aShape->impl(); if (anEdge.ShapeType() != TopAbs_EDGE) @@ -202,7 +182,7 @@ static void sortFaces(TopTools_ListOfShape& theAreas, if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); if (!aCurveToIndex.IsBound(aCurve)) - aCurveToIndex.Bind(aCurve, anIndex); + aCurveToIndex.Bind(aCurve, anIndex++); } // map from area to the most first indices of curves (to compare) in it NCollection_DataMap > anAreaToIndex; diff --git a/src/Model/Model_ResultConstruction.cpp b/src/Model/Model_ResultConstruction.cpp index 9b5dd8729..997eeab61 100644 --- a/src/Model/Model_ResultConstruction.cpp +++ b/src/Model/Model_ResultConstruction.cpp @@ -48,6 +48,48 @@ #include +typedef NCollection_IndexedDataMap MapFaceToEdgeIndices; + +/// Convert each edge of sketch to corresponding integer value +/// \param[in] theComposite sketch feature +/// \param[out] theCurvesIndices map curve to its index +/// \param[out] theEdgesIndices indexed edge +/// \param[out] theEdgesNames indexed name for edge +static void indexingSketchEdges( + const CompositeFeaturePtr& theComposite, + NCollection_DataMap& theCurvesIndices, + NCollection_DataMap& theEdgesIndices, + std::map& theEdgesNames); + +/// Convert each face to the list of indices of its edges +/// \param[in] theFaces list of faces to proceed +/// \param[in] theCurvesIndices index of each curve +/// \param[out] theFaceEdges map face to indices of its edges +static void faceToEdgeIndices( + const ListOfShape& theFaces, + const NCollection_DataMap& theCurvesIndices, + MapFaceToEdgeIndices& theFaceEdges); + +/// Assign faces to tags for the specified label +/// \param theDocument current document +/// \param theShapeLabel label to store shapes +/// \param theName name of the object +/// \param theShape shape to be stored to the label +/// \param theFacesOrder faces to be assigned to specified tag +/// \param theUnorderedFaces faces which may be stored to any tag +/// \param theFaceEdges indices of edges for each face +/// \param theEdgesIndices indices of edges +/// \param theEdgesNames named of edges +static void storeFacesOnLabel(std::shared_ptr& theDocument, + TDF_Label& theShapeLabel, + const std::string& theName, + const TopoDS_Shape& theShape, + NCollection_DataMap& theFacesOrder, + NCollection_List& theUnorderedFaces, + const MapFaceToEdgeIndices& theFaceEdges, + const NCollection_DataMap& theEdgesIndices, + const std::map& theEdgesNames); + // identifier of the infinite result Standard_GUID kIS_INFINITE("dea8cc5a-53f2-49c1-94e8-a947bed20a9f"); @@ -275,56 +317,19 @@ void Model_ResultConstruction::storeShape(std::shared_ptr theShap 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] = shortName(aConstr); - } - } - } + indexingSketchEdges(aComposite, aCurvesIndices, anEdgeIndices, aComponentsNames); GeomAlgoAPI_SketchBuilder aSketchBuilder(aWirePtr->origin(), aWirePtr->dirX(), aWirePtr->norm(), aWirePtr); const ListOfShape& aFaces = aSketchBuilder.faces(); // order is important to store faces in the same order if sketch is created from scratch - NCollection_IndexedDataMap aNewIndices; // edges indices - std::list >::const_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.Add(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 (aCurvesIndices.IsBound(aCurve)) { - int anIndex = aCurvesIndices.Find(aCurve); - if ((aFirst > aLast) != (anEdge.Orientation() == TopAbs_REVERSED)) - anIndex = -anIndex; - aNewIndices.ChangeFromKey(aTopoFace).Append(anIndex); - } - } - } - } + MapFaceToEdgeIndices aNewIndices; // edges indices + faceToEdgeIndices(aFaces, aCurvesIndices, aNewIndices); + 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_IndexedDataMap::Iterator - aNewIter(aNewIndices); + MapFaceToEdgeIndices::Iterator aNewIter(aNewIndices); for (; aNewIter.More(); aNewIter.Next()) { double aBestFound = 0, aBestNotFound = 1.e+100; int aBestTag = 0; @@ -364,105 +369,221 @@ void Model_ResultConstruction::storeShape(std::shared_ptr theShap anUnorderedFaces.Append(aNewIter.Key()); } } - aShapeLab.ForgetAllAttributes(); // clear all previously stored - TDataStd_Name::Set(aShapeLab, aMyName.c_str()); // restore name forgotten - TNaming_Builder aBuilder(aShapeLab); // store the compound to get it ready on open of document - aBuilder.Generated(aShape); - aMyDoc->addNamingName(aShapeLab, aMyName); - // 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(); - } + storeFacesOnLabel(aMyDoc, aShapeLab, aMyName, aShape, aFacesOrder, anUnorderedFaces, + aNewIndices, anEdgeIndices, aComponentsNames); + } + } +} - if (!aFaceToPut.IsNull()) { - TopTools_MapOfShape aFaceEdges; - for(TopExp_Explorer anEdges(aFaceToPut, TopAbs_EDGE); anEdges.More(); anEdges.Next()) { - aFaceEdges.Add(anEdges.Current()); - } +void Model_ResultConstruction::setFacesOrder(const std::list& theFaces) +{ + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData && aData->isValid()) { + std::string aMyName = data()->name(); + TDF_Label aShapeLab = aData->shapeLab(); + GeomShapePtr aResShape = shape(); + if (!aResShape.get() || aResShape->isNull()) { + // do nothing + return; + } + std::shared_ptr aMyDoc = + std::dynamic_pointer_cast(document()); + const TopoDS_Shape& aShape = aResShape->impl(); + if (aShape.ShapeType() != TopAbs_VERTEX && + aShape.ShapeType() != TopAbs_EDGE) { + ResultPtr aThisPtr = std::dynamic_pointer_cast(data()->owner()); + FeaturePtr aThisFeature = aMyDoc->feature(aThisPtr); + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(aThisFeature); + 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 + indexingSketchEdges(aComposite, aCurvesIndices, anEdgeIndices, aComponentsNames); - 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.FindFromKey(aFaceToPut); - std::stringstream aName; - aName<<"Face"; - TopExp_Explorer aPutEdges(aFaceToPut, TopAbs_EDGE); - TNaming_Builder *anEdgesBuilder = 0, *aVerticesBuilder = 0; - for(TColStd_ListOfInteger::Iterator anIter(aNewInd); anIter.More(); anIter.Next()) { - int anIndex = anIter.Value(); - int aModIndex = anIndex > 0 ? anIndex : -anIndex; - aNewMap->Add(anIndex); - aName<<"-"< 0) - aName<<"f"; - else - aName<<"r"; - // collect all edges of the face which are modified in sub-label of the face - if (anEdgeIndices.IsBound(aModIndex) && - !aFaceEdges.Contains(anEdgeIndices.Find(aModIndex))) { - if (!anEdgesBuilder) { - TDF_Label anEdgesLabel = aLab.FindChild(1); - anEdgesBuilder = new TNaming_Builder(anEdgesLabel); - std::ostringstream aSubName; - // tag is needed for Test1922 to distinguish sub-edges of different faces - aSubName<<"SubEdge_"<Modify(anEdgeIndices.Find(aModIndex), aPutEdges.Current()); - } - // put also modified vertices, otherwise vertex of original edge has no history - if (anEdgeIndices.IsBound(aModIndex)) { - TopExp_Explorer aVExpOld(anEdgeIndices.Find(aModIndex), TopAbs_VERTEX); - TopExp_Explorer aVExpNew(aPutEdges.Current(), TopAbs_VERTEX); - for(; aVExpNew.More() && aVExpOld.More(); aVExpNew.Next(), aVExpOld.Next()) { - if (!aVExpOld.Current().IsSame(aVExpNew.Current())) { - if (!aVerticesBuilder) { - TDF_Label aVertLabel = aLab.FindChild(2); - aVerticesBuilder = new TNaming_Builder(aVertLabel); - std::ostringstream aSubName; - // tag is needed for Test1922 to distinguish sub-edges of different faces - aSubName<<"SubVertex_"<Modify(aVExpOld.Current(), aVExpNew.Current()); - - } - } + ListOfShape aFaces; + NCollection_DataMap aFacesOrder; // faces -> tag where they must be set + NCollection_List anUnorderedFaces; // unordered faces are empty in this case + int aTagId = 0; + for (std::list::const_iterator aFIt = theFaces.begin(); + aFIt != theFaces.end(); ++aFIt) { + aFaces.push_back(*aFIt); + aFacesOrder.Bind(++aTagId, (*aFIt)->impl()); + } + + MapFaceToEdgeIndices aNewIndices; // edges indices + faceToEdgeIndices(aFaces, aCurvesIndices, aNewIndices); + + storeFacesOnLabel(aMyDoc, aShapeLab, aMyName, aShape, aFacesOrder, anUnorderedFaces, + aNewIndices, anEdgeIndices, aComponentsNames); + } + } +} + +// ========================== Auxiliary functions ========================================= + +void storeFacesOnLabel(std::shared_ptr& theDocument, + TDF_Label& theShapeLabel, + const std::string& theName, + const TopoDS_Shape& theShape, + NCollection_DataMap& theFacesOrder, + NCollection_List& theUnorderedFaces, + const MapFaceToEdgeIndices& theFaceEdges, + const NCollection_DataMap& theEdgesIndices, + const std::map& theEdgesNames) +{ + theShapeLabel.ForgetAllAttributes(); // clear all previously stored + TDataStd_Name::Set(theShapeLabel, theName.c_str()); // restore name forgotten + TNaming_Builder aBuilder(theShapeLabel); // store the compound to get it ready on open of document + aBuilder.Generated(theShape); + theDocument->addNamingName(theShapeLabel, theName); + // set new faces to the labels + int aCurrentTag = 1; + NCollection_List::Iterator anUnordered(theUnorderedFaces); + for (int aCurrentTag = 1; !theFacesOrder.IsEmpty() || anUnordered.More(); aCurrentTag++) { + TopoDS_Face aFaceToPut; + if (theFacesOrder.IsBound(aCurrentTag)) { + aFaceToPut = theFacesOrder.Find(aCurrentTag); + theFacesOrder.UnBind(aCurrentTag); + } + else if (anUnordered.More()) { + aFaceToPut = anUnordered.Value(); + anUnordered.Next(); + } + + if (aFaceToPut.IsNull()) + continue; + + TopTools_MapOfShape aFaceEdges; + for (TopExp_Explorer anEdges(aFaceToPut, TopAbs_EDGE); anEdges.More(); anEdges.Next()) + aFaceEdges.Add(anEdges.Current()); + + TDF_Label aLab = theShapeLabel.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 = theFaceEdges.FindFromKey(aFaceToPut); + std::stringstream aName; + aName<<"Face"; + TopExp_Explorer aPutEdges(aFaceToPut, TopAbs_EDGE); + TNaming_Builder *anEdgesBuilder = 0, *aVerticesBuilder = 0; + for(TColStd_ListOfInteger::Iterator anIter(aNewInd); anIter.More(); anIter.Next()) { + int anIndex = anIter.Value(); + int aModIndex = anIndex > 0 ? anIndex : -anIndex; + aNewMap->Add(anIndex); + aName<<"-"<second; + 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 (theEdgesIndices.IsBound(aModIndex) && + !aFaceEdges.Contains(theEdgesIndices.Find(aModIndex))) { + if (!anEdgesBuilder) { + TDF_Label anEdgesLabel = aLab.FindChild(1); + anEdgesBuilder = new TNaming_Builder(anEdgesLabel); + std::ostringstream aSubName; + // tag is needed for Test1922 to distinguish sub-edges of different faces + aSubName<<"SubEdge_"<Modify(theEdgesIndices.Find(aModIndex), aPutEdges.Current()); + } + // put also modified vertices, otherwise vertex of original edge has no history + if (theEdgesIndices.IsBound(aModIndex)) { + TopExp_Explorer aVExpOld(theEdgesIndices.Find(aModIndex), TopAbs_VERTEX); + TopExp_Explorer aVExpNew(aPutEdges.Current(), TopAbs_VERTEX); + for(; aVExpNew.More() && aVExpOld.More(); aVExpNew.Next(), aVExpOld.Next()) { + if (!aVExpOld.Current().IsSame(aVExpNew.Current())) { + if (!aVerticesBuilder) { + TDF_Label aVertLabel = aLab.FindChild(2); + aVerticesBuilder = new TNaming_Builder(aVertLabel); + std::ostringstream aSubName; + // tag is needed for Test1922 to distinguish sub-edges of different faces + aSubName<<"SubVertex_"<addNamingName(aLab, aName.str()); - // put also wires to sub-labels to correctly select them instead of collection by edges - int aWireTag = 3; // first tag is for SubEdge-s, second - for vertices - for(TopExp_Explorer aWires(aFaceToPut, TopAbs_WIRE); aWires.More(); aWires.Next()) { - TDF_Label aWireLab = aLab.FindChild(aWireTag); - TNaming_Builder aWireBuilder(aWireLab); - aWireBuilder.Generated(aWires.Current()); - std::ostringstream aWireName; - aWireName< 3) - aWireName<<"_"<addNamingName(aWireLab, aWireName.str()); - aWireTag++; + aVerticesBuilder->Modify(aVExpOld.Current(), aVExpNew.Current()); + } } } + aPutEdges.Next(); + } + if (anEdgesBuilder) + delete anEdgesBuilder; + if (aVerticesBuilder) + delete aVerticesBuilder; + TDataStd_Name::Set(aLab, TCollection_ExtendedString(aName.str().c_str())); + theDocument->addNamingName(aLab, aName.str()); + // put also wires to sub-labels to correctly select them instead of collection by edges + int aWireTag = 3; // first tag is for SubEdge-s, second - for vertices + for(TopExp_Explorer aWires(aFaceToPut, TopAbs_WIRE); aWires.More(); aWires.Next()) { + TDF_Label aWireLab = aLab.FindChild(aWireTag); + TNaming_Builder aWireBuilder(aWireLab); + aWireBuilder.Generated(aWires.Current()); + std::ostringstream aWireName; + aWireName< 3) + aWireName<<"_"<addNamingName(aWireLab, aWireName.str()); + aWireTag++; + } + } +} + +void indexingSketchEdges(const CompositeFeaturePtr& theComposite, + NCollection_DataMap& theCurvesIndices, + NCollection_DataMap& theEdgesIndices, + std::map& theEdgesNames) +{ + 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(); + 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); + theCurvesIndices.Bind(aCurve, a); + theEdgesIndices.Bind(a, anEdge); + theEdgesNames[a] = shortName(aConstr); + } + } + } +} + +void faceToEdgeIndices(const ListOfShape& theFaces, + const NCollection_DataMap& theCurvesIndices, + MapFaceToEdgeIndices& theFaceEdges) +{ + std::list >::const_iterator aFIter = theFaces.begin(); + for (; aFIter != theFaces.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()); + theFaceEdges.Add(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 (theCurvesIndices.IsBound(aCurve)) { + int anIndex = theCurvesIndices.Find(aCurve); + if ((aFirst > aLast) != (anEdge.Orientation() == TopAbs_REVERSED)) + anIndex = -anIndex; + theFaceEdges.ChangeFromKey(aTopoFace).Append(anIndex); + } + } } } } diff --git a/src/Model/Model_ResultConstruction.h b/src/Model/Model_ResultConstruction.h index a6913c4ae..71a015a98 100644 --- a/src/Model/Model_ResultConstruction.h +++ b/src/Model/Model_ResultConstruction.h @@ -58,6 +58,9 @@ class Model_ResultConstruction : public ModelAPI_ResultConstruction MODEL_EXPORT virtual int facesNum(const bool theUpdateNaming = true); /// if the construction result may be used as faces, this method returns face by zero based index MODEL_EXPORT virtual std::shared_ptr face(const int theIndex); + /// Change the order of faces + MODEL_EXPORT + virtual void setFacesOrder(const std::list >& theFaces); /// By default object is not infinite. MODEL_EXPORT virtual bool isInfinite(); diff --git a/src/ModelAPI/ModelAPI_ResultConstruction.h b/src/ModelAPI/ModelAPI_ResultConstruction.h index 0f24b3829..2a2cf8bff 100644 --- a/src/ModelAPI/ModelAPI_ResultConstruction.h +++ b/src/ModelAPI/ModelAPI_ResultConstruction.h @@ -74,6 +74,8 @@ class ModelAPI_ResultConstruction : public ModelAPI_Result virtual int facesNum(const bool theUpdateNaming = true) = 0; /// if the construction result may be used as faces, this method returns face by zero based index virtual std::shared_ptr face(const int theIndex) = 0; + /// Change the order of faces + virtual void setFacesOrder(const std::list >& theFaces) = 0; /// By default object is not infinite. virtual bool isInfinite() = 0; diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp b/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp index c65543ab8..207e4f3aa 100644 --- a/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp @@ -77,11 +77,8 @@ namespace ModelGeomAlgo_Shape std::list aSubs = theShape->subShapes(theType); for (std::list::const_iterator aSubIt = aSubs.begin(); aSubIt != aSubs.end(); ++aSubIt) { - double aTol = (*aSubIt)->tolerance(); - if (theTolerance > aTol) - aTol = theTolerance; GeomPointPtr aMiddlePoint = (*aSubIt)->middlePoint(); - if (aMiddlePoint && aMiddlePoint->distance(thePoint) < aTol) + if (aMiddlePoint && aMiddlePoint->distance(thePoint) < theTolerance) aFoundSubs.push_back(*aSubIt); } return aFoundSubs; diff --git a/src/ModelHighAPI/ModelHighAPI.i b/src/ModelHighAPI/ModelHighAPI.i index 896af71ef..f26df1e5d 100644 --- a/src/ModelHighAPI/ModelHighAPI.i +++ b/src/ModelHighAPI/ModelHighAPI.i @@ -241,6 +241,7 @@ // std::list -> [] %template(SelectionList) std::list; +%template(SelectionListList) std::list >; %template(RefAttrList) std::list; %template(RefList) std::list; diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index ef6f1ee62..c8e37dc1c 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -1189,6 +1189,19 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ResultPtr& theResult) return *this; } +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::list& theResults) +{ + *this << "["; + for (std::list::const_iterator anIt = theResults.begin(); + anIt != theResults.end(); ++anIt) { + if (anIt != theResults.begin()) + *this << ", "; + *this << *anIt; + } + *this << "]"; + return *this; +} + ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ObjectPtr& theObject) { FeaturePtr aFeature = std::dynamic_pointer_cast(theObject); diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.h b/src/ModelHighAPI/ModelHighAPI_Dumper.h index f4d0be3eb..ccd80c626 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.h +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.h @@ -287,6 +287,10 @@ public: MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const ResultPtr& theResult); + /// Dump a list of results + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::list& theResults); + /// Dump Attribute MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttr); diff --git a/src/SketchAPI/CMakeLists.txt b/src/SketchAPI/CMakeLists.txt index 4cc22fb6c..b93b91f9e 100644 --- a/src/SketchAPI/CMakeLists.txt +++ b/src/SketchAPI/CMakeLists.txt @@ -59,6 +59,7 @@ SET(PROJECT_SOURCES ) SET(PROJECT_LIBRARIES + GeomAlgoAPI ModelAPI ModelHighAPI SketcherPrs @@ -78,6 +79,7 @@ INCLUDE_DIRECTORIES( # TODO(spo): modify ConstructionPlugin headers to remove dependency on GeomAPI headers ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI ${PROJECT_SOURCE_DIR}/src/SketchPlugin ) diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 66e043c1c..f4d6f8bd3 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -65,8 +65,12 @@ #include "SketchAPI_Rotation.h" #include "SketchAPI_Translation.h" //-------------------------------------------------------------------------------------- +#include #include +#include +#include #include +#include #include //-------------------------------------------------------------------------------------- SketchAPI_Sketch::SketchAPI_Sketch( @@ -235,6 +239,59 @@ std::list< std::shared_ptr > SketchAPI_Sketch::getFreePoints() return aFreePoints; } +//-------------------------------------------------------------------------------------- +static GeomCurvePtr untrimmedCurve(GeomShapePtr theShape) +{ + GeomCurvePtr aCurve(new GeomAPI_Curve(theShape)); + if (aCurve->isTrimmed()) + aCurve = aCurve->basisCurve(); + return aCurve; +} + +void SketchAPI_Sketch::changeFacesOrder( + const std::list >& theFaces) +{ + // collect faces of the sketch + ResultConstructionPtr aSketchResult = + std::dynamic_pointer_cast(feature()->lastResult()); + std::list aFaces; + int aFacesNum = aSketchResult->facesNum(); + for (int i = 0; i < aFacesNum; ++i) + aFaces.push_back(aSketchResult->face(i)); + // find new faces order according to the given lists of edges + std::list aNewFacesOrder; + std::list >::const_iterator anIt = theFaces.begin(); + for (; anIt != theFaces.end(); ++anIt) { + // find the appropriate face + std::list::iterator aFIt = aFaces.begin(); + for (; aFIt != aFaces.end(); ++aFIt) { + std::list::const_iterator aEdgeIt = anIt->begin(); + GeomAPI_ShapeExplorer aFExp(*aFIt, GeomAPI_Shape::EDGE); + for (; aEdgeIt != anIt->end() && aFExp.more(); ++aEdgeIt, aFExp.next()) { + ResultPtr aCurRes = aEdgeIt->resultSubShapePair().first; + if (!aCurRes) + break; + GeomCurvePtr aCurve1 = untrimmedCurve(aCurRes->shape()); + GeomCurvePtr aCurve2 = untrimmedCurve(aFExp.current()); + if (!aCurve1->isEqual(aCurve2)) + break; + } + + if (aEdgeIt == anIt->end() && !aFExp.more()) { + // face is found + aNewFacesOrder.push_back(*aFIt); + aFaces.erase(aFIt); + break; + } + } + } + // place the rest faces at the end of new faces list + if (!aFaces.empty()) + aNewFacesOrder.insert(aNewFacesOrder.end(), aFaces.begin(), aFaces.end()); + // update the result of the sketch with the new order of faces + aSketchResult->setFacesOrder(aNewFacesOrder); +} + //-------------------------------------------------------------------------------------- std::shared_ptr SketchAPI_Sketch::addPoint( double theX, double theY) @@ -1008,6 +1065,99 @@ std::shared_ptr SketchAPI_Sketch::to2D(const std::shared_ptr anEdges1; + for (GeomAPI_ShapeExplorer anExp(theFace1, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) + anEdges1.push_back(anExp.current()); + // compare edges of faces + for (GeomAPI_ShapeExplorer anExp(theFace2, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + GeomShapePtr aCurrent = anExp.current(); + bool isFound = false; + std::list::iterator anIt1 = anEdges1.begin(); + for (; anIt1 != anEdges1.end(); ++anIt1) + if (aCurrent->isSameGeometry(*anIt1)) { + isFound = true; + anEdges1.erase(anIt1); + break; + } + if (!isFound) + return true; + } + return !anEdges1.empty(); +} + +static bool isCustomFacesOrder(CompositeFeaturePtr theSketch) +{ + ResultConstructionPtr aSketchResult = + std::dynamic_pointer_cast(theSketch->lastResult()); + if (!aSketchResult) + return false; + + std::shared_ptr aWires = + std::dynamic_pointer_cast(aSketchResult->shape()); + if (!aWires) + return false; + + // collect faces constructed by SketchBuilder algorithm + GeomAlgoAPI_SketchBuilder aSketchBuilder(aWires->origin(), aWires->dirX(), + aWires->norm(), aWires); + const ListOfShape& aFaces = aSketchBuilder.faces(); + + // compare faces stored in sketch with faces generated by SketchBuilder + int aNbSketchFaces = aSketchResult->facesNum(); + int aFaceIndex = 0; + for (ListOfShape::const_iterator aFIt = aFaces.begin(); + aFIt != aFaces.end() && aFaceIndex < aNbSketchFaces; + ++aFIt, ++aFaceIndex) { + GeomFacePtr aSketchFace = aSketchResult->face(aFaceIndex); + GeomFacePtr aCurFace = (*aFIt)->face(); + if (isDifferent(aSketchFace, aCurFace)) + return true; + } + return false; +} + +static void edgesOfSketchFaces(CompositeFeaturePtr theSketch, + std::list >& theEdges) +{ + ResultConstructionPtr aSketchResult = + std::dynamic_pointer_cast(theSketch->lastResult()); + if (!aSketchResult) + return; + + // collect curves of the sketch + std::map aCurves; + int aSubNum = theSketch->numberOfSubs(); + for (int a = 0; a < aSubNum; ++a) { + FeaturePtr aSub = theSketch->subFeature(a); + const std::list& aResults = aSub->results(); + std::list::const_iterator aRes = aResults.cbegin(); + for (; aRes != aResults.cend(); aRes++) { + GeomShapePtr aCurShape = (*aRes)->shape(); + if (aCurShape && aCurShape->isEdge()) + aCurves[untrimmedCurve(aCurShape)] = *aRes; + } + } + + // convert each face to the list of results of its edges + int aFacesNum = aSketchResult->facesNum(); + for (int a = 0; a < aFacesNum; ++a) { + theEdges.push_back(std::list()); + std::list& aCurEdges = theEdges.back(); + + GeomFacePtr aFace = aSketchResult->face(a); + for (GeomAPI_ShapeExplorer anExp(aFace, GeomAPI_Shape::EDGE); + anExp.more(); anExp.next()) { + GeomCurvePtr aCurrent = untrimmedCurve(anExp.current()); + aCurEdges.push_back(aCurves[aCurrent]); + } + } +} + +//-------------------------------------------------------------------------------------- + void SketchAPI_Sketch::dump(ModelHighAPI_Dumper& theDumper) const { FeaturePtr aBase = feature(); @@ -1067,4 +1217,24 @@ void SketchAPI_Sketch::dump(ModelHighAPI_Dumper& theDumper) const // dump sketch's subfeatures CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(aBase); theDumper.processSubs(aCompFeat, true); + + // if face order differs to the order generated by SketchBuilder, + // dump the list of faces for correct execution of the script + if (isCustomFacesOrder(aCompFeat)) { + std::list > aFaces; + edgesOfSketchFaces(aCompFeat, aFaces); + + const std::string& aSketchName = theDumper.name(aBase); + std::string aMethodName(".changeFacesOrder"); + std::string aSpaceShift(aSketchName.size() + aMethodName.size(), ' '); + + theDumper << aSketchName << aMethodName << "(["; + for (std::list >::iterator aFIt = aFaces.begin(); + aFIt != aFaces.end(); ++aFIt) { + if (aFIt != aFaces.begin()) + theDumper << ",\n" << aSpaceShift << " "; + theDumper << *aFIt; + } + theDumper << "\n" << aSpaceShift << " ])" << std::endl; + } } diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index 8b3237f7f..c32c88d9d 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -111,6 +111,10 @@ public: SKETCHAPI_EXPORT void setExternal(std::shared_ptr thePlaneObject); + /// Change order of sketch results (faces) + SKETCHAPI_EXPORT + void changeFacesOrder(const std::list >& theFaces); + /// List points not connected by constraints with other sketch entitites SKETCHAPI_EXPORT std::list< std::shared_ptr > getFreePoints(); -- 2.39.2