1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
6 // This file was modified by Oracle on 2016.
7 // Modifications copyright (c) 2016, Oracle and/or its affiliates.
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_WRITE_HPP
19 #define BOOST_GEOMETRY_IO_SVG_WRITE_HPP
24 #include <boost/config.hpp>
25 #include <boost/mpl/assert.hpp>
26 #include <boost/range.hpp>
28 #include <boost/variant/apply_visitor.hpp>
29 #include <boost/variant/static_visitor.hpp>
30 #include <boost/variant/variant_fwd.hpp>
32 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
34 #include <boost/geometry/core/exterior_ring.hpp>
35 #include <boost/geometry/core/interior_rings.hpp>
36 #include <boost/geometry/core/ring_type.hpp>
38 #include <boost/geometry/geometries/concepts/check.hpp>
41 namespace boost { namespace geometry
45 #ifndef DOXYGEN_NO_DETAIL
46 namespace detail { namespace svg
50 template <typename Point>
53 template <typename Char, typename Traits>
54 static inline void apply(std::basic_ostream<Char, Traits>& os,
55 Point const& p, std::string const& style, double size)
57 os << "<circle cx=\"" << geometry::get<0>(p)
58 << "\" cy=\"" << geometry::get<1>(p)
59 << "\" r=\"" << (size < 0 ? 5 : size)
60 << "\" style=\"" << style << "\"/>";
65 template <typename Box>
68 template <typename Char, typename Traits>
69 static inline void apply(std::basic_ostream<Char, Traits>& os,
70 Box const& box, std::string const& style, double)
72 // Prevent invisible boxes, making them >=1, using "max"
73 BOOST_USING_STD_MAX();
75 typedef typename coordinate_type<Box>::type ct;
76 ct x = geometry::get<geometry::min_corner, 0>(box);
77 ct y = geometry::get<geometry::min_corner, 1>(box);
78 ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION (ct(1),
79 geometry::get<geometry::max_corner, 0>(box) - x);
80 ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (ct(1),
81 geometry::get<geometry::max_corner, 1>(box) - y);
83 os << "<rect x=\"" << x << "\" y=\"" << y
84 << "\" width=\"" << width << "\" height=\"" << height
85 << "\" style=\"" << style << "\"/>";
89 template <typename Segment>
92 template <typename Char, typename Traits>
93 static inline void apply(std::basic_ostream<Char, Traits>& os,
94 Segment const& segment, std::string const& style, double)
96 typedef typename coordinate_type<Segment>::type ct;
97 ct x1 = geometry::get<0, 0>(segment);
98 ct y1 = geometry::get<0, 1>(segment);
99 ct x2 = geometry::get<1, 0>(segment);
100 ct y2 = geometry::get<1, 1>(segment);
102 os << "<line x1=\"" << x1 << "\" y1=\"" << y1
103 << "\" x2=\"" << x2 << "\" y2=\"" << y2
104 << "\" style=\"" << style << "\"/>";
109 \brief Stream ranges as SVG
110 \note policy is used to select type (polyline/polygon)
112 template <typename Range, typename Policy>
115 template <typename Char, typename Traits>
116 static inline void apply(std::basic_ostream<Char, Traits>& os,
117 Range const& range, std::string const& style, double)
119 typedef typename boost::range_iterator<Range const>::type iterator;
123 os << "<" << Policy::prefix() << " points=\"";
125 for (iterator it = boost::begin(range);
126 it != boost::end(range);
129 os << (first ? "" : " " )
130 << geometry::get<0>(*it)
132 << geometry::get<1>(*it);
134 os << "\" style=\"" << style << Policy::style() << "\"/>";
140 template <typename Polygon>
143 template <typename Char, typename Traits>
144 static inline void apply(std::basic_ostream<Char, Traits>& os,
145 Polygon const& polygon, std::string const& style, double)
147 typedef typename geometry::ring_type<Polygon>::type ring_type;
148 typedef typename boost::range_iterator<ring_type const>::type iterator_type;
151 os << "<g fill-rule=\"evenodd\"><path d=\"";
153 ring_type const& ring = geometry::exterior_ring(polygon);
154 for (iterator_type it = boost::begin(ring);
155 it != boost::end(ring);
158 os << (first ? "M" : " L") << " "
159 << geometry::get<0>(*it)
161 << geometry::get<1>(*it);
166 typename interior_return_type<Polygon const>::type
167 rings = interior_rings(polygon);
168 for (typename detail::interior_iterator<Polygon const>::type
169 rit = boost::begin(rings); rit != boost::end(rings); ++rit)
172 for (typename detail::interior_ring_iterator<Polygon const>::type
173 it = boost::begin(*rit); it != boost::end(*rit);
176 os << (first ? "M" : " L") << " "
177 << geometry::get<0>(*it)
179 << geometry::get<1>(*it);
183 os << " z \" style=\"" << style << "\"/></g>";
190 struct prefix_linestring
192 static inline const char* prefix() { return "polyline"; }
193 static inline const char* style() { return ";fill:none"; }
199 static inline const char* prefix() { return "polygon"; }
200 static inline const char* style() { return ""; }
204 template <typename MultiGeometry, typename Policy>
207 template <typename Char, typename Traits>
208 static inline void apply(std::basic_ostream<Char, Traits>& os,
209 MultiGeometry const& multi, std::string const& style, double size)
211 for (typename boost::range_iterator<MultiGeometry const>::type
212 it = boost::begin(multi);
213 it != boost::end(multi);
216 Policy::apply(os, *it, style, size);
224 }} // namespace detail::svg
225 #endif // DOXYGEN_NO_DETAIL
228 #ifndef DOXYGEN_NO_DISPATCH
233 \brief Dispatching base struct for SVG streaming, specialized below per geometry type
234 \details Specializations should implement a static method "stream" to stream a geometry
235 The static method should have the signature:
237 template <typename Char, typename Traits>
238 static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry)
240 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
245 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
250 template <typename Point>
251 struct svg<Point, point_tag> : detail::svg::svg_point<Point> {};
253 template <typename Segment>
254 struct svg<Segment, segment_tag> : detail::svg::svg_segment<Segment> {};
256 template <typename Box>
257 struct svg<Box, box_tag> : detail::svg::svg_box<Box> {};
259 template <typename Linestring>
260 struct svg<Linestring, linestring_tag>
261 : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
263 template <typename Ring>
264 struct svg<Ring, ring_tag>
265 : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
267 template <typename Polygon>
268 struct svg<Polygon, polygon_tag>
269 : detail::svg::svg_poly<Polygon> {};
271 template <typename MultiPoint>
272 struct svg<MultiPoint, multi_point_tag>
273 : detail::svg::svg_multi
276 detail::svg::svg_point
278 typename boost::range_value<MultiPoint>::type
284 template <typename MultiLinestring>
285 struct svg<MultiLinestring, multi_linestring_tag>
286 : detail::svg::svg_multi
289 detail::svg::svg_range
291 typename boost::range_value<MultiLinestring>::type,
292 detail::svg::prefix_linestring
298 template <typename MultiPolygon>
299 struct svg<MultiPolygon, multi_polygon_tag>
300 : detail::svg::svg_multi
303 detail::svg::svg_poly
305 typename boost::range_value<MultiPolygon>::type
312 template <typename Geometry>
313 struct devarianted_svg
315 template <typename OutputStream>
316 static inline void apply(OutputStream& os,
317 Geometry const& geometry,
318 std::string const& style,
321 svg<Geometry>::apply(os, geometry, style, size);
325 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
326 struct devarianted_svg<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
328 template <typename OutputStream>
329 struct visitor: static_visitor<void>
332 std::string const& m_style;
335 visitor(OutputStream& os, std::string const& style, double size)
341 template <typename Geometry>
342 inline void operator()(Geometry const& geometry) const
344 devarianted_svg<Geometry>::apply(m_os, geometry, m_style, m_size);
348 template <typename OutputStream>
349 static inline void apply(
351 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
352 std::string const& style,
356 boost::apply_visitor(visitor<OutputStream>(os, style, size), geometry);
360 } // namespace dispatch
361 #endif // DOXYGEN_NO_DISPATCH
365 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
367 \details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics)
369 template <typename Geometry>
370 class svg_manipulator
374 inline svg_manipulator(Geometry const& g, std::string const& style, double size)
380 template <typename Char, typename Traits>
381 inline friend std::basic_ostream<Char, Traits>& operator<<(
382 std::basic_ostream<Char, Traits>& os, svg_manipulator const& m)
384 dispatch::devarianted_svg<Geometry>::apply(os,
393 Geometry const& m_geometry;
394 std::string const& m_style;
399 \brief Manipulator to stream geometries as SVG
400 \tparam Geometry \tparam_geometry
401 \param geometry \param_geometry
402 \param style String containing verbatim SVG style information
403 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
404 specify linewidth in the SVG style information
407 template <typename Geometry>
408 inline svg_manipulator<Geometry> svg(Geometry const& geometry,
409 std::string const& style, double size = -1.0)
411 concepts::check<Geometry const>();
413 return svg_manipulator<Geometry>(geometry, style, size);
416 }} // namespace boost::geometry
418 #endif // BOOST_GEOMETRY_IO_SVG_WRITE_HPP