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-2020.
7 // Modifications copyright (c) 2016-2020, 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/range/begin.hpp>
26 #include <boost/range/end.hpp>
27 #include <boost/range/value_type.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>
37 #include <boost/geometry/core/static_assert.hpp>
39 #include <boost/geometry/geometries/concepts/check.hpp>
42 namespace boost { namespace geometry
46 #ifndef DOXYGEN_NO_DETAIL
47 namespace detail { namespace svg
51 template <typename Point>
54 template <typename Char, typename Traits>
55 static inline void apply(std::basic_ostream<Char, Traits>& os,
56 Point const& p, std::string const& style, double size)
58 os << "<circle cx=\"" << geometry::get<0>(p)
59 << "\" cy=\"" << geometry::get<1>(p)
60 << "\" r=\"" << (size < 0 ? 5 : size)
61 << "\" style=\"" << style << "\"/>";
66 template <typename Box>
69 template <typename Char, typename Traits>
70 static inline void apply(std::basic_ostream<Char, Traits>& os,
71 Box const& box, std::string const& style, double)
73 // Prevent invisible boxes, making them >=1, using "max"
74 BOOST_USING_STD_MAX();
76 typedef typename coordinate_type<Box>::type ct;
77 ct x = geometry::get<geometry::min_corner, 0>(box);
78 ct y = geometry::get<geometry::min_corner, 1>(box);
79 ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION (ct(1),
80 geometry::get<geometry::max_corner, 0>(box) - x);
81 ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (ct(1),
82 geometry::get<geometry::max_corner, 1>(box) - y);
84 os << "<rect x=\"" << x << "\" y=\"" << y
85 << "\" width=\"" << width << "\" height=\"" << height
86 << "\" style=\"" << style << "\"/>";
90 template <typename Segment>
93 template <typename Char, typename Traits>
94 static inline void apply(std::basic_ostream<Char, Traits>& os,
95 Segment const& segment, std::string const& style, double)
97 typedef typename coordinate_type<Segment>::type ct;
98 ct x1 = geometry::get<0, 0>(segment);
99 ct y1 = geometry::get<0, 1>(segment);
100 ct x2 = geometry::get<1, 0>(segment);
101 ct y2 = geometry::get<1, 1>(segment);
103 os << "<line x1=\"" << x1 << "\" y1=\"" << y1
104 << "\" x2=\"" << x2 << "\" y2=\"" << y2
105 << "\" style=\"" << style << "\"/>";
110 \brief Stream ranges as SVG
111 \note policy is used to select type (polyline/polygon)
113 template <typename Range, typename Policy>
116 template <typename Char, typename Traits>
117 static inline void apply(std::basic_ostream<Char, Traits>& os,
118 Range const& range, std::string const& style, double)
120 typedef typename boost::range_iterator<Range const>::type iterator;
124 os << "<" << Policy::prefix() << " points=\"";
126 for (iterator it = boost::begin(range);
127 it != boost::end(range);
130 os << (first ? "" : " " )
131 << geometry::get<0>(*it)
133 << geometry::get<1>(*it);
135 os << "\" style=\"" << style << Policy::style() << "\"/>";
141 template <typename Polygon>
144 template <typename Char, typename Traits>
145 static inline void apply(std::basic_ostream<Char, Traits>& os,
146 Polygon const& polygon, std::string const& style, double)
148 typedef typename geometry::ring_type<Polygon>::type ring_type;
149 typedef typename boost::range_iterator<ring_type const>::type iterator_type;
152 os << "<g fill-rule=\"evenodd\"><path d=\"";
154 ring_type const& ring = geometry::exterior_ring(polygon);
155 for (iterator_type it = boost::begin(ring);
156 it != boost::end(ring);
159 os << (first ? "M" : " L") << " "
160 << geometry::get<0>(*it)
162 << geometry::get<1>(*it);
167 typename interior_return_type<Polygon const>::type
168 rings = interior_rings(polygon);
169 for (typename detail::interior_iterator<Polygon const>::type
170 rit = boost::begin(rings); rit != boost::end(rings); ++rit)
173 for (typename detail::interior_ring_iterator<Polygon const>::type
174 it = boost::begin(*rit); it != boost::end(*rit);
177 os << (first ? "M" : " L") << " "
178 << geometry::get<0>(*it)
180 << geometry::get<1>(*it);
184 os << " z \" style=\"" << style << "\"/></g>";
191 struct prefix_linestring
193 static inline const char* prefix() { return "polyline"; }
194 static inline const char* style() { return ";fill:none"; }
200 static inline const char* prefix() { return "polygon"; }
201 static inline const char* style() { return ""; }
205 template <typename MultiGeometry, typename Policy>
208 template <typename Char, typename Traits>
209 static inline void apply(std::basic_ostream<Char, Traits>& os,
210 MultiGeometry const& multi, std::string const& style, double size)
212 for (typename boost::range_iterator<MultiGeometry const>::type
213 it = boost::begin(multi);
214 it != boost::end(multi);
217 Policy::apply(os, *it, style, size);
225 }} // namespace detail::svg
226 #endif // DOXYGEN_NO_DETAIL
229 #ifndef DOXYGEN_NO_DISPATCH
234 \brief Dispatching base struct for SVG streaming, specialized below per geometry type
235 \details Specializations should implement a static method "stream" to stream a geometry
236 The static method should have the signature:
238 template <typename Char, typename Traits>
239 static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry)
241 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
244 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
245 "Not or not yet implemented for this Geometry type.",
249 template <typename Point>
250 struct svg<Point, point_tag> : detail::svg::svg_point<Point> {};
252 template <typename Segment>
253 struct svg<Segment, segment_tag> : detail::svg::svg_segment<Segment> {};
255 template <typename Box>
256 struct svg<Box, box_tag> : detail::svg::svg_box<Box> {};
258 template <typename Linestring>
259 struct svg<Linestring, linestring_tag>
260 : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
262 template <typename Ring>
263 struct svg<Ring, ring_tag>
264 : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
266 template <typename Polygon>
267 struct svg<Polygon, polygon_tag>
268 : detail::svg::svg_poly<Polygon> {};
270 template <typename MultiPoint>
271 struct svg<MultiPoint, multi_point_tag>
272 : detail::svg::svg_multi
275 detail::svg::svg_point
277 typename boost::range_value<MultiPoint>::type
283 template <typename MultiLinestring>
284 struct svg<MultiLinestring, multi_linestring_tag>
285 : detail::svg::svg_multi
288 detail::svg::svg_range
290 typename boost::range_value<MultiLinestring>::type,
291 detail::svg::prefix_linestring
297 template <typename MultiPolygon>
298 struct svg<MultiPolygon, multi_polygon_tag>
299 : detail::svg::svg_multi
302 detail::svg::svg_poly
304 typename boost::range_value<MultiPolygon>::type
311 template <typename Geometry>
312 struct devarianted_svg
314 template <typename OutputStream>
315 static inline void apply(OutputStream& os,
316 Geometry const& geometry,
317 std::string const& style,
320 svg<Geometry>::apply(os, geometry, style, size);
324 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
325 struct devarianted_svg<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
327 template <typename OutputStream>
328 struct visitor: static_visitor<void>
331 std::string const& m_style;
334 visitor(OutputStream& os, std::string const& style, double size)
340 template <typename Geometry>
341 inline void operator()(Geometry const& geometry) const
343 devarianted_svg<Geometry>::apply(m_os, geometry, m_style, m_size);
347 template <typename OutputStream>
348 static inline void apply(
350 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
351 std::string const& style,
355 boost::apply_visitor(visitor<OutputStream>(os, style, size), geometry);
359 } // namespace dispatch
360 #endif // DOXYGEN_NO_DISPATCH
364 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
366 \details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics)
368 template <typename Geometry>
369 class svg_manipulator
373 inline svg_manipulator(Geometry const& g, std::string const& style, double size)
379 template <typename Char, typename Traits>
380 inline friend std::basic_ostream<Char, Traits>& operator<<(
381 std::basic_ostream<Char, Traits>& os, svg_manipulator const& m)
383 dispatch::devarianted_svg<Geometry>::apply(os,
392 Geometry const& m_geometry;
393 std::string const& m_style;
398 \brief Manipulator to stream geometries as SVG
399 \tparam Geometry \tparam_geometry
400 \param geometry \param_geometry
401 \param style String containing verbatim SVG style information
402 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
403 specify linewidth in the SVG style information
406 template <typename Geometry>
407 inline svg_manipulator<Geometry> svg(Geometry const& geometry,
408 std::string const& style, double size = -1.0)
410 concepts::check<Geometry const>();
412 return svg_manipulator<Geometry>(geometry, style, size);
415 }} // namespace boost::geometry
417 #endif // BOOST_GEOMETRY_IO_SVG_WRITE_HPP