1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2015-2020.
6 // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
7 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
11 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
13 // Use, modification and distribution is subject to the Boost Software License,
14 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
15 // http://www.boost.org/LICENSE_1_0.txt)
17 #ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
18 #define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
21 #include <type_traits>
24 #include <boost/algorithm/string/classification.hpp>
25 #include <boost/algorithm/string/split.hpp>
26 #include <boost/config.hpp>
27 #include <boost/noncopyable.hpp>
28 #include <boost/scoped_ptr.hpp>
30 #include <boost/geometry/core/static_assert.hpp>
31 #include <boost/geometry/core/tags.hpp>
32 #include <boost/geometry/core/tag_cast.hpp>
33 #include <boost/geometry/algorithms/envelope.hpp>
34 #include <boost/geometry/algorithms/expand.hpp>
35 #include <boost/geometry/algorithms/is_empty.hpp>
36 #include <boost/geometry/algorithms/transform.hpp>
37 #include <boost/geometry/strategies/transform/map_transformer.hpp>
38 #include <boost/geometry/views/segment_view.hpp>
40 #include <boost/geometry/io/svg/write.hpp>
42 // Helper geometries (all points are transformed to svg-points)
43 #include <boost/geometry/geometries/geometries.hpp>
46 namespace boost { namespace geometry
50 #ifndef DOXYGEN_NO_DISPATCH
55 template <typename GeometryTag, typename Geometry, typename SvgPoint>
58 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
59 "Not or not yet implemented for this Geometry type.",
60 GeometryTag, Geometry);
64 template <typename Point, typename SvgPoint>
65 struct svg_map<point_tag, Point, SvgPoint>
67 template <typename TransformStrategy>
68 static inline void apply(std::ostream& stream,
69 std::string const& style, double size,
70 Point const& point, TransformStrategy const& strategy)
73 geometry::transform(point, ipoint, strategy);
74 stream << geometry::svg(ipoint, style, size) << std::endl;
78 template <typename BoxSeg1, typename BoxSeg2, typename SvgPoint>
79 struct svg_map_box_seg
81 template <typename TransformStrategy>
82 static inline void apply(std::ostream& stream,
83 std::string const& style, double size,
84 BoxSeg1 const& box_seg, TransformStrategy const& strategy)
88 // Fix bug in gcc compiler warning for possible uninitialization
89 #if defined(BOOST_GCC)
90 geometry::assign_zero(ibox_seg);
92 geometry::transform(box_seg, ibox_seg, strategy);
94 stream << geometry::svg(ibox_seg, style, size) << std::endl;
98 template <typename Box, typename SvgPoint>
99 struct svg_map<box_tag, Box, SvgPoint>
100 : svg_map_box_seg<Box, model::box<SvgPoint>, SvgPoint>
103 template <typename Segment, typename SvgPoint>
104 struct svg_map<segment_tag, Segment, SvgPoint>
105 : svg_map_box_seg<Segment, model::segment<SvgPoint>, SvgPoint>
109 template <typename Range1, typename Range2, typename SvgPoint>
112 template <typename TransformStrategy>
113 static inline void apply(std::ostream& stream,
114 std::string const& style, double size,
115 Range1 const& range, TransformStrategy const& strategy)
118 geometry::transform(range, irange, strategy);
119 stream << geometry::svg(irange, style, size) << std::endl;
123 template <typename Ring, typename SvgPoint>
124 struct svg_map<ring_tag, Ring, SvgPoint>
125 : svg_map_range<Ring, model::ring<SvgPoint>, SvgPoint>
129 template <typename Linestring, typename SvgPoint>
130 struct svg_map<linestring_tag, Linestring, SvgPoint>
131 : svg_map_range<Linestring, model::linestring<SvgPoint>, SvgPoint>
135 template <typename Polygon, typename SvgPoint>
136 struct svg_map<polygon_tag, Polygon, SvgPoint>
138 template <typename TransformStrategy>
139 static inline void apply(std::ostream& stream,
140 std::string const& style, double size,
141 Polygon const& polygon, TransformStrategy const& strategy)
143 model::polygon<SvgPoint> ipoly;
144 geometry::transform(polygon, ipoly, strategy);
145 stream << geometry::svg(ipoly, style, size) << std::endl;
150 template <typename Multi, typename SvgPoint>
151 struct svg_map<multi_tag, Multi, SvgPoint>
153 typedef typename single_tag_of
155 typename geometry::tag<Multi>::type
158 template <typename TransformStrategy>
159 static inline void apply(std::ostream& stream,
160 std::string const& style, double size,
161 Multi const& multi, TransformStrategy const& strategy)
163 for (typename boost::range_iterator<Multi const>::type it
164 = boost::begin(multi);
165 it != boost::end(multi);
171 typename boost::range_value<Multi>::type,
173 >::apply(stream, style, size, *it, strategy);
179 template <typename SvgPoint, typename Geometry>
180 struct devarianted_svg_map
182 template <typename TransformStrategy>
183 static inline void apply(std::ostream& stream,
184 std::string const& style,
186 Geometry const& geometry,
187 TransformStrategy const& strategy)
193 typename tag<Geometry>::type,
196 typename std::remove_const<Geometry>::type,
198 >::apply(stream, style, size, geometry, strategy);
202 template <typename SvgPoint, BOOST_VARIANT_ENUM_PARAMS(typename T)>
203 struct devarianted_svg_map<SvgPoint, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
205 template <typename TransformStrategy>
206 struct visitor: static_visitor<void>
209 std::string const& m_style;
211 TransformStrategy const& m_strategy;
213 visitor(std::ostream& os,
214 std::string const& style,
216 TransformStrategy const& strategy)
220 , m_strategy(strategy)
223 template <typename Geometry>
224 inline void operator()(Geometry const& geometry) const
226 devarianted_svg_map<SvgPoint, Geometry>::apply(m_os, m_style, m_size, geometry, m_strategy);
230 template <typename TransformStrategy>
231 static inline void apply(std::ostream& stream,
232 std::string const& style,
234 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
235 TransformStrategy const& strategy)
237 boost::apply_visitor(visitor<TransformStrategy>(stream, style, size, strategy), geometry);
242 } // namespace dispatch
246 template <typename SvgPoint, typename Geometry, typename TransformStrategy>
247 inline void svg_map(std::ostream& stream,
248 std::string const& style, double size,
249 Geometry const& geometry, TransformStrategy const& strategy)
251 dispatch::devarianted_svg_map<SvgPoint, Geometry>::apply(stream,
252 style, size, geometry, strategy);
257 \brief Helper class to create SVG maps
258 \tparam Point Point type, for input geometries.
259 \tparam SameScale Boolean flag indicating if horizontal and vertical scale should
260 be the same. The default value is true
261 \tparam SvgCoordinateType Coordinate type of SVG points. SVG is capable to
262 use floating point coordinates. Therefore the default value is double
265 \qbk{[include reference/io/svg.qbk]}
270 bool SameScale = true,
271 typename SvgCoordinateType = double
273 class svg_mapper : boost::noncopyable
275 typedef model::point<SvgCoordinateType, 2, cs::cartesian> svg_point_type;
277 typedef typename geometry::select_most_precise
279 typename coordinate_type<Point>::type,
281 >::type calculation_type;
283 typedef strategy::transform::map_transformer
286 geometry::dimension<Point>::type::value,
287 geometry::dimension<Point>::type::value,
292 model::box<Point> m_bounding_box;
293 boost::scoped_ptr<transformer_type> m_matrix;
294 std::ostream& m_stream;
295 SvgCoordinateType m_width, m_height;
296 std::string m_width_height; // for <svg> tag only, defaults to 2x 100%
302 m_matrix.reset(new transformer_type(m_bounding_box,
306 m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
308 << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
310 << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
312 << "<svg " << m_width_height << " version=\"1.1\""
314 << "xmlns=\"http://www.w3.org/2000/svg\""
316 << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
325 \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
326 Should be called explicitly.
327 \param stream Output stream, should be a stream already open
328 \param width Width of the SVG map (in SVG pixels)
329 \param height Height of the SVG map (in SVG pixels)
330 \param width_height Optional information to increase width and/or height
332 svg_mapper(std::ostream& stream
333 , SvgCoordinateType width
334 , SvgCoordinateType height
335 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
339 , m_width_height(width_height)
341 assign_inverse(m_bounding_box);
345 \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
347 virtual ~svg_mapper()
349 m_stream << "</svg>" << std::endl;
353 \brief Adds a geometry to the transformation matrix. After doing this,
354 the specified geometry can be mapped fully into the SVG map
355 \tparam Geometry \tparam_geometry
356 \param geometry \param_geometry
358 template <typename Geometry>
359 void add(Geometry const& geometry)
361 if (! geometry::is_empty(geometry))
363 expand(m_bounding_box,
372 \brief Maps a geometry into the SVG map using the specified style
373 \tparam Geometry \tparam_geometry
374 \param geometry \param_geometry
375 \param style String containing verbatim SVG style information
376 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
377 specify linewidth in the SVG style information
379 template <typename Geometry>
380 void map(Geometry const& geometry, std::string const& style,
384 svg_map<svg_point_type>(m_stream, style, size, geometry, *m_matrix);
388 \brief Adds a text to the SVG map
389 \tparam TextPoint \tparam_point
390 \param point Location of the text (in map units)
391 \param s The text itself
392 \param style String containing verbatim SVG style information, of the text
393 \param offset_x Offset in SVG pixels, defaults to 0
394 \param offset_y Offset in SVG pixels, defaults to 0
395 \param lineheight Line height in SVG pixels, in case the text contains \n
397 template <typename TextPoint>
398 void text(TextPoint const& point, std::string const& s,
399 std::string const& style,
400 double offset_x = 0.0, double offset_y = 0.0,
401 double lineheight = 10.0)
404 svg_point_type map_point;
405 transform(point, map_point, *m_matrix);
407 << "<text style=\"" << style << "\""
408 << " x=\"" << get<0>(map_point) + offset_x << "\""
409 << " y=\"" << get<1>(map_point) + offset_y << "\""
411 if (s.find("\n") == std::string::npos)
419 std::vector<std::string> splitted;
420 boost::split(splitted, s, boost::is_any_of("\n"));
421 for (std::vector<std::string>::const_iterator it
423 it != splitted.end();
424 ++it, offset_y += lineheight)
427 << "<tspan x=\"" << get<0>(map_point) + offset_x
429 << " y=\"" << get<1>(map_point) + offset_y
431 << ">" << *it << "</tspan>";
434 m_stream << "</text>" << std::endl;
439 }} // namespace boost::geometry
442 #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP