diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 8d486d9419..e9d8c08ee2 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -67,11 +67,13 @@ #include #include #include -//# include -//# include #include #include #include +#include +#include +#include +#include #include #include @@ -87,8 +89,6 @@ #include "DrawViewPartPy.h" // generated from DrawViewPartPy.xml -void _dumpEdge1(char* label, int i, TopoDS_Edge e); - using namespace TechDraw; using namespace std; @@ -310,44 +310,8 @@ void DrawViewPart::extractFaces() faceEdges.insert(std::end(faceEdges), std::begin(edgesToAdd),std::end(edgesToAdd)); } - //find list of unique Vertex - std::vector uniqueVert; - for(auto& fe:faceEdges) { - TopoDS_Vertex v1 = TopExp::FirstVertex(fe); - TopoDS_Vertex v2 = TopExp::LastVertex(fe); - bool addv1 = true; - bool addv2 = true; - for (auto v:uniqueVert) { - if (isSamePoint(v,v1)) - addv1 = false; - if (isSamePoint(v,v2)) - addv2 = false; - } - if (addv1) - uniqueVert.push_back(v1); - if (addv2) - uniqueVert.push_back(v2); - } - - //rebuild every edge using only unique verts - //this should help with connecting them later - std::vector cleanEdges; - std::vector walkerEdges; - for (auto fe:faceEdges) { - TopoDS_Vertex fev1 = TopExp::FirstVertex(fe); - TopoDS_Vertex fev2 = TopExp::LastVertex(fe); - int v1dx = findUniqueVert(fev1, uniqueVert); - int v2dx = findUniqueVert(fev2, uniqueVert); - BRepAdaptor_Curve adapt(fe); - Handle_Geom_Curve c = adapt.Curve().Curve(); - BRepBuilderAPI_MakeEdge mkBuilder1(c, uniqueVert.at(v1dx), uniqueVert.at(v2dx)); - TopoDS_Edge eClean = mkBuilder1.Edge(); - cleanEdges.push_back(eClean); - WalkerEdge we; - we.v1 = v1dx; - we.v2 = v2dx; - walkerEdges.push_back(we); - } + std::vector uniqueVert = makeUniqueVList(faceEdges); + std::vector walkerEdges = makeWalkerEdges(faceEdges,uniqueVert); EdgeWalker ew; ew.setSize(uniqueVert.size()); @@ -361,10 +325,10 @@ void DrawViewPart::extractFaces() edgelist::iterator iEdge = (*iFace).begin(); std::vector fe; for (;iEdge != (*iFace).end(); iEdge++) { - fe.push_back(cleanEdges.at((*iEdge).idx)); + fe.push_back(faceEdges.at((*iEdge).idx)); } - std::vector w = connectEdges(fe); - fw.push_back(w.at(0)); //looks weird, but we only passing 1 wire's edges so we only want 1 wire back + TopoDS_Wire w = makeCleanWire(fe); //make 1 clean wire from its edges + fw.push_back(w); } std::vector sortedWires = sortWiresBySize(fw,false); @@ -429,24 +393,44 @@ void DrawViewPart::extractFaces() } } -//obs? -int DrawViewPart::findEdgeByWalkerEdge(WalkerEdge we, std::vector uniqueVert, std::vector& edges) +std::vector DrawViewPart:: makeUniqueVList(std::vector edges) { - int result = -1; - TopoDS_Vertex v1 = uniqueVert.at(we.v1); - TopoDS_Vertex v2 = uniqueVert.at(we.v2); - int idx = 0; - for (auto& e:edges) { + std::vector uniqueVert; + for(auto& e:edges) { + TopoDS_Vertex v1 = TopExp::FirstVertex(e); + TopoDS_Vertex v2 = TopExp::LastVertex(e); + bool addv1 = true; + bool addv2 = true; + for (auto v:uniqueVert) { + if (isSamePoint(v,v1)) + addv1 = false; + if (isSamePoint(v,v2)) + addv2 = false; + } + if (addv1) + uniqueVert.push_back(v1); + if (addv2) + uniqueVert.push_back(v2); + } + return uniqueVert; +} + +//!make WalkerEdges (unique Vertex index pairs) from edge list +std::vector DrawViewPart::makeWalkerEdges(std::vector edges, + std::vector verts) +{ + std::vector walkerEdges; + for (auto e:edges) { TopoDS_Vertex ev1 = TopExp::FirstVertex(e); TopoDS_Vertex ev2 = TopExp::LastVertex(e); - if ( (isSamePoint(v1,ev1) && isSamePoint(v2,ev2)) || - (isSamePoint(v2,ev1) && isSamePoint(v1,ev2)) ) { - result = idx; - break; - } - idx++; + int v1dx = findUniqueVert(ev1, verts); + int v2dx = findUniqueVert(ev2, verts); + WalkerEdge we; + we.v1 = v1dx; + we.v2 = v2dx; + walkerEdges.push_back(we); } - return result; + return walkerEdges; } int DrawViewPart::findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert) @@ -608,29 +592,34 @@ Base::BoundBox3d DrawViewPart::getBoundingBox() const return bbox; } -//! build 1 or more wires from list of edges -//note disjoint edges won't be connected. have to be able to traverse all the edges -std::vector DrawViewPart::connectEdges (std::vector& edges) +//! make a clean wire with sorted, oriented, connected, etc edges +TopoDS_Wire DrawViewPart::makeCleanWire(std::vector edges, double tol) { - std::vector result; - Handle(TopTools_HSequenceOfShape) hEdges = new TopTools_HSequenceOfShape(); - Handle(TopTools_HSequenceOfShape) hWires = new TopTools_HSequenceOfShape(); - std::vector::const_iterator itEdge = edges.begin(); - for (; itEdge != edges.end(); itEdge++) - hEdges->Append(*itEdge); + TopoDS_Wire result; + BRepBuilderAPI_MakeWire mkWire; + ShapeFix_ShapeTolerance sTol; + Handle(ShapeExtend_WireData) wireData = new ShapeExtend_WireData(); - //tolerance sb tolerance of DrawViewPart instead of Precision::Confusion()? - ShapeAnalysis_FreeBounds::ConnectEdgesToWires(hEdges, Precision::Confusion(), Standard_False, hWires); - int len = hWires->Length(); - for(int i=1;i<=len;i++) { - TopoDS_Wire w = TopoDS::Wire(hWires->Value(i)); - if (BRep_Tool::IsClosed(w)) { - result.push_back(w); - } + for (auto e:edges) { + wireData->Add(e); } - //delete hEdges; //does Handle<> take care of this? - //delete hWires; + Handle(ShapeFix_Wire) fixer = new ShapeFix_Wire; + fixer->Load(wireData); + fixer->Perform(); + fixer->FixReorder(); + fixer->SetMaxTolerance(tol); + fixer->ClosedWireMode() = Standard_True; + fixer->FixConnected(Precision::Confusion()); + fixer->FixClosed(Precision::Confusion()); + + for (int i = 1; i <= wireData->NbEdges(); i ++) { + TopoDS_Edge edge = fixer->WireData()->Edge(i); + sTol.SetTolerance(edge, tol, TopAbs_VERTEX); + mkWire.Add(edge); + } + + result = mkWire.Wire(); return result; } @@ -704,6 +693,13 @@ void DrawViewPart::dumpVertexes(const char* text, const TopoDS_Shape& s) } } +void DrawViewPart::dump1Vertex(const char* text, const TopoDS_Vertex& v) +{ + Base::Console().Message("DUMP - DVP::dump1Vertex - %s\n",text); + gp_Pnt pnt = BRep_Tool::Pnt(v); + Base::Console().Message("%s: (%.3f,%.3f,%.3f)\n",text,pnt.X(),pnt.Y(),pnt.Z()); +} + PyObject *DrawViewPart::getPyObject(void) { if (PythonObject.is(Py::_None())) { @@ -713,7 +709,7 @@ PyObject *DrawViewPart::getPyObject(void) return Py::new_reference_to(PythonObject); } -void _dumpEdge1(char* label, int i, TopoDS_Edge e) +void DrawViewPart::dumpEdge(char* label, int i, TopoDS_Edge e) { BRepAdaptor_Curve adapt(e); double start = BRepLProp_CurveTool::FirstParameter(adapt); diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h index 1aa479a219..5ac1e86c6c 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.h +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -95,6 +95,8 @@ public: virtual PyObject *getPyObject(void); void dumpVertexes(const char* text, const TopoDS_Shape& s); + void dumpEdge(char* label, int i, TopoDS_Edge e); + void dump1Vertex(const char* label, const TopoDS_Vertex& v); protected: TechDrawGeometry::GeometryObject *geometryObject; @@ -104,7 +106,6 @@ protected: Base::Vector3d getValidXDir() const; void buildGeometryObject(TopoDS_Shape shape, gp_Pnt& center); void extractFaces(); - std::vector connectEdges (std::vector& edges); std::vector sortWiresBySize(std::vector& w, bool reverse = false); class wireCompare; @@ -113,7 +114,11 @@ protected: double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); bool isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2); int findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert); - int findEdgeByWalkerEdge(WalkerEdge we, std::vector uniqueVert, std::vector& edges); //obs? + std::vector makeUniqueVList(std::vector edges); + std::vector makeWalkerEdges(std::vector edges, + std::vector verts); + TopoDS_Wire makeCleanWire(std::vector edges, double tol = 0.10); + private: static App::PropertyFloatConstraint::Constraints floatRange; diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index ff76811e56..e72a8a4cb4 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -39,7 +39,6 @@ #include #include -//#include #include #include #include @@ -71,6 +70,11 @@ #include #include #include +#include +#include +#include +#include + #include #include @@ -82,7 +86,7 @@ #include #include "DrawViewSection.h" -//#include "ProjectionAlgos.h" +#include "EdgeWalker.h" using namespace TechDraw; using namespace std; @@ -225,7 +229,7 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void) TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(rawShape, inputCenter, Scale.getValue()); - buildGeometryObject(mirroredShape,inputCenter); + buildGeometryObject(mirroredShape,inputCenter); //this is original shape cut by section prism #if MOD_TECHDRAW_HANDLE_FACES extractFaces(); #endif //#if MOD_TECHDRAW_HANDLE_FACES @@ -238,7 +242,7 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void) BRep_Builder builder; builder.MakeCompound(newFaces); TopExp_Explorer expl(mirroredSection, TopAbs_FACE); - for (int i = 1 ; expl.More(); expl.Next(),i++) { + for (; expl.More(); expl.Next()) { const TopoDS_Face& face = TopoDS::Face(expl.Current()); TopoDS_Face pFace = projectFace(face, inputCenter, @@ -300,9 +304,7 @@ TopoDS_Compound DrawViewSection::findSectionPlaneIntersections(const TopoDS_Shap std::vector DrawViewSection::getFaceGeometry() { std::vector result; - //TopoDS_Compound c = getSectionFaces(); //get projected section faces? TopoDS_Compound c = sectionFaces; - //for face in c TopExp_Explorer faces(c, TopAbs_FACE); for (; faces.More(); faces.Next()) { TechDrawGeometry::Face* f = new TechDrawGeometry::Face(); @@ -314,6 +316,7 @@ std::vector DrawViewSection::getFaceGeometry() TopExp_Explorer edges(wire, TopAbs_EDGE); for (; edges.More(); edges.Next()) { const TopoDS_Edge& edge = TopoDS::Edge(edges.Current()); + //dumpEdge("edge",edgeCount,edge); TechDrawGeometry::BaseGeom* base = TechDrawGeometry::BaseGeom::baseFactory(edge); w->geoms.push_back(base); } @@ -355,7 +358,7 @@ TopoDS_Face DrawViewSection::projectFace(const TopoDS_Shape &face, TopExp_Explorer expl(hardEdges, TopAbs_EDGE); int i; for (i = 1 ; expl.More(); expl.Next(),i++) { - const TopoDS_Edge& edge = TopoDS::Edge(expl.Current()); + TopoDS_Edge edge = TopoDS::Edge(expl.Current()); if (edge.IsNull()) { Base::Console().Log("INFO - GO::projectFace - hard edge: %d is NULL\n",i); continue; @@ -364,7 +367,7 @@ TopoDS_Face DrawViewSection::projectFace(const TopoDS_Shape &face, } expl.Init(outEdges, TopAbs_EDGE); for (i = 1 ; expl.More(); expl.Next(),i++) { - const TopoDS_Edge& edge = TopoDS::Edge(expl.Current()); + TopoDS_Edge edge = TopoDS::Edge(expl.Current()); if (edge.IsNull()) { Base::Console().Log("INFO - GO::projectFace - outline edge: %d is NULL\n",i); continue; @@ -372,16 +375,39 @@ TopoDS_Face DrawViewSection::projectFace(const TopoDS_Shape &face, faceEdges.push_back(edge); } - //no guarantee HLR gives edges in any particular order, so have to build back into a face. + std::vector uniqueVert = makeUniqueVList(faceEdges); + std::vector walkerEdges = makeWalkerEdges(faceEdges,uniqueVert); + + EdgeWalker ew; + ew.setSize(uniqueVert.size()); + ew.loadEdges(walkerEdges); + ew.perform(); + facelist result = ew.getResult(); //probably two Faces most of the time. Outerwire + real wires + + facelist::iterator iFace = result.begin(); + std::vector fw; + for (;iFace != result.end(); iFace++) { + edgelist::iterator iEdge = (*iFace).begin(); + std::vector fe; + for (;iEdge != (*iFace).end(); iEdge++) { + fe.push_back(faceEdges.at((*iEdge).idx)); + } + TopoDS_Wire w = makeCleanWire(fe); //make 1 clean wire from its edges + fw.push_back(w); + } TopoDS_Face projectedFace; - std::vector faceWires = connectEdges(faceEdges); //from DrawViewPart - if (!faceWires.empty()) { - std::vector sortedWires = sortWiresBySize(faceWires); //from DrawViewPart + if (!fw.empty()) { + std::vector sortedWires = sortWiresBySize(fw); if (sortedWires.empty()) { return projectedFace; } - BRepBuilderAPI_MakeFace mkFace(sortedWires.front(),true); //true => only want planes? - std::vector::iterator itWire = (sortedWires.begin()) + 1; //starting with second face + + //TODO: this really should have the same size checking logic as DVP + //remove the largest wire (OuterWire of graph) + sortedWires.erase(sortedWires.begin()); + + BRepBuilderAPI_MakeFace mkFace(sortedWires.front(),true); //true => only want planes? + std::vector::iterator itWire = ++sortedWires.begin(); //starting with second face for (; itWire != sortedWires.end(); itWire++) { mkFace.Add(*itWire); } diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index 2b0276f94f..53bdd05be2 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -253,7 +253,6 @@ class TechDrawExport GeometryUtils double tolerance ); //! return a vector of BaseGeom*'s in tail to nose order - //could/should this be replaced by DVP::connectEdges? static std::vector chainGeoms(std::vector geoms); }; diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.cpp b/src/Mod/TechDraw/Gui/QGIViewPart.cpp index 156d7252e4..9ec221209d 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewPart.cpp @@ -61,8 +61,6 @@ using namespace TechDrawGui; using namespace TechDrawGeometry; -void _dumpPath(const char* text,QPainterPath path); - const float lineScaleFactor = 1.; // temp fiddle for devel const float vertexScaleFactor = 2.; // temp fiddle for devel @@ -365,7 +363,7 @@ void QGIViewPart::drawViewPart() //QPainterPath edgePath=drawPainterPath(*itEdge); //std::stringstream edgeId; //edgeId << "QGIVP.edgePath" << i; - //_dumpPath(edgeId.str().c_str(),edgePath); + //dumpPath(edgeId.str().c_str(),edgePath); } } @@ -407,7 +405,7 @@ QGIFace* QGIViewPart::drawFace(TechDrawGeometry::Face* f, int idx) //debug a path //std::stringstream faceId; //faceId << "facePath " << idx; - //_dumpPath(faceId.str().c_str(),facePath); + //dumpPath(faceId.str().c_str(),facePath); return gFace; } @@ -586,7 +584,7 @@ QRectF QGIViewPart::boundingRect() const return childrenBoundingRect(); } -void _dumpPath(const char* text,QPainterPath path) +void QGIViewPart::dumpPath(const char* text,QPainterPath path) { QPainterPath::Element elem; Base::Console().Message(">>>%s has %d elements\n",text,path.elementCount()); diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.h b/src/Mod/TechDraw/Gui/QGIViewPart.h index 5b8d70d5e5..62e040ba0b 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.h +++ b/src/Mod/TechDraw/Gui/QGIViewPart.h @@ -86,6 +86,7 @@ protected: virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; TechDraw::DrawHatch* faceIsHatched(int i,std::vector hatchObjs) const; + void dumpPath(const char* text,QPainterPath path); QColor m_colHid; diff --git a/src/Mod/TechDraw/Gui/QGIViewSection.cpp b/src/Mod/TechDraw/Gui/QGIViewSection.cpp index 4686526c50..c0857ad691 100644 --- a/src/Mod/TechDraw/Gui/QGIViewSection.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewSection.cpp @@ -74,8 +74,8 @@ void QGIViewSection::drawSectionFace() return; } std::vector::iterator fit = sectionFaces.begin(); - //QColor faceColor(0,0,255,40); //temp. sb preference or property. transparency allows bleed through/colour mix. - QColor faceColor(170,170,255); //temp. sb preference or property. + QColor faceColor(0,0,255,40); //temp. sb preference or property. transparency allows bleed through/colour mix. + //QColor faceColor(170,170,255); //temp. sb preference or property. for(; fit != sectionFaces.end(); fit++) { QGIFace* newFace = drawFace(*fit,-1); //TODO: do we need to know which sectionFace this QGIFace came from? newFace->setZValue(ZVALUE::SECTIONFACE);