• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
applyboost::geometry::detail::svg::svg_point54     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>
applyboost::geometry::detail::svg::svg_box69     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>
applyboost::geometry::detail::svg::svg_segment93     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>
applyboost::geometry::detail::svg::svg_range116     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>
applyboost::geometry::detail::svg::svg_poly144     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 {
prefixboost::geometry::detail::svg::prefix_linestring192     static inline const char* prefix() { return "polyline"; }
styleboost::geometry::detail::svg::prefix_linestring193     static inline const char* style() { return ";fill:none"; }
194 };
195 
196 
197 struct prefix_ring
198 {
prefixboost::geometry::detail::svg::prefix_ring199     static inline const char* prefix() { return "polygon"; }
styleboost::geometry::detail::svg::prefix_ring200     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>
applyboost::geometry::detail::svg::svg_multi208     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>
applyboost::geometry::dispatch::devarianted_svg316     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 
visitorboost::geometry::dispatch::devarianted_svg::visitor335         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>
operator ()boost::geometry::dispatch::devarianted_svg::visitor342         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>
applyboost::geometry::dispatch::devarianted_svg349     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 
svg_manipulator(Geometry const & g,std::string const & style,double size)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>
operator <<(std::basic_ostream<Char,Traits> & os,svg_manipulator const & m)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>
svg(Geometry const & geometry,std::string const & style,double size=-1.0)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
419