Search code examples
c++svgboostboost-geometry

boost::geometry svg_mapper svg origin, my image is flipped?


I'm having some weird behavior with the svg_mapper.

The origin of the svg appears to be located in the lower left corner, but as far as I know an svg should have its default origin in the top left corner. The svg_mapper does not appear to have any interface to manipulate the coordinate system so I'm pretty sure I have not configured my mapper incorrectly.

The following code is just an example, I'm actually drawing a grid structure but the problem is the same. What I expect from this is a red line starting in the top left (0,0), a second point a bit to the right and then the last point in the lower right corner. But no, it goes from the lower left to the upper right.

Is this expected behavior from the svg_mapper or am I not using it properly?

typedef boost::geometry::model::d2::point_xy<double> point_type;
typedef boost::geometry::model::linestring<point_type> linestring_type;
typedef boost::geometry::svg_mapper<point_type> mapper_type;

std::ofstream svg("map.svg");
mapper_type mapper(svg, 400, 400);

linestring_type ls2{{0.0, 0.0}, {100.0, 0.0}, {400.0, 400.0}};
mapper.add(ls2);
mapper.map(ls2, "stroke:rgb(250,0,0);stroke-width:2");

enter image description here

The image above is a png but the svg generated looks like this:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<polyline points="0,400 100,400 400,0" style="stroke:rgb(250,0,0);stroke-width:2;fill:none"/>
</svg>

Edit >> Using boost 1.61


Solution

  • You are getting the expected output. If you look at the svg_mapper example program and its output at the bottom of the documentation page, you can see that the drawing produced has its origin at the lower left.

    The details of how that happens are in the svg_mapper class where it defines a transformer:

    typedef strategy::transform::map_transformer
        <
            calculation_type,
            geometry::dimension<Point>::type::value,
            geometry::dimension<Point>::type::value,
            true,  // <== Mirror in Y direction!!!
            SameScale
        > transformer_type;
    

    The map_transformer documentation explains the fourth template argument:

    if true map is mirrored upside-down (in most cases pixels are from top to bottom, while map is from bottom to top)

    The mirroring is hard-coded into svg_mapper, so to produce SVGs with the origin at top left you will need to handle that yourself. Some possible ways to do that:

    • Pre-apply a reflection to your geometry.
    • Write your own mapper class
    • Post-process the resulting XML.