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