Salome HOME
Intermediate changes for sketch builder
authorazv <azv@opencascade.com>
Wed, 4 Jun 2014 08:31:23 +0000 (12:31 +0400)
committerazv <azv@opencascade.com>
Thu, 5 Jun 2014 11:06:32 +0000 (15:06 +0400)
src/GeomAPI/GeomAPI_Dir.cpp
src/GeomAPI/GeomAPI_Dir.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Sketch.cpp

index abe357b2bfc17e033ddd4af1644aa204ed3b3c5c..e3badb4401b41cdd0fc5a2f7f3bd3712ca172f08 100644 (file)
@@ -41,3 +41,10 @@ double GeomAPI_Dir::dot(const boost::shared_ptr<GeomAPI_Dir>& theArg) const
 {
   return MY_DIR->Dot(theArg->impl<gp_Dir>());
 }
+
+const boost::shared_ptr<GeomAPI_XYZ> GeomAPI_Dir::cross(const boost::shared_ptr<GeomAPI_Dir>& theArg) const
+{
+  gp_XYZ aResult = MY_DIR->XYZ().Crossed(theArg->impl<gp_Dir>().XYZ());
+  return boost::shared_ptr<GeomAPI_XYZ>(new GeomAPI_XYZ(aResult.X(), aResult.Y(), aResult.Z()));
+}
+
index 6ab0f1dd2baced7076eff6b372d6d477e4f1ca49..181c4672e283379cf4281c3a9f269db5b9a0544c 100644 (file)
@@ -35,6 +35,8 @@ public:
 
   /// result is a scalar product of directions
   double dot(const boost::shared_ptr<GeomAPI_Dir>& theArg) const;
+  /// result is a cross product of two directions
+  const boost::shared_ptr<GeomAPI_XYZ> cross(const boost::shared_ptr<GeomAPI_Dir>& theArg) const;
 };
 
 #endif
index 509c7fd9e0bc5ab7b01c1f3dc608e14e237709ab..548f7002f059005ef606fec6c162634eac72afb6 100644 (file)
@@ -9,12 +9,14 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_CompoundBuilder.h
     GeomAlgoAPI_FaceBuilder.h
     GeomAlgoAPI_EdgeBuilder.h
+    GeomAlgoAPI_SketchBuilder.h
 )
 
 SET(PROJECT_SOURCES
     GeomAlgoAPI_CompoundBuilder.cpp
     GeomAlgoAPI_FaceBuilder.cpp
     GeomAlgoAPI_EdgeBuilder.cpp
+    GeomAlgoAPI_SketchBuilder.cpp
 )
 
 ADD_DEFINITIONS(-DGEOMALGOAPI_EXPORTS ${CAS_DEFINITIONS})
@@ -30,7 +32,7 @@ INCLUDE_DIRECTORIES(
   ${CAS_INCLUDE_DIRS}
 )
 
-TARGET_LINK_LIBRARIES(GeomAlgoAPI ${PROJECT_LIBRARIES} GeomAPI ${CAS_KERNEL} ${CAS_MODELER})
+TARGET_LINK_LIBRARIES(GeomAlgoAPI ${PROJECT_LIBRARIES} GeomAPI ${CAS_TKBool} ${CAS_TKBO})
 
 SET(SWIG_SCRIPTS
   ${CMAKE_CURRENT_BINARY_DIR}/GeomAlgoAPI.py
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp
new file mode 100644 (file)
index 0000000..01cc99b
--- /dev/null
@@ -0,0 +1,577 @@
+// File:        GeomAlgoAPI_SketchBuilder.cpp
+// Created:     02 Jun 2014
+// Author:      Artem ZHIDKOV
+
+#include <GeomAlgoAPI_SketchBuilder.h>
+
+#include <set>
+
+#include <gp_Dir.hxx>
+
+#include <BOPAlgo_Builder.hxx>
+#include <BOPAlgo_Operation.hxx>
+#include <BOPAlgo_PaveFiller.hxx>
+#include <BOPTools.hxx>
+#include <BRep_Builder.hxx>
+#include <BRep_Curve3D.hxx>
+#include <BRep_TEdge.hxx>
+#include <BRep_TVertex.hxx>
+#include <BRepAlgoAPI_Cut.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <Geom_Curve.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Wire.hxx>
+#include <TopOpeBRepTool_ShapeClassifier.hxx>
+
+#include <Precision.hxx>
+const double tolerance = Precision::Confusion();
+
+/// \brief Search first vertex - the vertex with lowest x coordinate, which is used in 2 edges at least
+static const TopoDS_Shape& findStartVertex(
+          const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE,
+          const gp_Dir& theDirX, const gp_Dir& theDirY);
+
+/// \brief Search the vertex on the sketch candidate to be the next one in the loop
+static void findNextVertex(
+          const TopoDS_Shape&                            theStartVertex, 
+          const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
+          const gp_Dir&                                  theStartDir,
+          const gp_Dir&                                  theNormal,
+                TopoDS_Shape&                            theNextVertex,
+                TopoDS_Shape&                            theNextEdge,
+                gp_Dir&                                  theNextDir);
+
+/// \brief Create planar face using the edges surrounding it
+static void createFace(const TopoDS_Shape&                      theStartVertex,
+                       const std::list<TopoDS_Shape>::iterator& theStartEdge,
+                       const std::list<TopoDS_Shape>::iterator& theEndOfEdges,
+                             TopoDS_Face&                       theResFace);
+
+/// \bief Create planar wire
+static void createWireList(const TopoDS_Shape&                      theStartVertex,
+                           const std::list<TopoDS_Shape>::iterator& theStartEdge,
+                           const std::list<TopoDS_Shape>::iterator& theEndOfEdges,
+                           const std::set<Handle(TopoDS_TShape)>&   theEdgesInLoops,
+                                 std::list<TopoDS_Wire>&            theResWires);
+
+/// \brief Calculate outer tengency on the edge in specified vertex
+static gp_Dir getOuterEdgeDirection(const TopoDS_Shape& theEdge,
+                                    const TopoDS_Shape& theVertex);
+
+/// \brief Unnecessary edges will be removed from the map.
+///        Positions of iterator will be updated
+static void removeWasteEdges(
+                std::list<TopoDS_Shape>::iterator&  theStartVertex,
+                std::list<TopoDS_Shape>::iterator&  theStartEdge,
+          const std::list<TopoDS_Shape>::iterator&  theEndOfVertexes,
+          const std::list<TopoDS_Shape>::iterator&  theEndOfEdges,
+          BOPCol_IndexedDataMapOfShapeListOfShape&  theMapVE);
+
+
+
+
+void GeomAlgoAPI_SketchBuilder::createFaces(
+          const boost::shared_ptr<GeomAPI_Dir>&                theDirX,
+          const boost::shared_ptr<GeomAPI_Dir>&                theDirY,
+          const boost::shared_ptr<GeomAPI_Dir>&                theNorm,
+          const std::list< boost::shared_ptr<GeomAPI_Shape> >& theFeatures,
+                std::list< boost::shared_ptr<GeomAPI_Shape> >& theResultFaces,
+                std::list< boost::shared_ptr<GeomAPI_Shape> >& theResultWires)
+{
+  // Create the list of edges with shared vertexes
+  BOPAlgo_Builder aBuilder;
+  BOPAlgo_PaveFiller aPF;
+
+  std::list< boost::shared_ptr<GeomAPI_Shape> >::const_iterator anIt = theFeatures.begin();
+  for (; anIt != theFeatures.end(); anIt++)
+  {
+    boost::shared_ptr<GeomAPI_Shape> aPreview(*anIt);
+    aBuilder.AddArgument(aPreview->impl<TopoDS_Edge>());
+  }
+  aPF.SetArguments(aBuilder.Arguments());
+  aPF.Perform();
+  int aErr = aPF.ErrorStatus();
+  if (aErr) return ;
+  aBuilder.PerformWithFiller(aPF);
+  aErr = aBuilder.ErrorStatus();
+  if (aErr) return ;
+
+  BOPCol_IndexedDataMapOfShapeListOfShape aMapVE; // map between vertexes and edges
+  BOPTools::MapShapesAndAncestors(aBuilder.Shape(), TopAbs_VERTEX, TopAbs_EDGE, aMapVE);
+
+  gp_Dir aDirX = theDirX->impl<gp_Dir>();
+  gp_Dir aDirY = theDirY->impl<gp_Dir>();
+  gp_Dir aNorm = theNorm->impl<gp_Dir>();
+
+  // Set of edges used in loops
+  std::set<Handle(TopoDS_TShape)> anEdgesInLoops;
+  // Lists for processed vertexes and edges
+  std::list<TopoDS_Shape> aProcVertexes;
+  std::list<TopoDS_Shape> aProcEdges;
+
+  // Search the start vertex
+  TopoDS_Shape aStartVertex = findStartVertex(aMapVE, aDirX, aDirY);
+  aProcVertexes.push_back(aStartVertex);
+
+  TopoDS_Shape aCurVertex = aStartVertex;
+  gp_Dir aCurDir = aDirY;
+  gp_Dir aCurNorm = aNorm.Reversed();
+
+  // Go through the edges and find loops
+  TopoDS_Shape aNextVertex;
+  TopoDS_Shape aBindingEdge;
+  gp_Dir aNextDir;
+  while (aMapVE.Extent() > 0)
+  {
+    findNextVertex(aCurVertex, aMapVE, aCurDir, aCurNorm, aNextVertex, aBindingEdge, aNextDir);
+    aCurNorm = aNorm;
+
+    // Try to find next vertex in the list of already processed
+    std::list<TopoDS_Shape>::iterator          aVertIter = aProcVertexes.begin();
+    std::list<TopoDS_Shape>::iterator          anEdgeIter = aProcEdges.begin();
+    for ( ; aVertIter != aProcVertexes.end(); aVertIter++)
+    {
+      if (aVertIter->TShape() == aNextVertex.TShape())
+        break;
+      if (anEdgeIter != aProcEdges.end())
+        anEdgeIter++;
+    }
+
+    aProcVertexes.push_back(aNextVertex);
+    aProcEdges.push_back(aBindingEdge);
+
+    // The loop was found
+    if (aVertIter != aProcVertexes.end())
+    {
+      if (aVertIter != aProcVertexes.begin())
+      {
+        // Check the orientation of the loop
+        Handle(BRep_TVertex) aVert = Handle(BRep_TVertex)::DownCast(aVertIter->TShape());
+        const gp_Pnt& aCurPnt = aVert->Pnt();
+        aVert = Handle(BRep_TVertex)::DownCast((++aVertIter)->TShape());
+        aVertIter--;
+        const gp_Pnt& aNextPnt = aVert->Pnt();
+        std::list<TopoDS_Shape>::reverse_iterator anItBeforeLast = aProcVertexes.rbegin();
+        aVert = Handle(BRep_TVertex)::DownCast((++anItBeforeLast)->TShape()); // get the vertex before last one, because the last duplicates the start of loop
+        const gp_Pnt& aPrevPnt = aVert->Pnt();
+        gp_Vec aCN(aCurPnt, aNextPnt);
+        gp_Vec aCP(aCurPnt, aPrevPnt);
+        if (aCN.DotCross(aCP, gp_Vec(aNorm)) < -tolerance)
+        {
+          // The found loop has wrong orientation and may contain sub-loops.
+          // Need to check it onle again with another initial direction.
+          aCurVertex = *aVertIter;
+          do {
+            aProcVertexes.pop_back();
+            aProcEdges.pop_back();
+          } while (aCurVertex != aProcVertexes.back());
+          aCurDir = getOuterEdgeDirection(aProcEdges.back(), aCurVertex);
+          aCurNorm = aNorm.Reversed();
+          continue;
+        }
+      }
+
+      // When the orientation is correct or the edges looped through
+      // the first element, create new face and remove unnecessary edges.
+      TopoDS_Face aPatch;
+      createFace(*aVertIter, anEdgeIter, aProcEdges.end(), aPatch);
+      if (!aPatch.IsNull())
+      {
+        boost::shared_ptr<GeomAPI_Shape> aFace(new GeomAPI_Shape);
+        aFace->setImpl(new TopoDS_Shape(aPatch));
+        theResultFaces.push_back(aFace);
+      }
+      // push the edges used in the loop to the map
+      std::list<TopoDS_Shape>::iterator anIter;
+      for (anIter = anEdgeIter; anIter != aProcEdges.end(); anIter++)
+        anEdgesInLoops.insert(anIter->TShape());
+      // remove unnecessary edges
+      std::list<TopoDS_Shape>::iterator aCopyVLoop = aVertIter;
+      std::list<TopoDS_Shape>::iterator aCopyELoop = anEdgeIter;
+      removeWasteEdges(aVertIter, anEdgeIter, aProcVertexes.end(), aProcEdges.end(), aMapVE);
+
+      // revert the list of remaining edges
+      std::list<TopoDS_Shape> aRemainVertexes;
+      for ( ; aVertIter != aProcVertexes.end(); aVertIter++)
+        aRemainVertexes.push_front(*aVertIter);
+      std::list<TopoDS_Shape> aRemainEdges;
+      for ( ; anEdgeIter != aProcEdges.end(); anEdgeIter++)
+        aRemainEdges.push_front(*anEdgeIter);
+      // remove edges and vertexes used in the loop and add remaining ones
+      aProcVertexes.erase(aCopyVLoop, aProcVertexes.end());
+      aProcVertexes.insert(aProcVertexes.end(), aRemainVertexes.begin(), aRemainVertexes.end());
+      aProcEdges.erase(aCopyELoop, aProcEdges.end());
+      aProcEdges.insert(aProcEdges.end(), aRemainEdges.begin(), aRemainEdges.end());
+
+      // Recalculate current vertex and current direction
+      if (!aProcVertexes.empty())
+      {
+        aNextVertex = aProcVertexes.back();
+        if (!aProcEdges.empty())
+          aNextDir = getOuterEdgeDirection(aProcEdges.back(), aNextVertex);
+        else aNextDir = -aDirY;
+      }
+    }
+
+    // if next vertex connected only to alone edge, this is a part of wire (not a closed loop),
+    // we need to go back through the list of already checked edges to find a branching vertex
+    if (!aMapVE.IsEmpty() && aMapVE.Contains(aNextVertex) && 
+        aMapVE.FindFromKey(aNextVertex).Size() == 1)
+    {
+      std::list<TopoDS_Shape>::reverse_iterator aVRIter = aProcVertexes.rbegin();
+      std::list<TopoDS_Shape>::reverse_iterator aERIter = aProcEdges.rbegin();
+      for (++aERIter, ++aVRIter; aERIter != aProcEdges.rend(); aERIter++, aVRIter++)
+        if (aMapVE.FindFromKey(*aVRIter).Size() > 2)
+          break;
+      if (aERIter != aProcEdges.rend() || aMapVE.FindFromKey(*aVRIter).Size() == 1)
+      { // the branching vertex was found or current list of edges is a wire without branches
+        std::list<TopoDS_Shape>::iterator aEIter;
+        TopoDS_Shape aCurEdge;
+        if (aERIter != aProcEdges.rend())
+        {
+          aEIter = aERIter.base();
+          aCurEdge = *aERIter;
+        }
+        else
+          aEIter = aProcEdges.begin();
+        std::list<TopoDS_Wire> aTail;
+        createWireList(*aVRIter, aEIter, aProcEdges.end(), anEdgesInLoops, aTail);
+        std::list<TopoDS_Wire>::const_iterator aTailIter = aTail.begin();
+        for ( ; aTailIter != aTail.end(); aTailIter++)
+          if (!aTailIter->IsNull())
+          {
+            boost::shared_ptr<GeomAPI_Shape> aWire(new GeomAPI_Shape);
+            aWire->setImpl(new TopoDS_Shape(*aTailIter));
+            theResultWires.push_back(aWire);
+          }
+        std::list<TopoDS_Shape>::iterator aVIter = aVRIter.base();
+        std::list<TopoDS_Shape>::iterator aEItCopy = aEIter;
+        removeWasteEdges(--aVIter, aEItCopy, aProcVertexes.end(), aProcEdges.end(), aMapVE);
+
+        aProcEdges.erase(aEIter, aProcEdges.end());
+        aVIter = aVRIter.base();
+        aProcVertexes.erase(aVIter, aProcVertexes.end());
+
+        if (!aProcVertexes.empty())
+        {
+          aNextVertex = aProcVertexes.back();
+          if (!aCurEdge.IsNull())
+            aNextDir = getOuterEdgeDirection(aCurEdge, aNextVertex);
+        }
+      }
+      else
+      { // there is no branching vertex in the list of proceeded,
+        // so we should revert the list and go the opposite way
+        aProcVertexes.reverse();
+        aProcEdges.reverse();
+        aNextVertex = aProcVertexes.back();
+        aNextDir = getOuterEdgeDirection(aProcEdges.back(), aNextVertex);
+      }
+    }
+
+    // When all edges of current component of connectivity are processed,
+    // we should repeat procedure for finding initial vertex in the remaining
+    if (!aMapVE.IsEmpty() && !aMapVE.Contains(aNextVertex))
+    {
+      aProcVertexes.clear();
+      aProcEdges.clear();
+
+      TopoDS_Shape aStartEdge;
+      aStartVertex = findStartVertex(aMapVE, aDirX, aDirY);
+      aProcVertexes.push_back(aStartVertex);
+      findNextVertex(aStartVertex, aMapVE, aDirY, aNorm.Reversed(), aNextVertex, aStartEdge, aNextDir);
+      aProcVertexes.push_back(aNextVertex);
+      aProcEdges.push_back(aStartEdge);
+    }
+
+    aCurVertex = aNextVertex;
+    aCurDir = aNextDir;
+  }
+
+  if (theResultFaces.size() > 1)
+    fixIntersections(theResultFaces);
+}
+
+void GeomAlgoAPI_SketchBuilder::fixIntersections(
+          std::list< boost::shared_ptr<GeomAPI_Shape> >& theFaces)
+{
+////  TopOpeBRepTool_ShapeClassifier aClassifier;
+////  const int aSameDomain = 1;
+////
+////  std::list< boost::shared_ptr<GeomAPI_Shape> >::iterator anIter1 = theFaces.begin();
+////  std::list< boost::shared_ptr<GeomAPI_Shape> >::iterator anIter2;
+////  for ( ; anIter1 != theFaces.end(); anIter1++)
+////  {
+////    anIter2 = anIter1;
+////    for (++anIter2; anIter2 != theFaces.end(); anIter2++)
+////    {
+////      TopAbs_State aState = aClassifier.StateShapeShape(
+////        (*anIter1)->impl<TopoDS_Shape>(), (*anIter2)->impl<TopoDS_Shape>(), aSameDomain);
+////      if (aState == TopAbs_IN)
+////      { // second shape should be cut from the first
+////        BRepAlgoAPI_Cut aCut((*anIter1)->impl<TopoDS_Shape>(),
+////                             (*anIter2)->impl<TopoDS_Shape>());
+////        (*anIter1)->setImpl(new TopoDS_Shape(aCut.Shape()));
+////      }
+////      else if (aState != TopAbs_OUT)
+////      { // change the shapes order and repeat
+////        aState = aClassifier.StateShapeShape(
+////          (*anIter2)->impl<TopoDS_Shape>(), (*anIter1)->impl<TopoDS_Shape>(), aSameDomain);
+////        if (aState == TopAbs_IN)
+////        { // first shape should be cut from the second
+////          BRepAlgoAPI_Cut aCut((*anIter2)->impl<TopoDS_Shape>(),
+////                               (*anIter1)->impl<TopoDS_Shape>());
+////          (*anIter2)->setImpl(new TopoDS_Shape(aCut.Shape()));
+////        }
+////      }
+////    }
+////  }
+}
+
+
+// =================== Auxiliary functions ====================================
+const TopoDS_Shape& findStartVertex(
+          const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE,
+          const gp_Dir& theDirX, const gp_Dir& theDirY)
+{
+  int aStartVertexInd = 1;
+  double aMinX = DBL_MAX;
+  double aMinY = DBL_MAX;
+  int aNbVert = theMapVE.Extent();
+  for (int i = 1; i <= aNbVert; i++)
+  {
+    const TopoDS_Vertex& aV = (const TopoDS_Vertex&)theMapVE.FindKey(i);
+    const Handle(BRep_TVertex)& aVert = (const Handle(BRep_TVertex)&)aV.TShape();
+    const gp_Pnt& aVertPnt = aVert->Pnt();
+
+    double aX = aVertPnt.XYZ().Dot(theDirX.XYZ());
+    double aY = aVertPnt.XYZ().Dot(theDirY.XYZ());
+    if ((aX < aMinX || (fabs(aX - aMinX) < tolerance && aY < aMinY)) && 
+        theMapVE.FindFromIndex(i).Extent() > 1)
+    {
+      aMinX = aX;
+      aMinY = aY;
+      aStartVertexInd = i;
+    }
+  }
+  return theMapVE.FindKey(aStartVertexInd);
+}
+
+void findNextVertex(
+          const TopoDS_Shape&                            theStartVertex,
+          const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
+          const gp_Dir&                                  theStartDir,
+          const gp_Dir&                                  theNormal,
+                TopoDS_Shape&                            theNextVertex,
+                TopoDS_Shape&                            theNextEdge,
+                gp_Dir&                                  theNextDir)
+{
+  const BOPCol_ListOfShape& anEdgesList = theVertexEdgeMap.FindFromKey(theStartVertex);
+  BOPCol_ListOfShape::Iterator aEdIter(anEdgesList);
+  double aBestEdgeProj = DBL_MAX;
+  for ( ; aEdIter.More(); aEdIter.Next())
+  {
+    gp_Dir aTang = getOuterEdgeDirection(aEdIter.Value(), theStartVertex);
+    aTang.Reverse();
+
+    // The projection is normalized in segment (-1, 1),
+    // where (-1, 0] corresponds to the angles (pi/2, 0] between theStartDir and aTang
+    // and [0, 1) corresponds to the angles [0, -pi/2)
+    double aProj = (aTang.Dot(theStartDir) - 1.0) * 0.5;
+    if (fabs(fabs(aProj) - 1) < tolerance)
+      continue;
+    if (theStartDir.DotCross(aTang, theNormal) < tolerance)
+      aProj *= -1.0;
+
+    if (aProj < aBestEdgeProj)
+    {
+      aBestEdgeProj = aProj;
+      theNextEdge = aEdIter.Value();
+      TopExp_Explorer aVertExp(theNextEdge, TopAbs_VERTEX);
+      for ( ; aVertExp.More(); aVertExp.Next())
+        if (aVertExp.Current().TShape() != theStartVertex.TShape())
+        {
+          theNextVertex = aVertExp.Current();
+          theNextDir = getOuterEdgeDirection(aEdIter.Value(), theNextVertex);
+          break;
+        }
+    }
+  }
+}
+
+static void addEdgeToWire(const TopoDS_Edge&  theEdge,
+                          const BRep_Builder& theBuilder,
+                                TopoDS_Shape& theSpliceVertex,
+                                TopoDS_Wire&  theWire)
+{
+  bool isCurVertChanged = false;
+  TopoDS_Shape aCurVertChanged;
+
+  TopExp_Explorer aVertExp(theEdge, TopAbs_VERTEX);
+  for ( ; aVertExp.More(); aVertExp.Next())
+  {
+    const TopoDS_Shape& aVertex = aVertExp.Current();
+    if (aVertex.TShape() == theSpliceVertex.TShape() && 
+        aVertex.Orientation() != theEdge.Orientation())
+    { // Current vertex is the last for the edge, so its orientation is wrong, need to revert the edge
+      const Handle(BRep_TEdge)& aTEdge = (const Handle(BRep_TEdge)&)theEdge.TShape();
+      Handle(BRep_Curve3D) aEdgeCurve = 
+        Handle(BRep_Curve3D)::DownCast(aTEdge->Curves().First());
+      Handle(Geom_Curve) aCurve = aEdgeCurve->Curve3D();
+      aCurve->Reverse();
+
+      theBuilder.UpdateEdge(theEdge, aCurve, aTEdge->Tolerance());
+      break;
+    }
+    if (aVertex.TShape() != theSpliceVertex.TShape())
+    {
+      aCurVertChanged = aVertex;
+      isCurVertChanged = true;
+    }
+  }
+  theSpliceVertex = isCurVertChanged ? aCurVertChanged : aVertExp.Current();
+
+  theBuilder.Add(theWire, theEdge);
+}
+
+void createFace(const TopoDS_Shape&                      theStartVertex,
+                const std::list<TopoDS_Shape>::iterator& theStartEdge,
+                const std::list<TopoDS_Shape>::iterator& theEndOfEdges,
+                      TopoDS_Face&                       theResFace)
+{
+  TopoDS_Wire aResWire;
+  BRep_Builder aBuilder;
+  aBuilder.MakeWire(aResWire);
+
+  TopoDS_Shape aCurVertex = theStartVertex;
+  std::list<TopoDS_Shape>::const_iterator anEdgeIter = theStartEdge;
+  for ( ; anEdgeIter != theEndOfEdges; anEdgeIter++)
+  {
+    TopoDS_Edge anEdge = *((TopoDS_Edge*)(&(*anEdgeIter)));
+    addEdgeToWire(anEdge, aBuilder, aCurVertex, aResWire);
+  }
+
+  BRepBuilderAPI_MakeFace aFaceBuilder(aResWire, Standard_True/*planar face*/);
+  if (aFaceBuilder.Error() == BRepBuilderAPI_FaceDone)
+    theResFace = aFaceBuilder.Face();
+}
+
+void createWireList(const TopoDS_Shape&                      theStartVertex,
+                    const std::list<TopoDS_Shape>::iterator& theStartEdge,
+                    const std::list<TopoDS_Shape>::iterator& theEndOfEdges,
+                    const std::set<Handle(TopoDS_TShape)>&   theEdgesInLoops,
+                          std::list<TopoDS_Wire>&            theResWires)
+{
+  BRep_Builder aBuilder;
+  bool needNewWire = true;
+  TopoDS_Shape aCurVertex = theStartVertex;
+
+  std::list<TopoDS_Shape>::iterator anIter = theStartEdge;
+  while (anIter != theEndOfEdges)
+  {
+    while (anIter != theEndOfEdges && needNewWire && 
+           theEdgesInLoops.count(anIter->TShape()) != 0)
+    {
+      TopExp_Explorer aVertExp(*anIter, TopAbs_VERTEX);
+      for ( ; aVertExp.More(); aVertExp.Next())
+        if (aVertExp.Current().TShape() != aCurVertex.TShape())
+        {
+          aCurVertex = aVertExp.Current();
+          break;
+        }
+      anIter++;
+    }
+    if (anIter == theEndOfEdges)
+      break;
+
+    if (needNewWire)
+    { // The new wire should be created
+      TopoDS_Wire aWire;
+      aBuilder.MakeWire(aWire);
+      theResWires.push_back(aWire);
+      needNewWire = false;
+    }
+    else if (theEdgesInLoops.count(anIter->TShape()) != 0)
+    { // There was found the edge already used in loop.
+      // Current wire should be released and new one should started
+      needNewWire = true;
+      continue;
+    }
+
+    TopoDS_Edge anEdge = *((TopoDS_Edge*)(&(*anIter)));
+    addEdgeToWire(anEdge, aBuilder, aCurVertex, theResWires.back());
+    anIter++;
+  }
+}
+
+
+gp_Dir getOuterEdgeDirection(const TopoDS_Shape& theEdge,
+                             const TopoDS_Shape& theVertex)
+{
+  const Handle(BRep_TVertex)& aVertex = (const Handle(BRep_TVertex)&)theVertex.TShape();
+  gp_Pnt aVertexPnt = aVertex->Pnt();
+
+  const Handle(BRep_TEdge)& anEdge = (const Handle(BRep_TEdge)&)theEdge.TShape();
+
+  // Convert the edge to the curve to calculate the tangency.
+  // There should be only one curve in the edge.
+  Handle(BRep_Curve3D) aEdCurve = 
+    Handle(BRep_Curve3D)::DownCast(anEdge->Curves().First());
+  double aFirst, aLast;
+  aEdCurve->Range(aFirst, aLast);
+  Handle(Geom_Curve) aCurve = aEdCurve->Curve3D();
+
+  gp_Pnt aPnt;
+  gp_Vec aTang;
+  aCurve->D1(aFirst, aPnt, aTang);
+  if (aVertexPnt.IsEqual(aPnt, tolerance))
+    return gp_Dir(aTang.Reversed());
+
+  aCurve->D1(aLast,  aPnt, aTang);
+  return gp_Dir(aTang);
+}
+
+void removeWasteEdges(
+                std::list<TopoDS_Shape>::iterator&  theStartVertex,
+                std::list<TopoDS_Shape>::iterator&  theStartEdge,
+          const std::list<TopoDS_Shape>::iterator&  theEndOfVertexes,
+          const std::list<TopoDS_Shape>::iterator&  theEndOfEdges,
+          BOPCol_IndexedDataMapOfShapeListOfShape&  theMapVE)
+{
+  bool isVertStep = true;
+  while (theStartVertex != theEndOfVertexes && theStartEdge != theEndOfEdges)
+  {
+    BOPCol_ListOfShape& aBunch = theMapVE.ChangeFromKey(*theStartVertex);
+    BOPCol_ListOfShape::Iterator anApprEdge(aBunch);
+    for ( ; anApprEdge.More(); anApprEdge.Next())
+      if (anApprEdge.Value() == *theStartEdge)
+        break;
+    if (anApprEdge.More())
+      aBunch.Remove(anApprEdge);
+
+    if (isVertStep)
+      theStartVertex++;
+    else
+    {
+      theStartEdge++;
+      // check current vertex to be a branching point
+      // if so, it will be a new starting point to find a loop
+      if (aBunch.Size() > 1)
+        break;
+    }
+    isVertStep = !isVertStep;
+  }
+
+  // The map of vertex-edges may be changed
+  BOPCol_IndexedDataMapOfShapeListOfShape aMapVECopy;
+  BOPCol_IndexedDataMapOfShapeListOfShape::Iterator aMapIter(theMapVE);
+  for (int ind = 1; aMapIter.More(); aMapIter.Next(), ind++)
+    if (!aMapIter.Value().IsEmpty())
+      aMapVECopy.Add(theMapVE.FindKey(ind), aMapIter.Value());
+  theMapVE.Clear();
+  theMapVE.Exchange(aMapVECopy);
+}
+
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h
new file mode 100644 (file)
index 0000000..eb1587a
--- /dev/null
@@ -0,0 +1,49 @@
+// File:        GeomAlgoAPI_SketchBuilder.h
+// Created:     02 Jun 2014
+// Author:      Artem ZHIDKOV
+
+#ifndef GeomAlgoAPI_SketchBuilder_HeaderFile
+#define GeomAlgoAPI_SketchBuilder_HeaderFile
+
+#include <GeomAlgoAPI.h>
+
+#include <boost/shared_ptr.hpp>
+#include <list>
+
+#include <GeomAPI_Dir.h>
+#include <GeomAPI_Shape.h>
+
+/** \class GeomAlgoAPI_SketchBuilder
+ *  \ingroup DataAlgo
+ *  \brief Creates planar faces based on the list of Sketch features
+ */
+class GEOMALGOAPI_EXPORT GeomAlgoAPI_SketchBuilder
+{
+public:
+  /** \brief Creates list of faces and unclosed wires on basis of the features of the sketch
+   *  \param[in]  theDirX        x-direction of the sketch
+   *  \param[in]  theDirY        y-direction of the sketch
+   *  \param[in]  theNorm        normal of the sketch
+   *  \param[in]  theFeatures    initial features of the sketch
+   *  \param[out] theResultFaces faces based on closed wires
+   *  \param[out] theResultWires unclosed wires of the sketch
+   *
+   *  The algorithm searches all loops of edges surrounding lesser squares.
+   *  It finds the vertex with minimal coordinates along X axis (theDirX) and then 
+   *  goes through the edges passing the surrounding area on the left.
+   */
+  static void createFaces(const boost::shared_ptr<GeomAPI_Dir>&                theDirX,
+                          const boost::shared_ptr<GeomAPI_Dir>&                theDirY,
+                          const boost::shared_ptr<GeomAPI_Dir>&                theNorm,
+                          const std::list< boost::shared_ptr<GeomAPI_Shape> >& theFeatures,
+                                std::list< boost::shared_ptr<GeomAPI_Shape> >& theResultFaces,
+                                std::list< boost::shared_ptr<GeomAPI_Shape> >& theResultWires);
+
+  /** \brief Searches intersections between the faces in the list 
+   *         and make holes in the faces to avoid intersections
+   *  \param[in,out] theFaces list of faces to proccess
+   */
+  static void fixIntersections(std::list< boost::shared_ptr<GeomAPI_Shape> >& theFaces);
+};
+
+#endif
index 1d97cb2b051be4fd0e51d787f4f9591d8989b2b9..a0adedd05eebb6a97b46f789ec3624a41713aaac 100644 (file)
@@ -10,6 +10,7 @@
 #include <GeomDataAPI_Point.h>
 #include <GeomAlgoAPI_FaceBuilder.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_SketchBuilder.h>
 
 using namespace std;
 
@@ -31,6 +32,38 @@ void SketchPlugin_Sketch::initAttributes()
 
 void SketchPlugin_Sketch::execute() 
 {
+  if (!data()->isValid())
+    return ;
+  boost::shared_ptr<ModelAPI_AttributeRefList> aRefList =
+    boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(data()->attribute(SKETCH_ATTR_FEATURES));
+
+  boost::shared_ptr<GeomDataAPI_Dir> aDirX = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Dir>(data()->attribute(SKETCH_ATTR_DIRX));
+  boost::shared_ptr<GeomDataAPI_Dir> aDirY = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Dir>(data()->attribute(SKETCH_ATTR_DIRY));
+  boost::shared_ptr<GeomDataAPI_Dir> aNorm = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Dir>(data()->attribute(SKETCH_ATTR_NORM));
+
+  std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aRefList->list();
+  if (aFeatures.empty())
+    return ;
+
+  std::list<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
+                                                                  aLast = aFeatures.end();
+
+  boost::shared_ptr<SketchPlugin_Feature> aFeature;
+  std::list< boost::shared_ptr<GeomAPI_Shape> > aFeaturesPreview;
+  for (; anIt != aLast; anIt++) {
+    aFeature = boost::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
+    boost::shared_ptr<GeomAPI_Shape> aPreview = aFeature->preview();
+    if (aPreview)
+      aFeaturesPreview.push_back(aPreview);
+  }
+
+  std::list< boost::shared_ptr<GeomAPI_Shape> > aLoops;
+  std::list< boost::shared_ptr<GeomAPI_Shape> > aWires;
+  GeomAlgoAPI_SketchBuilder::createFaces(aDirX->dir(), aDirY->dir(), aNorm->dir(),
+                                         aFeaturesPreview, aLoops, aWires);
 }
 
 const boost::shared_ptr<GeomAPI_Shape>& SketchPlugin_Sketch::preview()