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, 2016.
6 // Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
14 // Use, modification and distribution is subject to the Boost Software License,
15 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
16 // http://www.boost.org/LICENSE_1_0.txt)
18 #ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
19 #define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
25 #include <boost/config.hpp>
26 #include <boost/mpl/assert.hpp>
27 #include <boost/noncopyable.hpp>
28 #include <boost/scoped_ptr.hpp>
29 #include <boost/type_traits/is_same.hpp>
30 #include <boost/type_traits/remove_const.hpp>
32 #include <boost/algorithm/string/split.hpp>
33 #include <boost/algorithm/string/classification.hpp>
36 #include <boost/geometry/core/tags.hpp>
37 #include <boost/geometry/core/tag_cast.hpp>
39 #include <boost/geometry/algorithms/envelope.hpp>
40 #include <boost/geometry/algorithms/expand.hpp>
41 #include <boost/geometry/algorithms/is_empty.hpp>
42 #include <boost/geometry/algorithms/transform.hpp>
43 #include <boost/geometry/strategies/transform/map_transformer.hpp>
44 #include <boost/geometry/views/segment_view.hpp>
46 #include <boost/geometry/io/svg/write.hpp>
48 // Helper geometries (all points are transformed to svg-points)
49 #include <boost/geometry/geometries/geometries.hpp>
52 namespace boost { namespace geometry
56 #ifndef DOXYGEN_NO_DISPATCH
61 template <typename GeometryTag, typename Geometry, typename SvgPoint>
66 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
72 template <typename Point, typename SvgPoint>
73 struct svg_map<point_tag, Point, SvgPoint>
75 template <typename TransformStrategy>
76 static inline void apply(std::ostream& stream,
77 std::string const& style, double size,
78 Point const& point, TransformStrategy const& strategy)
81 geometry::transform(point, ipoint, strategy);
82 stream << geometry::svg(ipoint, style, size) << std::endl;
86 template <typename BoxSeg1, typename BoxSeg2, typename SvgPoint>
87 struct svg_map_box_seg
89 template <typename TransformStrategy>
90 static inline void apply(std::ostream& stream,
91 std::string const& style, double size,
92 BoxSeg1 const& box_seg, TransformStrategy const& strategy)
96 // Fix bug in gcc compiler warning for possible uninitialization
97 #if defined(BOOST_GCC)
98 geometry::assign_zero(ibox_seg);
100 geometry::transform(box_seg, ibox_seg, strategy);
102 stream << geometry::svg(ibox_seg, style, size) << std::endl;
106 template <typename Box, typename SvgPoint>
107 struct svg_map<box_tag, Box, SvgPoint>
108 : svg_map_box_seg<Box, model::box<SvgPoint>, SvgPoint>
111 template <typename Segment, typename SvgPoint>
112 struct svg_map<segment_tag, Segment, SvgPoint>
113 : svg_map_box_seg<Segment, model::segment<SvgPoint>, SvgPoint>
117 template <typename Range1, typename Range2, typename SvgPoint>
120 template <typename TransformStrategy>
121 static inline void apply(std::ostream& stream,
122 std::string const& style, double size,
123 Range1 const& range, TransformStrategy const& strategy)
126 geometry::transform(range, irange, strategy);
127 stream << geometry::svg(irange, style, size) << std::endl;
131 template <typename Ring, typename SvgPoint>
132 struct svg_map<ring_tag, Ring, SvgPoint>
133 : svg_map_range<Ring, model::ring<SvgPoint>, SvgPoint>
137 template <typename Linestring, typename SvgPoint>
138 struct svg_map<linestring_tag, Linestring, SvgPoint>
139 : svg_map_range<Linestring, model::linestring<SvgPoint>, SvgPoint>
143 template <typename Polygon, typename SvgPoint>
144 struct svg_map<polygon_tag, Polygon, SvgPoint>
146 template <typename TransformStrategy>
147 static inline void apply(std::ostream& stream,
148 std::string const& style, double size,
149 Polygon const& polygon, TransformStrategy const& strategy)
151 model::polygon<SvgPoint> ipoly;
152 geometry::transform(polygon, ipoly, strategy);
153 stream << geometry::svg(ipoly, style, size) << std::endl;
158 template <typename Multi, typename SvgPoint>
159 struct svg_map<multi_tag, Multi, SvgPoint>
161 typedef typename single_tag_of
163 typename geometry::tag<Multi>::type
166 template <typename TransformStrategy>
167 static inline void apply(std::ostream& stream,
168 std::string const& style, double size,
169 Multi const& multi, TransformStrategy const& strategy)
171 for (typename boost::range_iterator<Multi const>::type it
172 = boost::begin(multi);
173 it != boost::end(multi);
179 typename boost::range_value<Multi>::type,
181 >::apply(stream, style, size, *it, strategy);
187 template <typename SvgPoint, typename Geometry>
188 struct devarianted_svg_map
190 template <typename TransformStrategy>
191 static inline void apply(std::ostream& stream,
192 std::string const& style,
194 Geometry const& geometry,
195 TransformStrategy const& strategy)
201 typename tag<Geometry>::type,
204 typename boost::remove_const<Geometry>::type,
206 >::apply(stream, style, size, geometry, strategy);
210 template <typename SvgPoint, BOOST_VARIANT_ENUM_PARAMS(typename T)>
211 struct devarianted_svg_map<SvgPoint, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
213 template <typename TransformStrategy>
214 struct visitor: static_visitor<void>
217 std::string const& m_style;
219 TransformStrategy const& m_strategy;
221 visitor(std::ostream& os,
222 std::string const& style,
224 TransformStrategy const& strategy)
228 , m_strategy(strategy)
231 template <typename Geometry>
232 inline void operator()(Geometry const& geometry) const
234 devarianted_svg_map<SvgPoint, Geometry>::apply(m_os, m_style, m_size, geometry, m_strategy);
238 template <typename TransformStrategy>
239 static inline void apply(std::ostream& stream,
240 std::string const& style,
242 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
243 TransformStrategy const& strategy)
245 boost::apply_visitor(visitor<TransformStrategy>(stream, style, size, strategy), geometry);
250 } // namespace dispatch
254 template <typename SvgPoint, typename Geometry, typename TransformStrategy>
255 inline void svg_map(std::ostream& stream,
256 std::string const& style, double size,
257 Geometry const& geometry, TransformStrategy const& strategy)
259 dispatch::devarianted_svg_map<SvgPoint, Geometry>::apply(stream,
260 style, size, geometry, strategy);
265 \brief Helper class to create SVG maps
266 \tparam Point Point type, for input geometries.
267 \tparam SameScale Boolean flag indicating if horizontal and vertical scale should
268 be the same. The default value is true
269 \tparam SvgCoordinateType Coordinate type of SVG points. SVG is capable to
270 use floating point coordinates. Therefore the default value is double
273 \qbk{[include reference/io/svg.qbk]}
278 bool SameScale = true,
279 typename SvgCoordinateType = double
281 class svg_mapper : boost::noncopyable
283 typedef model::point<SvgCoordinateType, 2, cs::cartesian> svg_point_type;
285 typedef typename geometry::select_most_precise
287 typename coordinate_type<Point>::type,
289 >::type calculation_type;
291 typedef strategy::transform::map_transformer
294 geometry::dimension<Point>::type::value,
295 geometry::dimension<Point>::type::value,
300 model::box<Point> m_bounding_box;
301 boost::scoped_ptr<transformer_type> m_matrix;
302 std::ostream& m_stream;
303 SvgCoordinateType m_width, m_height;
304 std::string m_width_height; // for <svg> tag only, defaults to 2x 100%
310 m_matrix.reset(new transformer_type(m_bounding_box,
314 m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
316 << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
318 << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
320 << "<svg " << m_width_height << " version=\"1.1\""
322 << "xmlns=\"http://www.w3.org/2000/svg\""
324 << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
333 \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
334 Should be called explicitly.
335 \param stream Output stream, should be a stream already open
336 \param width Width of the SVG map (in SVG pixels)
337 \param height Height of the SVG map (in SVG pixels)
338 \param width_height Optional information to increase width and/or height
340 svg_mapper(std::ostream& stream
341 , SvgCoordinateType width
342 , SvgCoordinateType height
343 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
347 , m_width_height(width_height)
349 assign_inverse(m_bounding_box);
353 \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
355 virtual ~svg_mapper()
357 m_stream << "</svg>" << std::endl;
361 \brief Adds a geometry to the transformation matrix. After doing this,
362 the specified geometry can be mapped fully into the SVG map
363 \tparam Geometry \tparam_geometry
364 \param geometry \param_geometry
366 template <typename Geometry>
367 void add(Geometry const& geometry)
369 if (! geometry::is_empty(geometry))
371 expand(m_bounding_box,
380 \brief Maps a geometry into the SVG map using the specified style
381 \tparam Geometry \tparam_geometry
382 \param geometry \param_geometry
383 \param style String containing verbatim SVG style information
384 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
385 specify linewidth in the SVG style information
387 template <typename Geometry>
388 void map(Geometry const& geometry, std::string const& style,
392 svg_map<svg_point_type>(m_stream, style, size, geometry, *m_matrix);
396 \brief Adds a text to the SVG map
397 \tparam TextPoint \tparam_point
398 \param point Location of the text (in map units)
399 \param s The text itself
400 \param style String containing verbatim SVG style information, of the text
401 \param offset_x Offset in SVG pixels, defaults to 0
402 \param offset_y Offset in SVG pixels, defaults to 0
403 \param lineheight Line height in SVG pixels, in case the text contains \n
405 template <typename TextPoint>
406 void text(TextPoint const& point, std::string const& s,
407 std::string const& style,
408 double offset_x = 0.0, double offset_y = 0.0,
409 double lineheight = 10.0)
412 svg_point_type map_point;
413 transform(point, map_point, *m_matrix);
415 << "<text style=\"" << style << "\""
416 << " x=\"" << get<0>(map_point) + offset_x << "\""
417 << " y=\"" << get<1>(map_point) + offset_y << "\""
419 if (s.find("\n") == std::string::npos)
427 std::vector<std::string> splitted;
428 boost::split(splitted, s, boost::is_any_of("\n"));
429 for (std::vector<std::string>::const_iterator it
431 it != splitted.end();
432 ++it, offset_y += lineheight)
435 << "<tspan x=\"" << get<0>(map_point) + offset_x
437 << " y=\"" << get<1>(map_point) + offset_y
439 << ">" << *it << "</tspan>";
442 m_stream << "</text>" << std::endl;
447 }} // namespace boost::geometry
450 #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP