SvgSerializer: Support full circles and ellipses

Use <circle> and <ellipse> to create a valid SVG for these geometries.

Limit to only the *first* edge. I am not sure whether there are
scenarios with multiple edges like this:
1. One or more straight line pieces or arc segments
2. A full closed circle
3. More straight lines or arc segments

If there is, we are keeping the original behavior here.
This commit is contained in:
Anders Granskogen Bjørnstad
2017-11-23 11:10:41 +01:00
committed by Thomas Krijnen
parent aec9d32ce7
commit ce970792ba
+60 -4
View File
@@ -27,6 +27,8 @@
#include <gp_Pln.hxx>
#include <gp_Trsf.hxx>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopExp_Explorer.hxx>
@@ -76,10 +78,64 @@ void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) {
bool conical = (ty == STANDARD_TYPE(Geom_Circle) || ty == STANDARD_TYPE(Geom_Ellipse));
bool closed = ALMOST_THE_SAME(u1 + PI2, u2);
if (conical && closed) {
std::stringstream ss;
ss << "Full circles and ellipses currently not supported (id "
<< p.first << ")";
Logger::Warning(ss.str());
if (first) {
if (ty == STANDARD_TYPE(Geom_Circle)) {
Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve);
double r = circle->Radius();
gp_Circ c = circle->Circ();
gp_Pnt center = c.Location();
path.add(" <circle style=\"stroke:black; fill:none;\" r=\"");
radii.push_back(path.add(r));
path.add("\" cx=\"");
xcoords.push_back(path.add(center.X()));
path.add("\" cy=\"");
ycoords.push_back(path.add(center.Y()));
growBoundingBox(center.X() - r, center.Y() - r);
growBoundingBox(center.X() + r, center.Y() + r);
first = false;
continue;
} else if (ty == STANDARD_TYPE(Geom_Ellipse)) {
Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(curve);
gp_Elips e = ellipse->Elips();
gp_Pnt center = e.Location();
// Write the ellipse with major radius along X axis:
path.add(" <ellipse style=\"stroke:black; fill:none;\" rx=\"");
radii.push_back(path.add(e.MajorRadius()));
path.add("\" ry\"");
radii.push_back(path.add(e.MinorRadius()));
path.add("\" cx=\"");
xcoords.push_back(path.add(center.X()));
path.add("\" cy=\"");
ycoords.push_back(path.add(center.Y()));
path.add("\"");
// Rotate it with "transform":
gp_Ax1 major_axis = e.XAxis();
double z_rotation = major_axis.Direction().AngleWithRef(gp_Dir(1., 0., 0.), gp_Dir(0., 0., 1.));
path.add(" transform=\"rotate(");
path.add(z_rotation);
path.add(" ");
path.add(center.X());
path.add(" ");
path.add(center.Y());
// Bounding box:
// More important to have all geometry in bounding box than to be minimal
growBoundingBox(center.X() - e.MajorRadius(), center.Y() - e.MajorRadius());
growBoundingBox(center.X() + e.MajorRadius(), center.Y() + e.MajorRadius());
first = false;
continue;
}
} else {
std::stringstream ss;
ss << "Skipping full circle/ellipse inside aggregated <path> (id "
<< p.first << ")";
Logger::Warning(ss.str());
}
}
const bool reversed = edge.Orientation() == TopAbs_REVERSED;