]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/svg/write.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / geometry / io / svg / write.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 // This file was modified by Oracle on 2016-2020.
7 // Modifications copyright (c) 2016-2020, Oracle and/or its affiliates.
8
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
13
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)
17
18 #ifndef BOOST_GEOMETRY_IO_SVG_WRITE_HPP
19 #define BOOST_GEOMETRY_IO_SVG_WRITE_HPP
20
21 #include <ostream>
22 #include <string>
23
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>
31
32 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
33
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>
38
39 #include <boost/geometry/geometries/concepts/check.hpp>
40
41
42 namespace boost { namespace geometry
43 {
44
45
46 #ifndef DOXYGEN_NO_DETAIL
47 namespace detail { namespace svg
48 {
49
50
51 template <typename Point>
52 struct svg_point
53 {
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)
57 {
58 os << "<circle cx=\"" << geometry::get<0>(p)
59 << "\" cy=\"" << geometry::get<1>(p)
60 << "\" r=\"" << (size < 0 ? 5 : size)
61 << "\" style=\"" << style << "\"/>";
62 }
63 };
64
65
66 template <typename Box>
67 struct svg_box
68 {
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)
72 {
73 // Prevent invisible boxes, making them >=1, using "max"
74 BOOST_USING_STD_MAX();
75
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);
83
84 os << "<rect x=\"" << x << "\" y=\"" << y
85 << "\" width=\"" << width << "\" height=\"" << height
86 << "\" style=\"" << style << "\"/>";
87 }
88 };
89
90 template <typename Segment>
91 struct svg_segment
92 {
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)
96 {
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);
102
103 os << "<line x1=\"" << x1 << "\" y1=\"" << y1
104 << "\" x2=\"" << x2 << "\" y2=\"" << y2
105 << "\" style=\"" << style << "\"/>";
106 }
107 };
108
109 /*!
110 \brief Stream ranges as SVG
111 \note policy is used to select type (polyline/polygon)
112 */
113 template <typename Range, typename Policy>
114 struct svg_range
115 {
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)
119 {
120 typedef typename boost::range_iterator<Range const>::type iterator;
121
122 bool first = true;
123
124 os << "<" << Policy::prefix() << " points=\"";
125
126 for (iterator it = boost::begin(range);
127 it != boost::end(range);
128 ++it, first = false)
129 {
130 os << (first ? "" : " " )
131 << geometry::get<0>(*it)
132 << ","
133 << geometry::get<1>(*it);
134 }
135 os << "\" style=\"" << style << Policy::style() << "\"/>";
136 }
137 };
138
139
140
141 template <typename Polygon>
142 struct svg_poly
143 {
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)
147 {
148 typedef typename geometry::ring_type<Polygon>::type ring_type;
149 typedef typename boost::range_iterator<ring_type const>::type iterator_type;
150
151 bool first = true;
152 os << "<g fill-rule=\"evenodd\"><path d=\"";
153
154 ring_type const& ring = geometry::exterior_ring(polygon);
155 for (iterator_type it = boost::begin(ring);
156 it != boost::end(ring);
157 ++it, first = false)
158 {
159 os << (first ? "M" : " L") << " "
160 << geometry::get<0>(*it)
161 << ","
162 << geometry::get<1>(*it);
163 }
164
165 // Inner rings:
166 {
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)
171 {
172 first = true;
173 for (typename detail::interior_ring_iterator<Polygon const>::type
174 it = boost::begin(*rit); it != boost::end(*rit);
175 ++it, first = false)
176 {
177 os << (first ? "M" : " L") << " "
178 << geometry::get<0>(*it)
179 << ","
180 << geometry::get<1>(*it);
181 }
182 }
183 }
184 os << " z \" style=\"" << style << "\"/></g>";
185
186 }
187 };
188
189
190
191 struct prefix_linestring
192 {
193 static inline const char* prefix() { return "polyline"; }
194 static inline const char* style() { return ";fill:none"; }
195 };
196
197
198 struct prefix_ring
199 {
200 static inline const char* prefix() { return "polygon"; }
201 static inline const char* style() { return ""; }
202 };
203
204
205 template <typename MultiGeometry, typename Policy>
206 struct svg_multi
207 {
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)
211 {
212 for (typename boost::range_iterator<MultiGeometry const>::type
213 it = boost::begin(multi);
214 it != boost::end(multi);
215 ++it)
216 {
217 Policy::apply(os, *it, style, size);
218 }
219
220 }
221
222 };
223
224
225 }} // namespace detail::svg
226 #endif // DOXYGEN_NO_DETAIL
227
228
229 #ifndef DOXYGEN_NO_DISPATCH
230 namespace dispatch
231 {
232
233 /*!
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:
237
238 template <typename Char, typename Traits>
239 static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry)
240 */
241 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
242 struct svg
243 {
244 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
245 "Not or not yet implemented for this Geometry type.",
246 Geometry, Tag);
247 };
248
249 template <typename Point>
250 struct svg<Point, point_tag> : detail::svg::svg_point<Point> {};
251
252 template <typename Segment>
253 struct svg<Segment, segment_tag> : detail::svg::svg_segment<Segment> {};
254
255 template <typename Box>
256 struct svg<Box, box_tag> : detail::svg::svg_box<Box> {};
257
258 template <typename Linestring>
259 struct svg<Linestring, linestring_tag>
260 : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
261
262 template <typename Ring>
263 struct svg<Ring, ring_tag>
264 : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
265
266 template <typename Polygon>
267 struct svg<Polygon, polygon_tag>
268 : detail::svg::svg_poly<Polygon> {};
269
270 template <typename MultiPoint>
271 struct svg<MultiPoint, multi_point_tag>
272 : detail::svg::svg_multi
273 <
274 MultiPoint,
275 detail::svg::svg_point
276 <
277 typename boost::range_value<MultiPoint>::type
278 >
279
280 >
281 {};
282
283 template <typename MultiLinestring>
284 struct svg<MultiLinestring, multi_linestring_tag>
285 : detail::svg::svg_multi
286 <
287 MultiLinestring,
288 detail::svg::svg_range
289 <
290 typename boost::range_value<MultiLinestring>::type,
291 detail::svg::prefix_linestring
292 >
293
294 >
295 {};
296
297 template <typename MultiPolygon>
298 struct svg<MultiPolygon, multi_polygon_tag>
299 : detail::svg::svg_multi
300 <
301 MultiPolygon,
302 detail::svg::svg_poly
303 <
304 typename boost::range_value<MultiPolygon>::type
305 >
306
307 >
308 {};
309
310
311 template <typename Geometry>
312 struct devarianted_svg
313 {
314 template <typename OutputStream>
315 static inline void apply(OutputStream& os,
316 Geometry const& geometry,
317 std::string const& style,
318 double size)
319 {
320 svg<Geometry>::apply(os, geometry, style, size);
321 }
322 };
323
324 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
325 struct devarianted_svg<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
326 {
327 template <typename OutputStream>
328 struct visitor: static_visitor<void>
329 {
330 OutputStream& m_os;
331 std::string const& m_style;
332 double m_size;
333
334 visitor(OutputStream& os, std::string const& style, double size)
335 : m_os(os)
336 , m_style(style)
337 , m_size(size)
338 {}
339
340 template <typename Geometry>
341 inline void operator()(Geometry const& geometry) const
342 {
343 devarianted_svg<Geometry>::apply(m_os, geometry, m_style, m_size);
344 }
345 };
346
347 template <typename OutputStream>
348 static inline void apply(
349 OutputStream& os,
350 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
351 std::string const& style,
352 double size
353 )
354 {
355 boost::apply_visitor(visitor<OutputStream>(os, style, size), geometry);
356 }
357 };
358
359 } // namespace dispatch
360 #endif // DOXYGEN_NO_DISPATCH
361
362
363 /*!
364 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
365 \ingroup svg
366 \details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics)
367 */
368 template <typename Geometry>
369 class svg_manipulator
370 {
371 public:
372
373 inline svg_manipulator(Geometry const& g, std::string const& style, double size)
374 : m_geometry(g)
375 , m_style(style)
376 , m_size(size)
377 {}
378
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)
382 {
383 dispatch::devarianted_svg<Geometry>::apply(os,
384 m.m_geometry,
385 m.m_style,
386 m.m_size);
387 os.flush();
388 return os;
389 }
390
391 private:
392 Geometry const& m_geometry;
393 std::string const& m_style;
394 double m_size;
395 };
396
397 /*!
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
404 \ingroup svg
405 */
406 template <typename Geometry>
407 inline svg_manipulator<Geometry> svg(Geometry const& geometry,
408 std::string const& style, double size = -1.0)
409 {
410 concepts::check<Geometry const>();
411
412 return svg_manipulator<Geometry>(geometry, style, size);
413 }
414
415 }} // namespace boost::geometry
416
417 #endif // BOOST_GEOMETRY_IO_SVG_WRITE_HPP