+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
// File: GeomAlgoAPI_SketchBuilder.cpp
// Created: 02 Jun 2014
// Author: Artem ZHIDKOV
#include <GeomAlgoAPI_SketchBuilder.h>
+#include <GeomAPI_PlanarEdges.h>
#include <set>
#include <gp_Dir.hxx>
+#include <gp_Pln.hxx>
#include <BOPAlgo_Builder.hxx>
#include <BOPAlgo_Operation.hxx>
#include <BOPTools.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Curve3D.hxx>
-#include <BRep_TEdge.hxx>
-#include <BRep_TVertex.hxx>
+#include <BRep_Tool.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepClass_FaceClassifier.hxx>
#include <Geom_Curve.hxx>
+#include <Geom_Plane.hxx>
+#include <TopExp.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>
+
+#include <assert.h>
+
+#ifndef DBL_MAX
+#define DBL_MAX 1.7976931348623158e+308
+#endif
+
const double tolerance = Precision::Confusion();
+// This value helps to find direction on the boundaries of curve.
+// It is not significant for lines, but is used for circles to avoid
+// wrong directions of movement (when two edges are tangent on the certain vertex)
+const double shift = acos(1.0 - 3.0 * tolerance);
/// \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);
+static const TopoDS_Vertex& 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);
+static void findNextVertex(const TopoDS_Vertex& theStartVertex,
+ const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
+ const gp_Dir& theStartDir, const gp_Dir& theNormal,
+ TopoDS_Vertex& theNextVertex, TopoDS_Edge& 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);
+static void createFace(const TopoDS_Vertex& theStartVertex,
+ const std::list<TopoDS_Edge>::iterator& theStartEdge,
+ const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
+ const gp_Pln& thePlane, 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);
+static void createWireList(const TopoDS_Vertex& theStartVertex,
+ const std::list<TopoDS_Edge>::iterator& theStartEdge,
+ const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
+ const std::set<TopoDS_Edge*>& 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);
+static gp_Dir getOuterEdgeDirection(const TopoDS_Edge& theEdge, const TopoDS_Vertex& 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);
-
-
+static void removeWasteEdges(std::list<TopoDS_Vertex>::iterator& theStartVertex,
+ std::list<TopoDS_Edge>::iterator& theStartEdge,
+ const std::list<TopoDS_Vertex>::iterator& theEndOfVertexes,
+ const std::list<TopoDS_Edge>::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)
+ const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
+ const std::shared_ptr<GeomAPI_Dir>& theDirX,
+ const std::shared_ptr<GeomAPI_Dir>& theNorm,
+ const std::list<std::shared_ptr<GeomAPI_Shape> >& theFeatures,
+ std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces,
+ std::list<std::shared_ptr<GeomAPI_Shape> >& theResultWires)
{
+ if (theFeatures.empty())
+ return;
+
// Create the list of edges with shared vertexes
BOPAlgo_Builder aBuilder;
BOPAlgo_PaveFiller aPF;
+ TopoDS_Shape aFeaturesCompound;
+
+ // Obtain only edges from the features list
+ std::list<std::shared_ptr<GeomAPI_Shape> > anEdges;
+ std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theFeatures.begin();
+ for (; aFeatIt != theFeatures.end(); aFeatIt++) {
+ std::shared_ptr<GeomAPI_Shape> aShape(*aFeatIt);
+ const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
+ if (anEdge.ShapeType() == TopAbs_EDGE)
+ anEdges.push_back(aShape);
+ }
- 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>());
+ if (anEdges.size() == 1) { // If there is only one feature, BOPAlgo_Builder will decline to work. Need to process it anyway
+ aFeaturesCompound = anEdges.front()->impl<TopoDS_Shape>();
+ } else {
+ std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator anIt = anEdges.begin();
+ for (; anIt != anEdges.end(); anIt++) {
+ std::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;
+ aFeaturesCompound = aBuilder.Shape();
}
- 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);
+ BOPCol_IndexedDataMapOfShapeListOfShape aMapVE; // map between vertexes and edges
+ BOPTools::MapShapesAndAncestors(aFeaturesCompound, TopAbs_VERTEX, TopAbs_EDGE, aMapVE);
+ if (aMapVE.IsEmpty()) // in case of not-initialized circle
+ return;
gp_Dir aDirX = theDirX->impl<gp_Dir>();
- gp_Dir aDirY = theDirY->impl<gp_Dir>();
gp_Dir aNorm = theNorm->impl<gp_Dir>();
+ gp_Dir aDirY = aNorm.Crossed(aDirX);
+
+ gp_Pln aPlane(theOrigin->impl<gp_Pnt>(), aNorm);
// Set of edges used in loops
- std::set<Handle(TopoDS_TShape)> anEdgesInLoops;
+ std::set<TopoDS_Edge*> anEdgesInLoops;
// Lists for processed vertexes and edges
- std::list<TopoDS_Shape> aProcVertexes;
- std::list<TopoDS_Shape> aProcEdges;
+ std::list<TopoDS_Vertex> aProcVertexes;
+ std::list<TopoDS_Edge> aProcEdges;
// Search the start vertex
- TopoDS_Shape aStartVertex = findStartVertex(aMapVE, aDirX, aDirY);
+ TopoDS_Vertex aStartVertex = findStartVertex(aMapVE, aDirX, aDirY);
aProcVertexes.push_back(aStartVertex);
- TopoDS_Shape aCurVertex = aStartVertex;
- gp_Dir aCurDir = aDirY;
+ TopoDS_Vertex aCurVertex = aStartVertex;
+ gp_Dir aCurDir = aDirY.Reversed();
gp_Dir aCurNorm = aNorm.Reversed();
// Go through the edges and find loops
- TopoDS_Shape aNextVertex;
- TopoDS_Shape aBindingEdge;
+ TopoDS_Vertex aNextVertex;
+ TopoDS_Edge aBindingEdge;
gp_Dir aNextDir;
- while (aMapVE.Extent() > 0)
- {
+ while (aMapVE.Extent() > 0) {
+ if (aCurVertex.IsNull())
+ return;
+ if (!aProcEdges.empty())
+ aBindingEdge = aProcEdges.back();
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())
+ bool isLoopFound = false;
+ std::list<TopoDS_Vertex>::iterator aVertIter = aProcVertexes.begin();
+ std::list<TopoDS_Edge>::iterator anEdgeIter = aProcEdges.begin();
+ for (; aVertIter != aProcVertexes.end(); aVertIter++) {
+ if (aVertIter->IsSame(aNextVertex)) {
+ isLoopFound = true;
break;
+ }
if (anEdgeIter != aProcEdges.end())
anEdgeIter++;
}
+ bool isCircleFound = (isLoopFound && anEdgeIter == aProcEdges.end());
aProcVertexes.push_back(aNextVertex);
aProcEdges.push_back(aBindingEdge);
- // The loop was found
- if (aVertIter != aProcVertexes.end())
- {
- if (aVertIter != aProcVertexes.begin())
- {
+ if (isLoopFound) {
+ // If the binding edge is a full circle, then it may be added recently. Need to update edge iterator
+ if (isCircleFound) {
+ anEdgeIter = aProcEdges.end();
+ anEdgeIter--;
+ }
+ else 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)
- {
+ gp_Dir aCN = getOuterEdgeDirection(*anEdgeIter, *aVertIter);
+ gp_Dir aCP = getOuterEdgeDirection(aProcEdges.back(), *aVertIter);
+ aCN.Reverse();
+ aCP.Reverse();
+ if (aCN.DotCross(aCP, aNorm) < -tolerance) {
// The found loop has wrong orientation and may contain sub-loops.
- // Need to check it onle again with another initial direction.
+ // Need to check it once again with another initial direction.
aCurVertex = *aVertIter;
do {
aProcVertexes.pop_back();
aProcEdges.pop_back();
} while (aCurVertex != aProcVertexes.back());
- aCurDir = getOuterEdgeDirection(aProcEdges.back(), aCurVertex);
+ aCurDir = aCN.Reversed();
aCurNorm = aNorm.Reversed();
continue;
}
}
+ if (!isCircleFound && anEdgeIter != aProcEdges.end() &&
+ anEdgeIter->IsSame(aProcEdges.back())) { // The loop on the same edge taken twice
+ aProcVertexes.pop_back();
+ aProcEdges.pop_back();
+ 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));
+ createFace(*aVertIter, anEdgeIter, aProcEdges.end(), aPlane, aPatch);
+ if (!aPatch.IsNull()) {
+ std::shared_ptr<GeomAPI_Shape> aFace(new GeomAPI_Shape);
+ aFace->setImpl(new TopoDS_Face(aPatch));
theResultFaces.push_back(aFace);
}
// push the edges used in the loop to the map
- std::list<TopoDS_Shape>::iterator anIter;
+ std::list<TopoDS_Edge>::iterator anIter;
for (anIter = anEdgeIter; anIter != aProcEdges.end(); anIter++)
- anEdgesInLoops.insert(anIter->TShape());
+ anEdgesInLoops.insert(&(*anIter));
// remove unnecessary edges
- std::list<TopoDS_Shape>::iterator aCopyVLoop = aVertIter;
- std::list<TopoDS_Shape>::iterator aCopyELoop = anEdgeIter;
+ std::list<TopoDS_Vertex>::iterator aCopyVLoop = aVertIter;
+ std::list<TopoDS_Edge>::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++)
+ std::list<TopoDS_Vertex> aRemainVertexes;
+ for (; aVertIter != aProcVertexes.end(); aVertIter++)
aRemainVertexes.push_front(*aVertIter);
- std::list<TopoDS_Shape> aRemainEdges;
- for ( ; anEdgeIter != aProcEdges.end(); anEdgeIter++)
+ std::list<TopoDS_Edge> aRemainEdges;
+ for (; anEdgeIter != aProcEdges.end(); anEdgeIter++)
aRemainEdges.push_front(*anEdgeIter);
// remove edges and vertexes used in the loop and add remaining ones
+ if (aCopyVLoop != aProcVertexes.begin()) {
+ aVertIter = aCopyVLoop;
+ aVertIter--;
+ } else
+ aVertIter = aProcVertexes.end();
aProcVertexes.erase(aCopyVLoop, aProcVertexes.end());
aProcVertexes.insert(aProcVertexes.end(), aRemainVertexes.begin(), aRemainVertexes.end());
+ if (aCopyELoop != aProcEdges.begin()) {
+ anEdgeIter = aCopyELoop;
+ anEdgeIter--;
+ } else
+ anEdgeIter = aProcEdges.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 (aVertIter == aProcVertexes.end())
+ aVertIter = aProcVertexes.begin();
+ else
+ aVertIter++;
+ if (anEdgeIter == aProcEdges.end())
+ anEdgeIter = aProcEdges.begin();
+ else
+ anEdgeIter++;
+ aCopyVLoop = aVertIter;
+ aCopyELoop = anEdgeIter;
+
+ if (aVertIter != aProcVertexes.end() &&
+ aMapVE.Contains(*aVertIter) && aMapVE.FindFromKey(*aVertIter).Extent() <= 1)
+ removeWasteEdges(aVertIter, anEdgeIter, aProcVertexes.end(), aProcEdges.end(), aMapVE);
+ if (aCopyVLoop != aVertIter)
+ aProcVertexes.erase(aCopyVLoop, aVertIter);
+ if (aCopyELoop != anEdgeIter)
+ aProcEdges.erase(aCopyELoop, anEdgeIter);
+
+ // Check whether the next vertex already exists
+ if (aVertIter != aProcVertexes.end())
+ aVertIter++;
+ if (aVertIter != aProcVertexes.end() && anEdgeIter != aProcEdges.end()) {
+ aNextVertex = *aVertIter;
+ aNextDir = getOuterEdgeDirection(*anEdgeIter, aNextVertex);
+ aProcVertexes.erase(++aVertIter, aProcVertexes.end());
+ aProcEdges.erase(++anEdgeIter, aProcEdges.end());
+ } else {
+ // Recalculate current vertex and current direction
+ aProcEdges.clear();
+ aProcVertexes.clear();
+ if (aMapVE.Extent() > 0) {
+ aNextVertex = findStartVertex(aMapVE, aDirX, aDirY);
+ aProcVertexes.push_back(aNextVertex);
+ }
+ aNextDir = aDirY.Reversed();
+ aCurNorm = aNorm.Reversed();
}
}
// 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.IsEmpty() && aMapVE.Contains(aNextVertex)
+ && aMapVE.FindFromKey(aNextVertex).Size() == 1) {
+ std::list<TopoDS_Vertex>::reverse_iterator aVRIter = aProcVertexes.rbegin();
+ std::list<TopoDS_Edge>::reverse_iterator aERIter = aProcEdges.rbegin();
+ if (aVRIter != aProcVertexes.rend())
+ aVRIter++;
+ if (aERIter != aProcEdges.rend())
+ aERIter++;
+
+ for (; 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())
- {
+ if (aERIter != aProcEdges.rend()
+ || (aVRIter != aProcVertexes.rend() && aMapVE.FindFromKey(*aVRIter).Size() == 1)) { // the branching vertex was found or current list of edges is a wire without branches
+ std::list<TopoDS_Edge>::iterator aEIter;
+ TopoDS_Edge aCurEdge;
+ if (aERIter != aProcEdges.rend()) {
aEIter = aERIter.base();
aCurEdge = *aERIter;
- }
- else
+ } 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);
+ for (; aTailIter != aTail.end(); aTailIter++)
+ if (!aTailIter->IsNull()) {
+ std::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;
+ std::list<TopoDS_Vertex>::iterator aVIter = aVRIter.base();
+ std::list<TopoDS_Edge>::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())
- {
+ 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
+ } 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);
+ aNextDir =
+ aProcEdges.empty() ? aDirY : 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))
- {
+ 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);
+ aNextVertex = aStartVertex;
+ aNextDir = aDirY.Reversed();
+ aCurNorm = aNorm.Reversed();
}
aCurVertex = aNextVertex;
fixIntersections(theResultFaces);
}
-void GeomAlgoAPI_SketchBuilder::fixIntersections(
- std::list< boost::shared_ptr<GeomAPI_Shape> >& theFaces)
+void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
+ const std::shared_ptr<GeomAPI_Dir>& theDirX,
+ const std::shared_ptr<GeomAPI_Dir>& theNorm,
+ const std::shared_ptr<GeomAPI_Shape>& theWire,
+ std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
{
-//// 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()));
-//// }
-//// }
-//// }
-//// }
+ std::list<std::shared_ptr<GeomAPI_Shape> > aFilteredWires;
+ std::shared_ptr<GeomAPI_PlanarEdges> aWire =
+ std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theWire);
+ if(aWire) {
+ // Filter wires, return only faces.
+ createFaces(theOrigin, theDirX, theNorm,
+ aWire->getEdges(), theResultFaces, aFilteredWires);
+
+ return;
+ } else { // it may be only one circle
+ std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(theWire);
+ if (anEdge) {
+ std::list<std::shared_ptr<GeomAPI_Shape> > aList;
+ aList.push_back(anEdge);
+ createFaces(theOrigin, theDirX, theNorm,
+ aList, theResultFaces, aFilteredWires);
+ }
+ }
}
+void GeomAlgoAPI_SketchBuilder::fixIntersections(
+ std::list<std::shared_ptr<GeomAPI_Shape> >& theFaces)
+{
+ BRepClass_FaceClassifier aClassifier;
+
+ std::list<std::shared_ptr<GeomAPI_Shape> >::iterator anIter1 = theFaces.begin();
+ std::list<std::shared_ptr<GeomAPI_Shape> >::iterator anIter2;
+ for (; anIter1 != theFaces.end(); anIter1++) {
+ anIter2 = anIter1;
+ for (++anIter2; anIter2 != theFaces.end(); anIter2++) {
+ const TopoDS_Face& aF1 = (*anIter1)->impl<TopoDS_Face>();
+ assert(aF1.ShapeType() == TopAbs_FACE); // all items in result list should be faces
+ TopExp_Explorer aVert2((*anIter2)->impl<TopoDS_Shape>(), TopAbs_VERTEX);
+ for (; aVert2.More(); aVert2.Next()) {
+ const TopoDS_Vertex& aV = (const TopoDS_Vertex&)aVert2.Current();
+ aClassifier.Perform(aF1, BRep_Tool::Pnt(aV), tolerance);
+ TopAbs_State aState = aClassifier.State();
+ if (aState != TopAbs_IN && aState != TopAbs_ON)
+ break;
+ }
+ if (aVert2.More()) { // second shape is not inside first, change the shapes order and repeat comparision
+ const TopoDS_Face& aF2 = (*anIter2)->impl<TopoDS_Face>();
+ assert(aF2.ShapeType() == TopAbs_FACE); // all items in result list should be faces
+ TopExp_Explorer aVert1((*anIter1)->impl<TopoDS_Shape>(), TopAbs_VERTEX);
+ for (; aVert1.More(); aVert1.Next()) {
+ const TopoDS_Vertex& aV = (const TopoDS_Vertex&)aVert2.Current();
+ aClassifier.Perform(aF2, BRep_Tool::Pnt(aV), tolerance);
+ TopAbs_State aState = aClassifier.State();
+ if (aState != TopAbs_IN && aState != TopAbs_ON)
+ break;
+ }
+ if (!aVert1.More()) { // first shape should be cut from the second
+ BRepAlgoAPI_Cut aCut((*anIter2)->impl<TopoDS_Shape>(), (*anIter1)->impl<TopoDS_Shape>());
+ aCut.Build();
+ TopExp_Explorer anExp(aCut.Shape(), TopAbs_FACE);
+ bool isFirstFace = true;
+ for (; anExp.More(); anExp.Next()) {
+ if (anExp.Current().ShapeType() != TopAbs_FACE) continue;
+ if (isFirstFace) {
+ (*anIter2)->setImpl(new TopoDS_Shape(anExp.Current()));
+ isFirstFace = false;
+ } else {
+ std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
+ aShape->setImpl(new TopoDS_Shape(anExp.Current()));
+ theFaces.push_back(aShape);
+ }
+ }
+ }
+ } else { // second shape should be cut from the first
+ BRepAlgoAPI_Cut aCut((*anIter1)->impl<TopoDS_Shape>(), (*anIter2)->impl<TopoDS_Shape>());
+ aCut.Build();
+ TopExp_Explorer anExp(aCut.Shape(), TopAbs_FACE);
+ bool isFirstFace = true;
+ for (; anExp.More(); anExp.Next()) {
+ if (anExp.Current().ShapeType() != TopAbs_FACE) continue;
+ if (isFirstFace) {
+ (*anIter1)->setImpl(new TopoDS_Shape(anExp.Current()));
+ isFirstFace = false;
+ } else {
+ std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
+ aShape->setImpl(new TopoDS_Shape(anExp.Current()));
+ theFaces.push_back(aShape);
+ }
+ }
+ }
+ }
+ }
+}
+
// =================== Auxiliary functions ====================================
-const TopoDS_Shape& findStartVertex(
- const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE,
- const gp_Dir& theDirX, const gp_Dir& theDirY)
+const TopoDS_Vertex& findStartVertex(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE,
+ const gp_Dir& theDirX, const gp_Dir& theDirY)
{
int aStartVertexInd = 1;
- double aMinX = DBL_MAX;
- double aMinY = DBL_MAX;
+ double aMaxX = -DBL_MAX;
+ double aMaxY = -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();
+ for (int i = 1; i <= aNbVert; i++) {
+ const TopoDS_Vertex& aV = (const TopoDS_Vertex&) theMapVE.FindKey(i);
+ const gp_Pnt& aVertPnt = BRep_Tool::Pnt(aV);
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;
+ if ((aX > aMaxX || (fabs(aX - aMaxX) < tolerance && aY > aMaxY))
+ && theMapVE.FindFromIndex(i).Extent() > 1) {
+ aMaxX = aX;
+ aMaxY = aY;
aStartVertexInd = i;
}
}
- return theMapVE.FindKey(aStartVertexInd);
+ return static_cast<const TopoDS_Vertex&>(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)
+void findNextVertex(const TopoDS_Vertex& theStartVertex,
+ const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
+ const gp_Dir& theStartDir, const gp_Dir& theNormal, TopoDS_Vertex& theNextVertex,
+ TopoDS_Edge& theNextEdge, gp_Dir& theNextDir)
{
+ theNextVertex = TopoDS_Vertex();
const BOPCol_ListOfShape& anEdgesList = theVertexEdgeMap.FindFromKey(theStartVertex);
+ int anEdgesNum = anEdgesList.Extent();
BOPCol_ListOfShape::Iterator aEdIter(anEdgesList);
double aBestEdgeProj = DBL_MAX;
- for ( ; aEdIter.More(); aEdIter.Next())
- {
- gp_Dir aTang = getOuterEdgeDirection(aEdIter.Value(), theStartVertex);
+ for (; aEdIter.More(); aEdIter.Next()) {
+ const TopoDS_Edge& anEdge = static_cast<const TopoDS_Edge&>(aEdIter.Value());
+ gp_Dir aTang = getOuterEdgeDirection(anEdge, 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)
+ if (anEdgesNum > 1 && fabs(fabs(aProj) - 1) < tolerance)
continue;
if (theStartDir.DotCross(aTang, theNormal) < tolerance)
aProj *= -1.0;
- if (aProj < aBestEdgeProj)
- {
+ if (aProj < aBestEdgeProj) {
aBestEdgeProj = aProj;
- theNextEdge = aEdIter.Value();
+ theNextEdge = anEdge;
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);
+ for (; aVertExp.More(); aVertExp.Next())
+ if (!aVertExp.Current().IsSame(theStartVertex)) {
+ theNextVertex = static_cast<const TopoDS_Vertex&>(aVertExp.Current());
+ theNextDir = getOuterEdgeDirection(anEdge, theNextVertex);
break;
}
+ if (!aVertExp.More()) { // This edge is a full circle
+ TopoDS_Vertex aV1, aV2;
+ TopExp::Vertices(theNextEdge, aV1, aV2);
+ if (aV1.Orientation() == theStartVertex.Orientation())
+ theNextVertex = aV2;
+ else
+ theNextVertex = aV1;
+ theNextDir = getOuterEdgeDirection(anEdge, theNextVertex);
+ }
}
}
+
+ // Probably there are two tangent edges. We will take the edge differs from current one
+ if (theNextVertex.IsNull() && anEdgesNum == 2) {
+ BOPCol_ListOfShape::Iterator aEdIter(anEdgesList);
+ if (aEdIter.Value() == theNextEdge)
+ aEdIter.Next();
+ theNextEdge = static_cast<const TopoDS_Edge&>(aEdIter.Value());
+ TopoDS_Vertex aV1, aV2;
+ TopExp::Vertices(theNextEdge, aV1, aV2);
+ theNextVertex = theStartVertex.IsSame(aV1) ? aV2 : aV1;
+ theNextDir = getOuterEdgeDirection(theNextEdge, theNextVertex);
+ }
}
-static void addEdgeToWire(const TopoDS_Edge& theEdge,
- const BRep_Builder& theBuilder,
- TopoDS_Shape& theSpliceVertex,
- TopoDS_Wire& theWire)
+static void addEdgeToWire(const TopoDS_Edge& theEdge, const BRep_Builder& theBuilder,
+ TopoDS_Shape& theSpliceVertex, TopoDS_Wire& theWire)
{
+ TopoDS_Edge anEdge = theEdge;
bool isCurVertChanged = false;
TopoDS_Shape aCurVertChanged;
TopExp_Explorer aVertExp(theEdge, TopAbs_VERTEX);
- for ( ; aVertExp.More(); aVertExp.Next())
- {
+ 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());
+ if (aVertex.IsSame(theSpliceVertex)
+ && aVertex.Orientation() != theEdge.Orientation()) { // Current vertex is the last for the edge, so its orientation is wrong, need to revert the edge
+ anEdge.Reverse();
break;
}
- if (aVertex.TShape() != theSpliceVertex.TShape())
- {
+ if (!aVertex.IsSame(theSpliceVertex)) {
aCurVertChanged = aVertex;
isCurVertChanged = true;
}
}
theSpliceVertex = isCurVertChanged ? aCurVertChanged : aVertExp.Current();
- theBuilder.Add(theWire, theEdge);
+ theBuilder.Add(theWire, anEdge);
}
-void createFace(const TopoDS_Shape& theStartVertex,
- const std::list<TopoDS_Shape>::iterator& theStartEdge,
- const std::list<TopoDS_Shape>::iterator& theEndOfEdges,
- TopoDS_Face& theResFace)
+void createFace(const TopoDS_Vertex& theStartVertex,
+ const std::list<TopoDS_Edge>::iterator& theStartEdge,
+ const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
+ const gp_Pln& thePlane,
+ 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);
+ TopoDS_Vertex aCurVertex = theStartVertex;
+ std::list<TopoDS_Edge>::const_iterator anEdgeIter = theStartEdge;
+ for (; anEdgeIter != theEndOfEdges; anEdgeIter++) {
+ if (!anEdgeIter->IsNull())
+ addEdgeToWire(*anEdgeIter, aBuilder, aCurVertex, aResWire);
}
- BRepBuilderAPI_MakeFace aFaceBuilder(aResWire, Standard_True/*planar face*/);
+ BRepBuilderAPI_MakeFace aFaceBuilder(thePlane, aResWire);
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)
+void createWireList(const TopoDS_Vertex& theStartVertex,
+ const std::list<TopoDS_Edge>::iterator& theStartEdge,
+ const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
+ const std::set<TopoDS_Edge*>& 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)
- {
+ TopoDS_Vertex aCurVertex = theStartVertex;
+
+ std::list<TopoDS_Edge>::iterator anIter = theStartEdge;
+ while (anIter != theEndOfEdges) {
+ while (anIter != theEndOfEdges && needNewWire && theEdgesInLoops.count(&(*anIter)) != 0) {
TopExp_Explorer aVertExp(*anIter, TopAbs_VERTEX);
- for ( ; aVertExp.More(); aVertExp.Next())
- if (aVertExp.Current().TShape() != aCurVertex.TShape())
- {
- aCurVertex = aVertExp.Current();
+ for (; aVertExp.More(); aVertExp.Next())
+ if (!aVertExp.Current().IsSame(aCurVertex)) {
+ aCurVertex = static_cast<const TopoDS_Vertex&>(aVertExp.Current());
break;
}
anIter++;
if (anIter == theEndOfEdges)
break;
- if (needNewWire)
- { // The new wire should be created
+ 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
+ } else if (theEdgesInLoops.count(&(*anIter)) != 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());
+ addEdgeToWire(*anIter, aBuilder, aCurVertex, theResWires.back());
anIter++;
}
}
-
-gp_Dir getOuterEdgeDirection(const TopoDS_Shape& theEdge,
- const TopoDS_Shape& theVertex)
+gp_Dir getOuterEdgeDirection(const TopoDS_Edge& theEdge, const TopoDS_Vertex& 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();
+ gp_Pnt aVertexPnt = BRep_Tool::Pnt(theVertex);
// 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();
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
gp_Pnt aPnt;
gp_Vec aTang;
- aCurve->D1(aFirst, aPnt, aTang);
+ // A direction is determined not in the boundary points but in the points with small shift.
+ // It was done to avoid tangency between circle and other edge in the shared vertex.
+ aCurve->D1(aFirst + shift > aLast ? aFirst : aFirst + shift, aPnt, aTang);
+ aCurve->D0(aFirst, aPnt);
if (aVertexPnt.IsEqual(aPnt, tolerance))
return gp_Dir(aTang.Reversed());
- aCurve->D1(aLast, aPnt, aTang);
+ aCurve->D1(aLast - shift < aFirst ? aLast : aLast - shift, 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)
+void removeWasteEdges(std::list<TopoDS_Vertex>::iterator& theStartVertex,
+ std::list<TopoDS_Edge>::iterator& theStartEdge,
+ const std::list<TopoDS_Vertex>::iterator& theEndOfVertexes,
+ const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
+ BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE)
{
bool isVertStep = true;
- while (theStartVertex != theEndOfVertexes && theStartEdge != theEndOfEdges)
- {
+ 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)
+ for (; anApprEdge.More(); anApprEdge.Next())
+ if (anApprEdge.Value().IsSame(*theStartEdge))
break;
if (anApprEdge.More())
aBunch.Remove(anApprEdge);
if (isVertStep)
theStartVertex++;
- else
- {
+ else {
theStartEdge++;
// check current vertex to be a branching point
// if so, it will be a new starting point to find a loop