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