Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / geometry / io / svg / write_svg.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
5
6 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
7 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
8
9 // Use, modification and distribution is subject to the Boost Software License,
10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 #ifndef BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
14 #define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
15
16 #include <ostream>
17 #include <string>
18
19 #include <boost/config.hpp>
20 #include <boost/mpl/assert.hpp>
21 #include <boost/range.hpp>
22
23 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
24
25 #include <boost/geometry/core/exterior_ring.hpp>
26 #include <boost/geometry/core/interior_rings.hpp>
27 #include <boost/geometry/core/ring_type.hpp>
28
29 #include <boost/geometry/geometries/concepts/check.hpp>
30
31
32 namespace boost { namespace geometry
33 {
34
35
36 #ifndef DOXYGEN_NO_DETAIL
37 namespace detail { namespace svg
38 {
39
40
41 template <typename Point>
42 struct svg_point
43 {
44     template <typename Char, typename Traits>
45     static inline void apply(std::basic_ostream<Char, Traits>& os,
46                 Point const& p, std::string const& style, int size)
47     {
48         os << "<circle cx=\"" << geometry::get<0>(p)
49             << "\" cy=\"" << geometry::get<1>(p)
50             << "\" r=\"" << (size < 0 ? 5 : size)
51             << "\" style=\"" << style << "\"/>";
52     }
53 };
54
55
56 template <typename Box>
57 struct svg_box
58 {
59     template <typename Char, typename Traits>
60     static inline void apply(std::basic_ostream<Char, Traits>& os,
61                 Box const& box, std::string const& style, int )
62     {
63         // Prevent invisible boxes, making them >=1, using "max"
64         BOOST_USING_STD_MAX();
65
66         typedef typename coordinate_type<Box>::type ct;
67         ct x = geometry::get<geometry::min_corner, 0>(box);
68         ct y = geometry::get<geometry::min_corner, 1>(box);
69         ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION(1,
70                     geometry::get<geometry::max_corner, 0>(box) - x);
71         ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (1,
72                     geometry::get<geometry::max_corner, 1>(box) - y);
73
74         os << "<rect x=\"" << x << "\" y=\"" << y
75            << "\" width=\"" << width << "\" height=\"" << height
76            << "\" style=\"" << style << "\"/>";
77     }
78 };
79
80
81 /*!
82 \brief Stream ranges as SVG
83 \note policy is used to select type (polyline/polygon)
84 */
85 template <typename Range, typename Policy>
86 struct svg_range
87 {
88     template <typename Char, typename Traits>
89     static inline void apply(std::basic_ostream<Char, Traits>& os,
90         Range const& range, std::string const& style, int )
91     {
92         typedef typename boost::range_iterator<Range const>::type iterator;
93
94         bool first = true;
95
96         os << "<" << Policy::prefix() << " points=\"";
97
98         for (iterator it = boost::begin(range);
99             it != boost::end(range);
100             ++it, first = false)
101         {
102             os << (first ? "" : " " )
103                 << geometry::get<0>(*it)
104                 << ","
105                 << geometry::get<1>(*it);
106         }
107         os << "\" style=\"" << style << Policy::style() << "\"/>";
108     }
109 };
110
111
112
113 template <typename Polygon>
114 struct svg_poly
115 {
116     template <typename Char, typename Traits>
117     static inline void apply(std::basic_ostream<Char, Traits>& os,
118         Polygon const& polygon, std::string const& style, int )
119     {
120         typedef typename geometry::ring_type<Polygon>::type ring_type;
121         typedef typename boost::range_iterator<ring_type const>::type iterator_type;
122
123         bool first = true;
124         os << "<g fill-rule=\"evenodd\"><path d=\"";
125
126         ring_type const& ring = geometry::exterior_ring(polygon);
127         for (iterator_type it = boost::begin(ring);
128             it != boost::end(ring);
129             ++it, first = false)
130         {
131             os << (first ? "M" : " L") << " "
132                 << geometry::get<0>(*it)
133                 << ","
134                 << geometry::get<1>(*it);
135         }
136
137         // Inner rings:
138         {
139             typename interior_return_type<Polygon const>::type
140                 rings = interior_rings(polygon);
141             for (typename detail::interior_iterator<Polygon const>::type
142                     rit = boost::begin(rings); rit != boost::end(rings); ++rit)
143             {
144                 first = true;
145                 for (typename detail::interior_ring_iterator<Polygon const>::type
146                         it = boost::begin(*rit); it != boost::end(*rit);
147                     ++it, first = false)
148                 {
149                     os << (first ? "M" : " L") << " "
150                         << geometry::get<0>(*it)
151                         << ","
152                         << geometry::get<1>(*it);
153                 }
154             }
155         }
156         os << " z \" style=\"" << style << "\"/></g>";
157
158     }
159 };
160
161
162
163 struct prefix_linestring
164 {
165     static inline const char* prefix() { return "polyline"; }
166     static inline const char* style() { return ";fill:none"; }
167 };
168
169
170 struct prefix_ring
171 {
172     static inline const char* prefix() { return "polygon"; }
173     static inline const char* style() { return ""; }
174 };
175
176
177
178 }} // namespace detail::svg
179 #endif // DOXYGEN_NO_DETAIL
180
181
182 #ifndef DOXYGEN_NO_DISPATCH
183 namespace dispatch
184 {
185
186 /*!
187 \brief Dispatching base struct for SVG streaming, specialized below per geometry type
188 \details Specializations should implement a static method "stream" to stream a geometry
189 The static method should have the signature:
190
191 template <typename Char, typename Traits>
192 static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry)
193 */
194 template <typename GeometryTag, typename Geometry>
195 struct svg
196 {
197     BOOST_MPL_ASSERT_MSG
198         (
199             false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
200             , (Geometry)
201         );
202 };
203
204 template <typename Point>
205 struct svg<point_tag, Point> : detail::svg::svg_point<Point> {};
206
207 template <typename Box>
208 struct svg<box_tag, Box> : detail::svg::svg_box<Box> {};
209
210 template <typename Linestring>
211 struct svg<linestring_tag, Linestring>
212     : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
213
214 template <typename Ring>
215 struct svg<ring_tag, Ring>
216     : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
217
218 template <typename Polygon>
219 struct svg<polygon_tag, Polygon>
220     : detail::svg::svg_poly<Polygon> {};
221
222 } // namespace dispatch
223 #endif // DOXYGEN_NO_DISPATCH
224
225
226 /*!
227 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
228 \ingroup svg
229 \details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics)
230 */
231 template <typename G>
232 class svg_manipulator
233 {
234 public:
235
236     inline svg_manipulator(G const& g, std::string const& style, int size)
237         : m_geometry(g)
238         , m_style(style)
239         , m_size(size)
240     {}
241
242     template <typename Char, typename Traits>
243     inline friend std::basic_ostream<Char, Traits>& operator<<(
244                     std::basic_ostream<Char, Traits>& os, svg_manipulator const& m)
245     {
246         dispatch::svg
247             <
248                 typename tag<G>::type, G
249             >::apply(os, m.m_geometry, m.m_style, m.m_size);
250         os.flush();
251         return os;
252     }
253
254 private:
255     G const& m_geometry;
256     std::string const& m_style;
257     int m_size;
258 };
259
260 /*!
261 \brief Manipulator to stream geometries as SVG
262 \tparam Geometry \tparam_geometry
263 \param geometry \param_geometry
264 \param style String containing verbatim SVG style information
265 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
266     specify linewidth in the SVG style information
267 \ingroup svg
268 */
269 template <typename Geometry>
270 inline svg_manipulator<Geometry> svg(Geometry const& geometry, std::string const& style, int size = -1)
271 {
272     concept::check<Geometry const>();
273
274     return svg_manipulator<Geometry>(geometry, style, size);
275 }
276
277 }} // namespace boost::geometry
278
279 #endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP