什么定义了 Boost 的 svg_mapper 缩放和平移?

What define's Boost's svg_mapper scaling and translation?

此代码:

#include <fstream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

namespace bg = boost::geometry;

int main()
{
    std::ofstream svg ( "test.svg" );
    boost::geometry::svg_mapper<bg::model::d2::point_xy<double>, true, double> mapper ( svg, 6000, 3000 );

    bg::model::polygon<bg::model::d2::point_xy<double>> square{
        {{0, 0}, {0, 1000}, {1000, 1000}, {1000, 0}, {0, 0}}};
    const std::string style{"fill-opacity:1.0;fill:rgb(128,128,128);stroke:rgb(0,0,0);stroke-width:5"};

    mapper.add ( square );
    mapper.map ( square, style, 1.0 );
}

生成此 svg:

<?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">
<g fill-rule="evenodd"><path d="M 1500,3000 L 1500,0 L 4500,0 L 4500,3000 L 1500,3000 z " style="fill-opacity:1.0;fill:rgb(128,128,128);stroke:rgb(0,0,0);stroke-width:5"/></g>
</svg>

从输入多边形到映射的 svg 几何图形发生以下转换:

(0, 0) -> (1500,3000)
(0, 1000) -> (1500,0)
(1000, 1000) -> (4500,0)
(1000, 0) -> (4500,3000)
(0, 0) -> (1500,3000)

稍微盯着它看,您会看到应用了一些转换,如下所示:


我的问题是 - 是什么推动了这种转变,我可以阻止它吗?如果我不能阻止它,我可以自己检索或计算吗?

原因是我正在制作许多复杂的 SVG,并希望它们都在同一帧中。因此,如果在一个像素 (10,10) 处有一个圆圈,我希望所有图像的大小都与圆圈在完全相同的位置相同。我试图用 viewBox 来完成这个,但是缩放和平移太难预测以保持图像一致。

svg_mapper 从所有 add 编辑的几何图形计算边界框。

然后,使用map_transformer缩小到所需的width/height。

与您的预期相反,add 除了扩展边界框外 没有做任何事情。同样,在第一个 map 调用之后,没有其他 add 对用于转换的 bounding-box 有任何影响。

换句话说,您可以使用某种固定边界框,仅添加它,然后将您的几何图形映射到该“canvas”:

Demo

#include <fstream>
#include <iostream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

namespace bg = boost::geometry;
using V      = /*long*/ double;
using P      = bg::model::d2::point_xy<V>;
using B      = bg::model::box<P>;

int main()
{
    auto verify = [](auto& g) {
        if (std::string r; !bg::is_valid(g, r)) {
            std::cout << "Correcting " << r << "\n";
            bg::correct(g);
        }
    };

    V side = 1000;
    bg::model::polygon<P> square{
        {{0, 0}, {0, side}, {side, side}, {side, 0}, {0, 0}},
    };

    verify(square);

    std::array steps {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,};
    for (unsigned i = 0; i < steps.size(); ++i) {
        {
            std::ofstream svg("test" + std::to_string(i) + ".svg");
            bg::svg_mapper<P, true, V> mapper(svg, 400, 400);

            auto clone = square;
            V    ofs   = (steps[i] / 5. - 1.0) * side;
            for (auto& p : boost::make_iterator_range(bg::points_begin(clone), bg::points_end(clone)))
                bg::add_point(p, P{ofs, ofs});
            std::cout << i << ": " << bg::wkt(square) << " " << bg::wkt(clone) << "\n";

            mapper.add(B{{-side, -side}, {2 * side, 2 * side}});
            //mapper.add(square); // no effect, already within bounding box
            //mapper.add(clone);  // no effect, already within bounding box
            mapper.map(square, "fill-opacity:0.1;fill:rgb(128,0,0)", 1.0);
            mapper.map(clone,  "fill-opacity:0.1;fill:rgb(0,0,128)", 1.0);
        }
    }
}

创建了一系列 svg,我可以将其显示为穷人的动画,以表明 square 的定位是恒定的: