diff --git a/src/Mod/Drawing/App/DrawingExport.cpp b/src/Mod/Drawing/App/DrawingExport.cpp index 145923fa4b..09b81ef981 100644 --- a/src/Mod/Drawing/App/DrawingExport.cpp +++ b/src/Mod/Drawing/App/DrawingExport.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include +# include # include # include # include @@ -33,6 +34,7 @@ #include #include +#include #include #include #include @@ -71,6 +73,7 @@ #include #include #include +#include #include "DrawingExport.h" #include @@ -78,6 +81,70 @@ using namespace Drawing; +TopoDS_Edge DrawingOutput::asCircle(const BRepAdaptor_Curve& c) const +{ + double curv=0; + gp_Pnt pnt, center; + + // approximate the circle center from three positions + BRepLProp_CLProps prop(c,c.FirstParameter(),2,Precision::Confusion()); + curv += prop.Curvature(); + prop.CentreOfCurvature(pnt); + center.ChangeCoord().Add(pnt.Coord()); + + prop.SetParameter(0.5*(c.FirstParameter()+c.LastParameter())); + curv += prop.Curvature(); + prop.CentreOfCurvature(pnt); + center.ChangeCoord().Add(pnt.Coord()); + + prop.SetParameter(c.LastParameter()); + curv += prop.Curvature(); + prop.CentreOfCurvature(pnt); + center.ChangeCoord().Add(pnt.Coord()); + + center.ChangeCoord().Divide(3); + curv /= 3; + + // get circle from curvature information + double radius = 1 / curv; + + TopLoc_Location location; + Handle(Poly_Polygon3D) polygon = BRep_Tool::Polygon3D(c.Edge(), location); + if (!polygon.IsNull()) { + const TColgp_Array1OfPnt& nodes = polygon->Nodes(); + for (int i = nodes.Lower(); i <= nodes.Upper(); i++) { + gp_Pnt p = nodes(i); + double dist = p.Distance(center); + if (std::abs(dist - radius) > 0.001) + return TopoDS_Edge(); + } + + gp_Circ circ; + circ.SetLocation(center); + circ.SetRadius(radius); + gp_Pnt p1 = nodes(nodes.Lower()); + gp_Pnt p2 = nodes(nodes.Upper()); + double dist = p1.Distance(p2); + + if (dist < Precision::Confusion()) { + BRepBuilderAPI_MakeEdge mkEdge(circ); + return mkEdge.Edge(); + } + else { + gp_Vec dir1(center, p1); + dir1.Normalize(); + gp_Vec dir2(center, p2); + dir2.Normalize(); + p1 = gp_Pnt(center.XYZ() + radius * dir1.XYZ()); + p2 = gp_Pnt(center.XYZ() + radius * dir2.XYZ()); + BRepBuilderAPI_MakeEdge mkEdge(circ, p1, p2); + return mkEdge.Edge(); + } + } + + return TopoDS_Edge(); +} + SVGOutput::SVGOutput() { } @@ -97,7 +164,14 @@ std::string SVGOutput::exportEdges(const TopoDS_Shape& input) printEllipse(adapt, i, result); } else if (adapt.GetType() == GeomAbs_BSplineCurve) { - printBSpline(adapt, i, result); + TopoDS_Edge circle = asCircle(adapt); + if (circle.IsNull()) { + printBSpline(adapt, i, result); + } + else { + BRepAdaptor_Curve adapt_circle(circle); + printCircle(adapt_circle, result); + } } // fallback else { diff --git a/src/Mod/Drawing/App/DrawingExport.h b/src/Mod/Drawing/App/DrawingExport.h index c525e0f513..6f93cc007e 100644 --- a/src/Mod/Drawing/App/DrawingExport.h +++ b/src/Mod/Drawing/App/DrawingExport.h @@ -25,6 +25,7 @@ #define DRAWING_EXPORT_H #include +#include class TopoDS_Shape; class BRepAdaptor_Curve; @@ -32,7 +33,15 @@ class BRepAdaptor_Curve; namespace Drawing { -class DrawingExport SVGOutput +class DrawingExport DrawingOutput +{ +public: + // If the curve is approximately a circle it will be returned, + // otherwise a null edge is returned. + TopoDS_Edge asCircle(const BRepAdaptor_Curve&) const; +}; + +class DrawingExport SVGOutput : public DrawingOutput { public: SVGOutput(); @@ -46,7 +55,7 @@ private: }; /* dxf output section - Dan Falck 2011/09/25 */ -class DrawingExport DXFOutput +class DrawingExport DXFOutput : public DrawingOutput { public: DXFOutput();