From: azv Date: Wed, 4 Jun 2014 08:31:23 +0000 (+0400) Subject: Intermediate changes for sketch builder X-Git-Tag: V_0.4.4~303^2^2^2~3 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=b035864efaaa03ffcf5a3aa32d20f84f5d6ddc58;p=modules%2Fshaper.git Intermediate changes for sketch builder --- diff --git a/src/GeomAPI/GeomAPI_Dir.cpp b/src/GeomAPI/GeomAPI_Dir.cpp index abe357b2b..e3badb440 100644 --- a/src/GeomAPI/GeomAPI_Dir.cpp +++ b/src/GeomAPI/GeomAPI_Dir.cpp @@ -41,3 +41,10 @@ double GeomAPI_Dir::dot(const boost::shared_ptr& theArg) const { return MY_DIR->Dot(theArg->impl()); } + +const boost::shared_ptr GeomAPI_Dir::cross(const boost::shared_ptr& theArg) const +{ + gp_XYZ aResult = MY_DIR->XYZ().Crossed(theArg->impl().XYZ()); + return boost::shared_ptr(new GeomAPI_XYZ(aResult.X(), aResult.Y(), aResult.Z())); +} + diff --git a/src/GeomAPI/GeomAPI_Dir.h b/src/GeomAPI/GeomAPI_Dir.h index 6ab0f1dd2..181c4672e 100644 --- a/src/GeomAPI/GeomAPI_Dir.h +++ b/src/GeomAPI/GeomAPI_Dir.h @@ -35,6 +35,8 @@ public: /// result is a scalar product of directions double dot(const boost::shared_ptr& theArg) const; + /// result is a cross product of two directions + const boost::shared_ptr cross(const boost::shared_ptr& theArg) const; }; #endif diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 509c7fd9e..548f7002f 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -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 index 000000000..01cc99bff --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp @@ -0,0 +1,577 @@ +// File: GeomAlgoAPI_SketchBuilder.cpp +// Created: 02 Jun 2014 +// Author: Artem ZHIDKOV + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +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::iterator& theStartEdge, + const std::list::iterator& theEndOfEdges, + TopoDS_Face& theResFace); + +/// \bief Create planar wire +static void createWireList(const TopoDS_Shape& theStartVertex, + const std::list::iterator& theStartEdge, + const std::list::iterator& theEndOfEdges, + const std::set& theEdgesInLoops, + std::list& 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::iterator& theStartVertex, + std::list::iterator& theStartEdge, + const std::list::iterator& theEndOfVertexes, + const std::list::iterator& theEndOfEdges, + BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE); + + + + +void GeomAlgoAPI_SketchBuilder::createFaces( + const boost::shared_ptr& theDirX, + const boost::shared_ptr& theDirY, + const boost::shared_ptr& theNorm, + const std::list< boost::shared_ptr >& theFeatures, + std::list< boost::shared_ptr >& theResultFaces, + std::list< boost::shared_ptr >& theResultWires) +{ + // Create the list of edges with shared vertexes + BOPAlgo_Builder aBuilder; + BOPAlgo_PaveFiller aPF; + + std::list< boost::shared_ptr >::const_iterator anIt = theFeatures.begin(); + for (; anIt != theFeatures.end(); anIt++) + { + boost::shared_ptr aPreview(*anIt); + aBuilder.AddArgument(aPreview->impl()); + } + 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 aDirY = theDirY->impl(); + gp_Dir aNorm = theNorm->impl(); + + // Set of edges used in loops + std::set anEdgesInLoops; + // Lists for processed vertexes and edges + std::list aProcVertexes; + std::list 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::iterator aVertIter = aProcVertexes.begin(); + std::list::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::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 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::iterator anIter; + for (anIter = anEdgeIter; anIter != aProcEdges.end(); anIter++) + anEdgesInLoops.insert(anIter->TShape()); + // remove unnecessary edges + std::list::iterator aCopyVLoop = aVertIter; + std::list::iterator aCopyELoop = anEdgeIter; + removeWasteEdges(aVertIter, anEdgeIter, aProcVertexes.end(), aProcEdges.end(), aMapVE); + + // revert the list of remaining edges + std::list aRemainVertexes; + for ( ; aVertIter != aProcVertexes.end(); aVertIter++) + aRemainVertexes.push_front(*aVertIter); + std::list 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::reverse_iterator aVRIter = aProcVertexes.rbegin(); + std::list::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::iterator aEIter; + TopoDS_Shape aCurEdge; + if (aERIter != aProcEdges.rend()) + { + aEIter = aERIter.base(); + aCurEdge = *aERIter; + } + else + aEIter = aProcEdges.begin(); + std::list aTail; + createWireList(*aVRIter, aEIter, aProcEdges.end(), anEdgesInLoops, aTail); + std::list::const_iterator aTailIter = aTail.begin(); + for ( ; aTailIter != aTail.end(); aTailIter++) + if (!aTailIter->IsNull()) + { + boost::shared_ptr aWire(new GeomAPI_Shape); + aWire->setImpl(new TopoDS_Shape(*aTailIter)); + theResultWires.push_back(aWire); + } + std::list::iterator aVIter = aVRIter.base(); + std::list::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 >& theFaces) +{ +//// TopOpeBRepTool_ShapeClassifier aClassifier; +//// const int aSameDomain = 1; +//// +//// std::list< boost::shared_ptr >::iterator anIter1 = theFaces.begin(); +//// std::list< boost::shared_ptr >::iterator anIter2; +//// for ( ; anIter1 != theFaces.end(); anIter1++) +//// { +//// anIter2 = anIter1; +//// for (++anIter2; anIter2 != theFaces.end(); anIter2++) +//// { +//// TopAbs_State aState = aClassifier.StateShapeShape( +//// (*anIter1)->impl(), (*anIter2)->impl(), aSameDomain); +//// if (aState == TopAbs_IN) +//// { // second shape should be cut from the first +//// BRepAlgoAPI_Cut aCut((*anIter1)->impl(), +//// (*anIter2)->impl()); +//// (*anIter1)->setImpl(new TopoDS_Shape(aCut.Shape())); +//// } +//// else if (aState != TopAbs_OUT) +//// { // change the shapes order and repeat +//// aState = aClassifier.StateShapeShape( +//// (*anIter2)->impl(), (*anIter1)->impl(), aSameDomain); +//// if (aState == TopAbs_IN) +//// { // first shape should be cut from the second +//// BRepAlgoAPI_Cut aCut((*anIter2)->impl(), +//// (*anIter1)->impl()); +//// (*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::iterator& theStartEdge, + const std::list::iterator& theEndOfEdges, + TopoDS_Face& theResFace) +{ + TopoDS_Wire aResWire; + BRep_Builder aBuilder; + aBuilder.MakeWire(aResWire); + + TopoDS_Shape aCurVertex = theStartVertex; + std::list::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::iterator& theStartEdge, + const std::list::iterator& theEndOfEdges, + const std::set& theEdgesInLoops, + std::list& theResWires) +{ + BRep_Builder aBuilder; + bool needNewWire = true; + TopoDS_Shape aCurVertex = theStartVertex; + + std::list::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::iterator& theStartVertex, + std::list::iterator& theStartEdge, + const std::list::iterator& theEndOfVertexes, + const std::list::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 index 000000000..eb1587a54 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h @@ -0,0 +1,49 @@ +// File: GeomAlgoAPI_SketchBuilder.h +// Created: 02 Jun 2014 +// Author: Artem ZHIDKOV + +#ifndef GeomAlgoAPI_SketchBuilder_HeaderFile +#define GeomAlgoAPI_SketchBuilder_HeaderFile + +#include + +#include +#include + +#include +#include + +/** \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& theDirX, + const boost::shared_ptr& theDirY, + const boost::shared_ptr& theNorm, + const std::list< boost::shared_ptr >& theFeatures, + std::list< boost::shared_ptr >& theResultFaces, + std::list< boost::shared_ptr >& 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 >& theFaces); +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 1d97cb2b0..a0adedd05 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace std; @@ -31,6 +32,38 @@ void SketchPlugin_Sketch::initAttributes() void SketchPlugin_Sketch::execute() { + if (!data()->isValid()) + return ; + boost::shared_ptr aRefList = + boost::dynamic_pointer_cast(data()->attribute(SKETCH_ATTR_FEATURES)); + + boost::shared_ptr aDirX = + boost::dynamic_pointer_cast(data()->attribute(SKETCH_ATTR_DIRX)); + boost::shared_ptr aDirY = + boost::dynamic_pointer_cast(data()->attribute(SKETCH_ATTR_DIRY)); + boost::shared_ptr aNorm = + boost::dynamic_pointer_cast(data()->attribute(SKETCH_ATTR_NORM)); + + std::list > aFeatures = aRefList->list(); + if (aFeatures.empty()) + return ; + + std::list >::const_iterator anIt = aFeatures.begin(), + aLast = aFeatures.end(); + + boost::shared_ptr aFeature; + std::list< boost::shared_ptr > aFeaturesPreview; + for (; anIt != aLast; anIt++) { + aFeature = boost::dynamic_pointer_cast(*anIt); + boost::shared_ptr aPreview = aFeature->preview(); + if (aPreview) + aFeaturesPreview.push_back(aPreview); + } + + std::list< boost::shared_ptr > aLoops; + std::list< boost::shared_ptr > aWires; + GeomAlgoAPI_SketchBuilder::createFaces(aDirX->dir(), aDirY->dir(), aNorm->dir(), + aFeaturesPreview, aLoops, aWires); } const boost::shared_ptr& SketchPlugin_Sketch::preview()