]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/svg/svg_mapper.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / geometry / io / svg / svg_mapper.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2015-2020.
6 // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
7 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9
10 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
11 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
12
13 // Use, modification and distribution is subject to the Boost Software License,
14 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
15 // http://www.boost.org/LICENSE_1_0.txt)
16
17 #ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
18 #define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
19
20 #include <cstdio>
21 #include <type_traits>
22 #include <vector>
23
24 #include <boost/algorithm/string/classification.hpp>
25 #include <boost/algorithm/string/split.hpp>
26 #include <boost/config.hpp>
27 #include <boost/noncopyable.hpp>
28 #include <boost/scoped_ptr.hpp>
29
30 #include <boost/geometry/core/static_assert.hpp>
31 #include <boost/geometry/core/tags.hpp>
32 #include <boost/geometry/core/tag_cast.hpp>
33 #include <boost/geometry/algorithms/envelope.hpp>
34 #include <boost/geometry/algorithms/expand.hpp>
35 #include <boost/geometry/algorithms/is_empty.hpp>
36 #include <boost/geometry/algorithms/transform.hpp>
37 #include <boost/geometry/strategies/transform/map_transformer.hpp>
38 #include <boost/geometry/views/segment_view.hpp>
39
40 #include <boost/geometry/io/svg/write.hpp>
41
42 // Helper geometries (all points are transformed to svg-points)
43 #include <boost/geometry/geometries/geometries.hpp>
44
45
46 namespace boost { namespace geometry
47 {
48
49
50 #ifndef DOXYGEN_NO_DISPATCH
51 namespace dispatch
52 {
53
54
55 template <typename GeometryTag, typename Geometry, typename SvgPoint>
56 struct svg_map
57 {
58 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
59 "Not or not yet implemented for this Geometry type.",
60 GeometryTag, Geometry);
61 };
62
63
64 template <typename Point, typename SvgPoint>
65 struct svg_map<point_tag, Point, SvgPoint>
66 {
67 template <typename TransformStrategy>
68 static inline void apply(std::ostream& stream,
69 std::string const& style, double size,
70 Point const& point, TransformStrategy const& strategy)
71 {
72 SvgPoint ipoint;
73 geometry::transform(point, ipoint, strategy);
74 stream << geometry::svg(ipoint, style, size) << std::endl;
75 }
76 };
77
78 template <typename BoxSeg1, typename BoxSeg2, typename SvgPoint>
79 struct svg_map_box_seg
80 {
81 template <typename TransformStrategy>
82 static inline void apply(std::ostream& stream,
83 std::string const& style, double size,
84 BoxSeg1 const& box_seg, TransformStrategy const& strategy)
85 {
86 BoxSeg2 ibox_seg;
87
88 // Fix bug in gcc compiler warning for possible uninitialization
89 #if defined(BOOST_GCC)
90 geometry::assign_zero(ibox_seg);
91 #endif
92 geometry::transform(box_seg, ibox_seg, strategy);
93
94 stream << geometry::svg(ibox_seg, style, size) << std::endl;
95 }
96 };
97
98 template <typename Box, typename SvgPoint>
99 struct svg_map<box_tag, Box, SvgPoint>
100 : svg_map_box_seg<Box, model::box<SvgPoint>, SvgPoint>
101 {};
102
103 template <typename Segment, typename SvgPoint>
104 struct svg_map<segment_tag, Segment, SvgPoint>
105 : svg_map_box_seg<Segment, model::segment<SvgPoint>, SvgPoint>
106 {};
107
108
109 template <typename Range1, typename Range2, typename SvgPoint>
110 struct svg_map_range
111 {
112 template <typename TransformStrategy>
113 static inline void apply(std::ostream& stream,
114 std::string const& style, double size,
115 Range1 const& range, TransformStrategy const& strategy)
116 {
117 Range2 irange;
118 geometry::transform(range, irange, strategy);
119 stream << geometry::svg(irange, style, size) << std::endl;
120 }
121 };
122
123 template <typename Ring, typename SvgPoint>
124 struct svg_map<ring_tag, Ring, SvgPoint>
125 : svg_map_range<Ring, model::ring<SvgPoint>, SvgPoint>
126 {};
127
128
129 template <typename Linestring, typename SvgPoint>
130 struct svg_map<linestring_tag, Linestring, SvgPoint>
131 : svg_map_range<Linestring, model::linestring<SvgPoint>, SvgPoint>
132 {};
133
134
135 template <typename Polygon, typename SvgPoint>
136 struct svg_map<polygon_tag, Polygon, SvgPoint>
137 {
138 template <typename TransformStrategy>
139 static inline void apply(std::ostream& stream,
140 std::string const& style, double size,
141 Polygon const& polygon, TransformStrategy const& strategy)
142 {
143 model::polygon<SvgPoint> ipoly;
144 geometry::transform(polygon, ipoly, strategy);
145 stream << geometry::svg(ipoly, style, size) << std::endl;
146 }
147 };
148
149
150 template <typename Multi, typename SvgPoint>
151 struct svg_map<multi_tag, Multi, SvgPoint>
152 {
153 typedef typename single_tag_of
154 <
155 typename geometry::tag<Multi>::type
156 >::type stag;
157
158 template <typename TransformStrategy>
159 static inline void apply(std::ostream& stream,
160 std::string const& style, double size,
161 Multi const& multi, TransformStrategy const& strategy)
162 {
163 for (typename boost::range_iterator<Multi const>::type it
164 = boost::begin(multi);
165 it != boost::end(multi);
166 ++it)
167 {
168 svg_map
169 <
170 stag,
171 typename boost::range_value<Multi>::type,
172 SvgPoint
173 >::apply(stream, style, size, *it, strategy);
174 }
175 }
176 };
177
178
179 template <typename SvgPoint, typename Geometry>
180 struct devarianted_svg_map
181 {
182 template <typename TransformStrategy>
183 static inline void apply(std::ostream& stream,
184 std::string const& style,
185 double size,
186 Geometry const& geometry,
187 TransformStrategy const& strategy)
188 {
189 svg_map
190 <
191 typename tag_cast
192 <
193 typename tag<Geometry>::type,
194 multi_tag
195 >::type,
196 typename std::remove_const<Geometry>::type,
197 SvgPoint
198 >::apply(stream, style, size, geometry, strategy);
199 }
200 };
201
202 template <typename SvgPoint, BOOST_VARIANT_ENUM_PARAMS(typename T)>
203 struct devarianted_svg_map<SvgPoint, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
204 {
205 template <typename TransformStrategy>
206 struct visitor: static_visitor<void>
207 {
208 std::ostream& m_os;
209 std::string const& m_style;
210 double m_size;
211 TransformStrategy const& m_strategy;
212
213 visitor(std::ostream& os,
214 std::string const& style,
215 double size,
216 TransformStrategy const& strategy)
217 : m_os(os)
218 , m_style(style)
219 , m_size(size)
220 , m_strategy(strategy)
221 {}
222
223 template <typename Geometry>
224 inline void operator()(Geometry const& geometry) const
225 {
226 devarianted_svg_map<SvgPoint, Geometry>::apply(m_os, m_style, m_size, geometry, m_strategy);
227 }
228 };
229
230 template <typename TransformStrategy>
231 static inline void apply(std::ostream& stream,
232 std::string const& style,
233 double size,
234 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
235 TransformStrategy const& strategy)
236 {
237 boost::apply_visitor(visitor<TransformStrategy>(stream, style, size, strategy), geometry);
238 }
239 };
240
241
242 } // namespace dispatch
243 #endif
244
245
246 template <typename SvgPoint, typename Geometry, typename TransformStrategy>
247 inline void svg_map(std::ostream& stream,
248 std::string const& style, double size,
249 Geometry const& geometry, TransformStrategy const& strategy)
250 {
251 dispatch::devarianted_svg_map<SvgPoint, Geometry>::apply(stream,
252 style, size, geometry, strategy);
253 }
254
255
256 /*!
257 \brief Helper class to create SVG maps
258 \tparam Point Point type, for input geometries.
259 \tparam SameScale Boolean flag indicating if horizontal and vertical scale should
260 be the same. The default value is true
261 \tparam SvgCoordinateType Coordinate type of SVG points. SVG is capable to
262 use floating point coordinates. Therefore the default value is double
263 \ingroup svg
264
265 \qbk{[include reference/io/svg.qbk]}
266 */
267 template
268 <
269 typename Point,
270 bool SameScale = true,
271 typename SvgCoordinateType = double
272 >
273 class svg_mapper : boost::noncopyable
274 {
275 typedef model::point<SvgCoordinateType, 2, cs::cartesian> svg_point_type;
276
277 typedef typename geometry::select_most_precise
278 <
279 typename coordinate_type<Point>::type,
280 double
281 >::type calculation_type;
282
283 typedef strategy::transform::map_transformer
284 <
285 calculation_type,
286 geometry::dimension<Point>::type::value,
287 geometry::dimension<Point>::type::value,
288 true,
289 SameScale
290 > transformer_type;
291
292 model::box<Point> m_bounding_box;
293 boost::scoped_ptr<transformer_type> m_matrix;
294 std::ostream& m_stream;
295 SvgCoordinateType m_width, m_height;
296 std::string m_width_height; // for <svg> tag only, defaults to 2x 100%
297
298 void init_matrix()
299 {
300 if (! m_matrix)
301 {
302 m_matrix.reset(new transformer_type(m_bounding_box,
303 m_width, m_height));
304
305
306 m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
307 << std::endl
308 << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
309 << std::endl
310 << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
311 << std::endl
312 << "<svg " << m_width_height << " version=\"1.1\""
313 << std::endl
314 << "xmlns=\"http://www.w3.org/2000/svg\""
315 << std::endl
316 << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
317 << ">"
318 << std::endl;
319 }
320 }
321
322 public :
323
324 /*!
325 \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
326 Should be called explicitly.
327 \param stream Output stream, should be a stream already open
328 \param width Width of the SVG map (in SVG pixels)
329 \param height Height of the SVG map (in SVG pixels)
330 \param width_height Optional information to increase width and/or height
331 */
332 svg_mapper(std::ostream& stream
333 , SvgCoordinateType width
334 , SvgCoordinateType height
335 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
336 : m_stream(stream)
337 , m_width(width)
338 , m_height(height)
339 , m_width_height(width_height)
340 {
341 assign_inverse(m_bounding_box);
342 }
343
344 /*!
345 \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
346 */
347 virtual ~svg_mapper()
348 {
349 m_stream << "</svg>" << std::endl;
350 }
351
352 /*!
353 \brief Adds a geometry to the transformation matrix. After doing this,
354 the specified geometry can be mapped fully into the SVG map
355 \tparam Geometry \tparam_geometry
356 \param geometry \param_geometry
357 */
358 template <typename Geometry>
359 void add(Geometry const& geometry)
360 {
361 if (! geometry::is_empty(geometry))
362 {
363 expand(m_bounding_box,
364 return_envelope
365 <
366 model::box<Point>
367 >(geometry));
368 }
369 }
370
371 /*!
372 \brief Maps a geometry into the SVG map using the specified style
373 \tparam Geometry \tparam_geometry
374 \param geometry \param_geometry
375 \param style String containing verbatim SVG style information
376 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
377 specify linewidth in the SVG style information
378 */
379 template <typename Geometry>
380 void map(Geometry const& geometry, std::string const& style,
381 double size = -1.0)
382 {
383 init_matrix();
384 svg_map<svg_point_type>(m_stream, style, size, geometry, *m_matrix);
385 }
386
387 /*!
388 \brief Adds a text to the SVG map
389 \tparam TextPoint \tparam_point
390 \param point Location of the text (in map units)
391 \param s The text itself
392 \param style String containing verbatim SVG style information, of the text
393 \param offset_x Offset in SVG pixels, defaults to 0
394 \param offset_y Offset in SVG pixels, defaults to 0
395 \param lineheight Line height in SVG pixels, in case the text contains \n
396 */
397 template <typename TextPoint>
398 void text(TextPoint const& point, std::string const& s,
399 std::string const& style,
400 double offset_x = 0.0, double offset_y = 0.0,
401 double lineheight = 10.0)
402 {
403 init_matrix();
404 svg_point_type map_point;
405 transform(point, map_point, *m_matrix);
406 m_stream
407 << "<text style=\"" << style << "\""
408 << " x=\"" << get<0>(map_point) + offset_x << "\""
409 << " y=\"" << get<1>(map_point) + offset_y << "\""
410 << ">";
411 if (s.find("\n") == std::string::npos)
412 {
413 m_stream << s;
414 }
415 else
416 {
417 // Multi-line modus
418
419 std::vector<std::string> splitted;
420 boost::split(splitted, s, boost::is_any_of("\n"));
421 for (std::vector<std::string>::const_iterator it
422 = splitted.begin();
423 it != splitted.end();
424 ++it, offset_y += lineheight)
425 {
426 m_stream
427 << "<tspan x=\"" << get<0>(map_point) + offset_x
428 << "\""
429 << " y=\"" << get<1>(map_point) + offset_y
430 << "\""
431 << ">" << *it << "</tspan>";
432 }
433 }
434 m_stream << "</text>" << std::endl;
435 }
436 };
437
438
439 }} // namespace boost::geometry
440
441
442 #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP