Salome HOME
Issue #2971: Naming issue in a group when loading a dump file
authorazv <azv@opencascade.com>
Thu, 22 Aug 2019 13:34:57 +0000 (16:34 +0300)
committerazv <azv@opencascade.com>
Thu, 22 Aug 2019 13:35:27 +0000 (16:35 +0300)
Additional dump to change the order of sketch faces if it was changed while editing the model.

16 files changed:
src/FeaturesPlugin/Test/Test2971.py
src/GeomAPI/GeomAPI_Curve.cpp
src/GeomAPI/GeomAPI_Curve.h
src/GeomAPI/GeomAPI_Shape.cpp
src/GeomAPI/GeomAPI_Shape.h
src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp
src/Model/Model_ResultConstruction.cpp
src/Model/Model_ResultConstruction.h
src/ModelAPI/ModelAPI_ResultConstruction.h
src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp
src/ModelHighAPI/ModelHighAPI.i
src/ModelHighAPI/ModelHighAPI_Dumper.cpp
src/ModelHighAPI/ModelHighAPI_Dumper.h
src/SketchAPI/CMakeLists.txt
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h

index eb880f14d53ee2f0dfd3a2434f37b561f0b0337b..4116aec426d230f9e1a12d14c501ce63c91aac97 100644 (file)
@@ -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)
index 07fb93d65c858bfc5b3be00cf2bdc4f9ab91ad77..142a9ff5fb6a84a008b7567fa3b96c5824de0816 100644 (file)
 #include<GeomAPI_Pnt.h>
 
 #include <TopoDS_Shape.hxx>
+#include <Geom_Circle.hxx>
 #include <Geom_Curve.hxx>
 #include <Geom_Line.hxx>
-#include <Geom_Circle.hxx>
+#include <Geom_TrimmedCurve.hxx>
 #include <BRep_Tool.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS.hxx>
@@ -70,3 +71,34 @@ std::shared_ptr<GeomAPI_Pnt> GeomAPI_Curve::getPoint(double theParam)
   gp_Pnt aPnt = aAdaptor.Value(theParam);
   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
 }
+
+bool GeomAPI_Curve::isEqual(const std::shared_ptr<GeomAPI_Curve>& theOther) const
+{
+  return MY_CURVE == theOther->impl<Handle_Geom_Curve>();
+}
+
+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<Handle_Geom_Curve>();
+  const Handle(Geom_Curve)& aCurve2 = theCurve2->impl<Handle_Geom_Curve>();
+  return aCurve1.get() < aCurve2.get();
+}
index d002d4250189c63bb5015d681424bfc7ecf38784..30b9bd99840b9ebae2cc9637b2f0a055b08e4fd2 100644 (file)
@@ -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<GeomAPI_Curve>& 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<GeomAPI_Curve> basisCurve() const;
+
   /// Returns point on the curve by parameter
   /// \param theParam parameter on the curve
   GEOMAPI_EXPORT
   std::shared_ptr<GeomAPI_Pnt> 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<GeomAPI_Curve>& theCurve1,
+                     const std::shared_ptr<GeomAPI_Curve>& theCurve2) const;
+  };
+
 private:
   double myStart;
   double myEnd;
index 511de1a9c47243af62abb645716d6f0a3dc15cf0..99b27729f3164da58edf98701a7085655256b136 100644 (file)
@@ -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<GeomAPI_Shape>& theShape1,
                                            const std::shared_ptr<GeomAPI_Shape>& theShape2) const
 {
index 3e680e527a55165f1e747ae39ce9cbc572c343f1..2202d022664622308452afc0ec41863a2f40dfab 100644 (file)
@@ -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
index f7f3b937515721eef1db84d9ad2c6667359b09c4..c193b3a8315d4c50cd708f8a903eb4fb05438c53 100644 (file)
@@ -104,16 +104,8 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Wire& theWire, const TopoDS_Fa
   return findStartVertex(theWire);
 }
 
-static double averageValue(const NCollection_Array1<int>& theArray)
-{
-  double aSum = 0.0;
-  for (NCollection_Array1<int>::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<TopoDS_Shape, NCollection_Array1<int> >& theAreaToIndex,
   const NCollection_DataMap<Handle(Geom_Curve), int>& 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<int>& aFirstList  = theAreaToIndex.ChangeFind(theFirst);
-    NCollection_Array1<int>& 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<int>::Iterator aFirstListIt(aFirstList);
-    NCollection_Array1<int>::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<int>::Iterator aFirstList(theAreaToIndex.ChangeFind(theFirst));
+    NCollection_Array1<int>::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<Handle(Geom_Curve), int> aCurveToIndex; // curve -> index in initial shapes
   std::list<std::shared_ptr<GeomAPI_Shape> >::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<GeomAPI_Shape> aShape(*aFeatIt);
     const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
     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<TopoDS_Shape, NCollection_Array1<int> > anAreaToIndex;
index 9b5dd872929d5411888083f73e4f44f62b04ad84..997eeab619de6daf694e0788b623ca2c9b88f7ce 100644 (file)
 
 #include <algorithm>
 
+typedef NCollection_IndexedDataMap<TopoDS_Face, TColStd_ListOfInteger> 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<Handle(Geom_Curve), int>& theCurvesIndices,
+    NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
+    std::map<int, std::string>& 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<Handle(Geom_Curve), int>& 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<Model_Document>& theDocument,
+                              TDF_Label& theShapeLabel,
+                              const std::string& theName,
+                              const TopoDS_Shape& theShape,
+                              NCollection_DataMap<int, TopoDS_Face>& theFacesOrder,
+                              NCollection_List<TopoDS_Face>& theUnorderedFaces,
+                              const MapFaceToEdgeIndices& theFaceEdges,
+                              const NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
+                              const std::map<int, std::string>& 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<GeomAPI_Shape> theShap
       NCollection_DataMap<Handle(Geom_Curve), int> aCurvesIndices;
       NCollection_DataMap<int, TopoDS_Edge> anEdgeIndices;
       std::map<int, std::string> 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<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
-        std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
-        for (; aRes != aResults.cend(); aRes++) {
-          ResultConstructionPtr aConstr =
-            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
-          if (aConstr->shape() && aConstr->shape()->isEdge()) {
-            TopoDS_Edge anEdge = TopoDS::Edge(aConstr->shape()->impl<TopoDS_Shape>());
-            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<TopoDS_Face, TColStd_ListOfInteger> aNewIndices; // edges indices
-      std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFIter = aFaces.begin();
-      for (; aFIter != aFaces.end(); aFIter++) {
-        std::shared_ptr<GeomAPI_Face> 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<TopoDS_Shape>());
-          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<int, TopoDS_Face> aFacesOrder; // faces -> tag where they must be set
       NCollection_List<TopoDS_Face> anUnorderedFaces; // faces that may be located at any index
       // searching for the best new candidate to old location
-      NCollection_IndexedDataMap<TopoDS_Face, TColStd_ListOfInteger>::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<GeomAPI_Shape> 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<TopoDS_Face>::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<GeomFacePtr>& theFaces)
+{
+  std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(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<Model_Document> aMyDoc =
+        std::dynamic_pointer_cast<Model_Document>(document());
+    const TopoDS_Shape& aShape = aResShape->impl<TopoDS_Shape>();
+    if (aShape.ShapeType() != TopAbs_VERTEX &&
+        aShape.ShapeType() != TopAbs_EDGE) {
+      ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
+      FeaturePtr aThisFeature = aMyDoc->feature(aThisPtr);
+      CompositeFeaturePtr aComposite =
+        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
+      if (!aComposite || aComposite->numberOfSubs() == 0)
+        return; // unknown case
+      // collect indices of curves of current composite
+      NCollection_DataMap<Handle(Geom_Curve), int> aCurvesIndices;
+      NCollection_DataMap<int, TopoDS_Edge> anEdgeIndices;
+      std::map<int, std::string> 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<<"-"<<aComponentsNames[aModIndex];
-            if (anIter.Value() > 0)
-              aName<<"f";
-            else
-              aName<<"r";
-            // collect all edges of the face which are modified in sub-label of the face
-            if (anEdgeIndices.IsBound(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_"<<aCurrentTag;
-                TDataStd_Name::Set(anEdgesLabel, aSubName.str().c_str());
-              }
-              anEdgesBuilder->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_"<<aCurrentTag;
-                    TDataStd_Name::Set(aVertLabel, aSubName.str().c_str());
-                  }
-                  aVerticesBuilder->Modify(aVExpOld.Current(), aVExpNew.Current());
-
-                }
-              }
+      ListOfShape aFaces;
+      NCollection_DataMap<int, TopoDS_Face> aFacesOrder; // faces -> tag where they must be set
+      NCollection_List<TopoDS_Face> anUnorderedFaces; // unordered faces are empty in this case
+      int aTagId = 0;
+      for (std::list<GeomFacePtr>::const_iterator aFIt = theFaces.begin();
+           aFIt != theFaces.end(); ++aFIt) {
+        aFaces.push_back(*aFIt);
+        aFacesOrder.Bind(++aTagId, (*aFIt)->impl<TopoDS_Face>());
+      }
+
+      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<Model_Document>& theDocument,
+                       TDF_Label& theShapeLabel,
+                       const std::string& theName,
+                       const TopoDS_Shape& theShape,
+                       NCollection_DataMap<int, TopoDS_Face>& theFacesOrder,
+                       NCollection_List<TopoDS_Face>& theUnorderedFaces,
+                       const MapFaceToEdgeIndices& theFaceEdges,
+                       const NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
+                       const std::map<int, std::string>& 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<TopoDS_Face>::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<<"-"<<theEdgesNames.find(aModIndex)->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_"<<aCurrentTag;
+          TDataStd_Name::Set(anEdgesLabel, aSubName.str().c_str());
+        }
+        anEdgesBuilder->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_"<<aCurrentTag;
+              TDataStd_Name::Set(aVertLabel, aSubName.str().c_str());
             }
-            aPutEdges.Next();
-          }
-          if (anEdgesBuilder)
-            delete anEdgesBuilder;
-          if (aVerticesBuilder)
-            delete aVerticesBuilder;
-          TDataStd_Name::Set(aLab, TCollection_ExtendedString(aName.str().c_str()));
-          aMyDoc->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<<aName.str()<<"_wire";
-            if (aWireTag > 3)
-              aWireName<<"_"<<aWireTag - 2;
-            TDataStd_Name::Set(aWireLab, aWireName.str().c_str());
-            aMyDoc->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<<aName.str()<<"_wire";
+      if (aWireTag > 3)
+        aWireName<<"_"<<aWireTag - 2;
+      TDataStd_Name::Set(aWireLab, aWireName.str().c_str());
+      theDocument->addNamingName(aWireLab, aWireName.str());
+      aWireTag++;
+    }
+  }
+}
+
+void indexingSketchEdges(const CompositeFeaturePtr& theComposite,
+                         NCollection_DataMap<Handle(Geom_Curve), int>& theCurvesIndices,
+                         NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
+                         std::map<int, std::string>& theEdgesNames)
+{
+  const int aSubNum = theComposite->numberOfSubs();
+  for (int a = 0; a < aSubNum; a++) {
+    FeaturePtr aSub = theComposite->subFeature(a);
+    const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
+    std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
+    for (; aRes != aResults.cend(); aRes++) {
+      ResultConstructionPtr aConstr =
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
+      if (aConstr->shape() && aConstr->shape()->isEdge()) {
+        TopoDS_Edge anEdge = TopoDS::Edge(aConstr->shape()->impl<TopoDS_Shape>());
+        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<Handle(Geom_Curve), int>& theCurvesIndices,
+                       MapFaceToEdgeIndices& theFaceEdges)
+{
+  std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFIter = theFaces.begin();
+  for (; aFIter != theFaces.end(); aFIter++) {
+    std::shared_ptr<GeomAPI_Face> 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<TopoDS_Shape>());
+      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);
+        }
+      }
     }
   }
 }
index a6913c4aeb91306cccc95eed11ba51daa5c78685..71a015a981740990be5858be751e12cbb8db646f 100644 (file)
@@ -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<GeomAPI_Face> face(const int theIndex);
+  /// Change the order of faces
+  MODEL_EXPORT
+  virtual void setFacesOrder(const std::list<std::shared_ptr<GeomAPI_Face> >& theFaces);
 
   /// By default object is not infinite.
   MODEL_EXPORT virtual bool isInfinite();
index 0f24b3829ab8584f33db216d8182656334b1f2e5..2a2cf8bff1b1124ff95a0afbf280e3cd58486440 100644 (file)
@@ -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<GeomAPI_Face> face(const int theIndex) = 0;
+  /// Change the order of faces
+  virtual void setFacesOrder(const std::list<std::shared_ptr<GeomAPI_Face> >& theFaces) = 0;
 
   /// By default object is not infinite.
   virtual bool isInfinite() = 0;
index c65543ab81ff80b371cec879cf20f5b21842bdf3..207e4f3aa807ce4c1b861cd4f76df85927b0a26c 100644 (file)
@@ -77,11 +77,8 @@ namespace ModelGeomAlgo_Shape
     std::list<GeomShapePtr> aSubs = theShape->subShapes(theType);
     for (std::list<GeomShapePtr>::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;
index 896af71efcf0385e682f72f244454bef69a068dd..f26df1e5d32b3b5610fb1c06347d111d0284936f 100644 (file)
 
 // std::list -> []
 %template(SelectionList) std::list<ModelHighAPI_Selection>;
+%template(SelectionListList) std::list<std::list<ModelHighAPI_Selection> >;
 %template(RefAttrList) std::list<ModelHighAPI_RefAttr>;
 %template(RefList) std::list<ModelHighAPI_Reference>;
 
index ef6f1ee621e4e62e6e1d8153220b6f7791a9e2a9..c8e37dc1c6598fbffb86604342bdce884a57119d 100644 (file)
@@ -1189,6 +1189,19 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ResultPtr& theResult)
   return *this;
 }
 
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::list<ResultPtr>& theResults)
+{
+  *this << "[";
+  for (std::list<ResultPtr>::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<ModelAPI_Feature>(theObject);
index f4d0be3eb82f3aeb07f2599e92f5fd12697ca0e1..ccd80c626bd8da98bc5c46553cd73418c83284bf 100644 (file)
@@ -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<ResultPtr>& theResults);
+
   /// Dump Attribute
   MODELHIGHAPI_EXPORT ModelHighAPI_Dumper&
     operator<<(const std::shared_ptr<ModelAPI_Attribute>& theAttr);
index 4cc22fb6c380c93c9653d859e0eaaccead5c0732..b93b91f9e4590e8cdc4059f51874d8677c6b16f5 100644 (file)
@@ -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
 )
 
index 66e043c1c85b201f3ebc64051c866b825a7a0263..f4d6f8bd3fb329d010a800339cb514f5bdb95e71 100644 (file)
 #include "SketchAPI_Rotation.h"
 #include "SketchAPI_Translation.h"
 //--------------------------------------------------------------------------------------
+#include <GeomAPI_Curve.h>
 #include <GeomAPI_Dir2d.h>
+#include <GeomAPI_PlanarEdges.h>
+#include <GeomAPI_ShapeExplorer.h>
 #include <GeomAPI_XY.h>
+#include <GeomAlgoAPI_SketchBuilder.h>
 #include <cmath>
 //--------------------------------------------------------------------------------------
 SketchAPI_Sketch::SketchAPI_Sketch(
@@ -235,6 +239,59 @@ std::list< std::shared_ptr<SketchAPI_Point> > 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<std::list<ModelHighAPI_Selection> >& theFaces)
+{
+  // collect faces of the sketch
+  ResultConstructionPtr aSketchResult =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(feature()->lastResult());
+  std::list<GeomFacePtr> 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<GeomFacePtr> aNewFacesOrder;
+  std::list<std::list<ModelHighAPI_Selection> >::const_iterator anIt = theFaces.begin();
+  for (; anIt != theFaces.end(); ++anIt) {
+    // find the appropriate face
+    std::list<GeomFacePtr>::iterator aFIt = aFaces.begin();
+    for (; aFIt != aFaces.end(); ++aFIt) {
+      std::list<ModelHighAPI_Selection>::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_Point> SketchAPI_Sketch::addPoint(
     double theX, double theY)
@@ -1008,6 +1065,99 @@ std::shared_ptr<GeomAPI_Pnt2d> SketchAPI_Sketch::to2D(const std::shared_ptr<Geom
 
 //--------------------------------------------------------------------------------------
 
+static bool isDifferent(GeomFacePtr theFace1, GeomFacePtr theFace2)
+{
+  // collect edges of the first face
+  std::list<GeomShapePtr> 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<GeomShapePtr>::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<ModelAPI_ResultConstruction>(theSketch->lastResult());
+  if (!aSketchResult)
+    return false;
+
+  std::shared_ptr<GeomAPI_PlanarEdges> aWires =
+      std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(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<std::list<ResultPtr> >& theEdges)
+{
+  ResultConstructionPtr aSketchResult =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theSketch->lastResult());
+  if (!aSketchResult)
+    return;
+
+  // collect curves of the sketch
+  std::map<GeomCurvePtr, ResultPtr, GeomAPI_Curve::Comparator> aCurves;
+  int aSubNum = theSketch->numberOfSubs();
+  for (int a = 0; a < aSubNum; ++a) {
+    FeaturePtr aSub = theSketch->subFeature(a);
+    const std::list<ResultPtr>& aResults = aSub->results();
+    std::list<ResultPtr>::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<ResultPtr>());
+    std::list<ResultPtr>& 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<ModelAPI_CompositeFeature>(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<std::list<ResultPtr> > 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<std::list<ResultPtr> >::iterator aFIt = aFaces.begin();
+         aFIt != aFaces.end(); ++aFIt) {
+      if (aFIt != aFaces.begin())
+        theDumper << ",\n" << aSpaceShift << "  ";
+      theDumper << *aFIt;
+    }
+    theDumper << "\n" << aSpaceShift << " ])" << std::endl;
+  }
 }
index 8b3237f7f04df08e3cb8e3da1dbf4a4e49185f90..c32c88d9daf73dc0980d559d2988f126f56a2f10 100644 (file)
@@ -111,6 +111,10 @@ public:
   SKETCHAPI_EXPORT
   void setExternal(std::shared_ptr<ModelAPI_Object> thePlaneObject);
 
+  /// Change order of sketch results (faces)
+  SKETCHAPI_EXPORT
+  void changeFacesOrder(const std::list<std::list<ModelHighAPI_Selection> >& theFaces);
+
   /// List points not connected by constraints with other sketch entitites
   SKETCHAPI_EXPORT
   std::list< std::shared_ptr<SketchAPI_Point> > getFreePoints();