diff --git a/doc/html/img/io/svg_mapper_scale.png b/doc/html/img/io/svg_mapper_scale.png new file mode 100644 index 000000000..d537408ee Binary files /dev/null and b/doc/html/img/io/svg_mapper_scale.png differ diff --git a/doc/imports.qbk b/doc/imports.qbk index a184f1513..8bee56818 100644 --- a/doc/imports.qbk +++ b/doc/imports.qbk @@ -151,6 +151,7 @@ [import src/examples/geometries/register/multi_polygon.cpp] [import src/examples/io/svg.cpp] +[import src/examples/io/svg_mapper_scale.cpp] [import src/examples/io/wkt.cpp] [import src/examples/io/read_wkt.cpp] diff --git a/doc/reference/io/svg.qbk b/doc/reference/io/svg.qbk index be76303d3..e298dbbad 100644 --- a/doc/reference/io/svg.qbk +++ b/doc/reference/io/svg.qbk @@ -12,5 +12,9 @@ [svg_mapper] [svg_mapper_output] +[heading Example with arrows and groups] +[svg_mapper_scale] +[svg_mapper_scale_output] + [heading See also] * [link geometry.reference.io.svg.svg The SVG manipulator] diff --git a/doc/src/examples/io/Jamfile b/doc/src/examples/io/Jamfile index 489fa6a77..1b8620e6a 100644 --- a/doc/src/examples/io/Jamfile +++ b/doc/src/examples/io/Jamfile @@ -15,5 +15,6 @@ project boost-geometry-doc-example-io ; exe svg : svg.cpp ; +exe svg_mapper_scale : svg_mapper_scale.cpp ; exe wkt : wkt.cpp ; exe read_wkt : read_wkt.cpp ; diff --git a/doc/src/examples/io/svg.cpp b/doc/src/examples/io/svg.cpp index 37fb171cc..5c7ca91b3 100644 --- a/doc/src/examples/io/svg.cpp +++ b/doc/src/examples/io/svg.cpp @@ -37,7 +37,7 @@ int main() std::ofstream svg("my_map.svg"); boost::geometry::svg_mapper mapper(svg, 400, 400); - // Add geometries such that all these geometries fit on the map + // Add geometries such that all these geometries fit exactly on the map mapper.add(a); mapper.add(b); mapper.add(c); diff --git a/doc/src/examples/io/svg_mapper_scale.cpp b/doc/src/examples/io/svg_mapper_scale.cpp new file mode 100644 index 000000000..97eaf8c24 --- /dev/null +++ b/doc/src/examples/io/svg_mapper_scale.cpp @@ -0,0 +1,75 @@ +// Boost.Geometry +// QuickBook Example + +// Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[svg_mapper_scale +//` Shows the usage of svg_mapper with the scale function + +#include +#include + +#include +#include + +int main() +{ + // Specify the basic type + using point_type = boost::geometry::model::d2::point_xy; + + // Declare linestrings and set their values + boost::geometry::model::linestring a, b, c; + a.push_back({1, 0}); + a.push_back({3, 3}); + + b.push_back({5, 0}); + b.push_back({3, 2}); + + c.push_back({4, 5}); + c.push_back({3, 4}); + + // Declare a stream and an SVG mapper + std::ofstream svg("my_map.svg"); + boost::geometry::svg_mapper mapper(svg, 400, 400); + + // Add geometries such that all these geometries fit exactly on the map + mapper.add(a); + mapper.add(b); + mapper.add(c); + + // Zoom out 5% to have a bit margin around the geometries + // This also forces writing the SVG header. + mapper.scale(0.95); + + // Write a marker definition. + svg << ""; + svg << "" + " "; + svg << ""; + + // Group the first two geometries + svg << ""; + mapper.map(a, "opacity:0.5;stroke-width:1;stroke:gray;marker-end:url(#arrowhead)"); + mapper.map(b, "opacity:0.5;stroke-width:3;stroke:gray;marker-end:url(#arrowhead)"); + svg << ""; + + mapper.map(c, "opacity:0.5;stroke-width:5;stroke:red;marker-end:url(#arrowhead)"); + + return 0; +} + +//] + + +//[svg_mapper_scale_output +/*` +Output: + +[$img/io/svg_mapper_scale.png] +*/ +//] diff --git a/include/boost/geometry/io/svg/svg_mapper.hpp b/include/boost/geometry/io/svg/svg_mapper.hpp index 6722518c4..8292e12d2 100644 --- a/include/boost/geometry/io/svg/svg_mapper.hpp +++ b/include/boost/geometry/io/svg/svg_mapper.hpp @@ -368,6 +368,35 @@ public : } } + /*! + \brief Optional step, zoom in or zoom out, and forces writing the header. After writing the + transformation, geometries should not be added, and mapping can begin. After writing the + header, other SVG elements can be streamed (for example defs) which can later be used + in styles. + Call this function after add and before map or text. + \param scale A value larger than 1.0 zooms in, a value smaller than 1.0 zooms out. + A scale of 1.0 doesn't change any scaling, but still writes the SVG header. + */ + void scale(double scale = 1.0) + { + if (scale != 1.0 && scale > 0) + { + // Zoom out (scale < 1) or zoom in (scale > 1). + // Typically, users might specify 0.95, to have a small margin around their geometries. + auto& b = m_bounding_box; + auto const w = geometry::get<1, 0>(b) - geometry::get<0, 0>(b); + auto const h = geometry::get<1, 1>(b) - geometry::get<0, 1>(b); + + auto const& m = std::max(w, h) * (1.0 - scale); + geometry::set<0, 0>(b, geometry::get<0, 0>(b) - m); + geometry::set<0, 1>(b, geometry::get<0, 1>(b) - m); + geometry::set<1, 0>(b, geometry::get<1, 0>(b) + m); + geometry::set<1, 1>(b, geometry::get<1, 1>(b) + m); + } + + init_matrix(); + } + /*! \brief Maps a geometry into the SVG map using the specified style \tparam Geometry \tparam_geometry diff --git a/test/io/svg/svg.cpp b/test/io/svg/svg.cpp index d7f6fa825..4ac59e7c9 100644 --- a/test/io/svg/svg.cpp +++ b/test/io/svg/svg.cpp @@ -131,6 +131,8 @@ void test_all() mapper.add(m_po); mapper.add(var); + mapper.scale(0.95); + mapper.map(pt, style); mapper.map(b, style); mapper.map(s, style); diff --git a/test/to_svg.hpp b/test/to_svg.hpp index ad62e217a..10c13f800 100644 --- a/test/to_svg.hpp +++ b/test/to_svg.hpp @@ -259,11 +259,11 @@ inline void geom_to_svg(std::string const& wkt1, std::string const& wkt2, std::s } struct to_svg_assign_policy - : boost::geometry::detail::overlay::assign_null_policy { static bool const include_no_turn = false; static bool const include_degenerate = false; static bool const include_opposite = false; + static bool const include_start_turn = false; }; template