#include <set>
#include <gp_Dir.hxx>
+#include <gp_Pln.hxx>
#include <BOPAlgo_Builder.hxx>
#include <BOPAlgo_Operation.hxx>
#include <BRep_TVertex.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>
+
+#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 - 2.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(
static void createFace(const TopoDS_Shape& theStartVertex,
const std::list<TopoDS_Shape>::iterator& theStartEdge,
const std::list<TopoDS_Shape>::iterator& theEndOfEdges,
+ const gp_Pln& thePlane,
TopoDS_Face& theResFace);
/// \bief Create planar wire
void GeomAlgoAPI_SketchBuilder::createFaces(
+ const boost::shared_ptr<GeomAPI_Pnt>& theOrigin,
const boost::shared_ptr<GeomAPI_Dir>& theDirX,
const boost::shared_ptr<GeomAPI_Dir>& theDirY,
const boost::shared_ptr<GeomAPI_Dir>& theNorm,
std::list< boost::shared_ptr<GeomAPI_Shape> >& theResultFaces,
std::list< boost::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;
- std::list< boost::shared_ptr<GeomAPI_Shape> >::const_iterator anIt = theFeatures.begin();
- for (; anIt != theFeatures.end(); anIt++)
+ if (theFeatures.size() == 1)
+ { // If there is only one feature, BOPAlgo_Builder will decline to work. Need to process it anyway
+ aFeaturesCompound = theFeatures.front()->impl<TopoDS_Shape>();
+ }
+ else
{
- boost::shared_ptr<GeomAPI_Shape> aPreview(*anIt);
- aBuilder.AddArgument(aPreview->impl<TopoDS_Edge>());
+ 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 ;
+ 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);
+ 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_Pln aPlane(theOrigin->impl<gp_Pnt>(), aNorm);
+
// Set of edges used in loops
std::set<Handle(TopoDS_TShape)> anEdgesInLoops;
// Lists for processed vertexes and edges
aProcVertexes.push_back(aStartVertex);
TopoDS_Shape aCurVertex = aStartVertex;
- gp_Dir aCurDir = aDirY;
+ gp_Dir aCurDir = aDirY.Reversed();
gp_Dir aCurNorm = aNorm.Reversed();
// Go through the edges and find loops
gp_Dir aNextDir;
while (aMapVE.Extent() > 0)
{
+ if (aCurVertex.IsNull())
+ return;
findNextVertex(aCurVertex, aMapVE, aCurDir, aCurNorm, aNextVertex, aBindingEdge, aNextDir);
aCurNorm = aNorm;
// The loop was found
if (aVertIter != aProcVertexes.end())
{
+ // If the binding edge is a full circle, then the list may be empty before addition. Need to update edge iterator
+ if (aProcEdges.size() == 1)
+ anEdgeIter = aProcEdges.begin();
+
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.
// 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);
+ createFace(*aVertIter, anEdgeIter, aProcEdges.end(), aPlane, aPatch);
if (!aPatch.IsNull())
{
boost::shared_ptr<GeomAPI_Shape> aFace(new GeomAPI_Shape);
- aFace->setImpl(new TopoDS_Shape(aPatch));
+ aFace->setImpl(new TopoDS_Face(aPatch));
theResultFaces.push_back(aFace);
}
// push the edges used in the loop to the map
aNextVertex = aProcVertexes.back();
if (!aProcEdges.empty())
aNextDir = getOuterEdgeDirection(aProcEdges.back(), aNextVertex);
- else aNextDir = -aDirY;
+ else aNextDir = aDirY;
}
}
{
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 (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)
+ 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_Shape>::iterator aEIter;
TopoDS_Shape aCurEdge;
aProcVertexes.reverse();
aProcEdges.reverse();
aNextVertex = aProcVertexes.back();
- aNextDir = getOuterEdgeDirection(aProcEdges.back(), aNextVertex);
+ aNextDir = aProcEdges.empty() ? aDirY :
+ getOuterEdgeDirection(aProcEdges.back(), aNextVertex);
}
}
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;
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()));
-//// }
-//// }
-//// }
-//// }
+ BRepClass_FaceClassifier aClassifier;
+
+ 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++)
+ {
+ const TopoDS_Face& aF1 = (*anIter1)->impl<TopoDS_Face>();
+ if (aF1.ShapeType() != TopAbs_FACE) // TODO: MPV - this workaround must be fixed later by AZV, now it just removes crash
+ continue;
+ TopExp_Explorer aVert2((*anIter2)->impl<TopoDS_Shape>(), TopAbs_VERTEX);
+ for ( ; aVert2.More(); aVert2.Next())
+ {
+ Handle(BRep_TVertex) aV = Handle(BRep_TVertex)::DownCast(aVert2.Current().TShape());
+ aClassifier.Perform(aF1, aV->Pnt(), tolerance);
+ if (aClassifier.State() != TopAbs_IN)
+ 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>();
+ if (aF2.ShapeType() != TopAbs_FACE) // TODO: MPV - this workaround must be fixed later by AZV, now it just removes crash
+ continue;
+ TopExp_Explorer aVert1((*anIter1)->impl<TopoDS_Shape>(), TopAbs_VERTEX);
+ for ( ; aVert1.More(); aVert1.Next())
+ {
+ Handle(BRep_TVertex) aV = Handle(BRep_TVertex)::DownCast(aVert1.Current().TShape());
+ aClassifier.Perform(aF2, aV->Pnt(), tolerance);
+ if (aClassifier.State() != TopAbs_IN)
+ break;
+ }
+ if (!aVert1.More())
+ { // 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()));
+ }
+ }
+ else
+ { // 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()));
+ }
+ }
+ }
}
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++)
{
double aX = aVertPnt.XYZ().Dot(theDirX.XYZ());
double aY = aVertPnt.XYZ().Dot(theDirY.XYZ());
- if ((aX < aMinX || (fabs(aX - aMinX) < tolerance && aY < aMinY)) &&
+ if ((aX > aMaxX || (fabs(aX - aMaxX) < tolerance && aY > aMaxY)) &&
theMapVE.FindFromIndex(i).Extent() > 1)
{
- aMinX = aX;
- aMinY = aY;
+ aMaxX = aX;
+ aMaxY = aY;
aStartVertexInd = i;
}
}
theNextDir = getOuterEdgeDirection(aEdIter.Value(), theNextVertex);
break;
}
+ if (!aVertExp.More())
+ { // This edge is a full circle
+ TopoDS_Vertex aV1, aV2;
+ TopExp::Vertices(*(const TopoDS_Edge*)(&theNextEdge), aV1, aV2);
+ if (aV1.Orientation() == theStartVertex.Orientation())
+ theNextVertex = aV2;
+ else
+ theNextVertex = aV1;
+ theNextDir = getOuterEdgeDirection(aEdIter.Value(), theNextVertex);
+ }
}
}
}
TopoDS_Shape& theSpliceVertex,
TopoDS_Wire& theWire)
{
+ TopoDS_Edge anEdge = theEdge;
bool isCurVertChanged = false;
TopoDS_Shape aCurVertChanged;
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());
+ anEdge.Reverse();
break;
}
if (aVertex.TShape() != theSpliceVertex.TShape())
}
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,
+ const gp_Pln& thePlane,
TopoDS_Face& theResFace)
{
TopoDS_Wire aResWire;
for ( ; anEdgeIter != theEndOfEdges; anEdgeIter++)
{
TopoDS_Edge anEdge = *((TopoDS_Edge*)(&(*anEdgeIter)));
- addEdgeToWire(anEdge, aBuilder, aCurVertex, aResWire);
+ if (!anEdge.IsNull())
+ addEdgeToWire(anEdge, aBuilder, aCurVertex, aResWire);
}
- BRepBuilderAPI_MakeFace aFaceBuilder(aResWire, Standard_True/*planar face*/);
+ BRepBuilderAPI_MakeFace aFaceBuilder(thePlane, aResWire);
if (aFaceBuilder.Error() == BRepBuilderAPI_FaceDone)
theResFace = aFaceBuilder.Face();
}
gp_Pnt aPnt;
gp_Vec aTang;
- aCurve->D1(aFirst, aPnt, aTang);
+ aCurve->D1(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, aPnt, aTang);
return gp_Dir(aTang);
}