]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/io/svg/svg_mapper.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / geometry / io / svg / svg_mapper.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
4
1e59de90 5// This file was modified by Oracle on 2015-2021.
20effc67 6// Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
7c673cae
FG
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>
20effc67 21#include <type_traits>
7c673cae
FG
22#include <vector>
23
20effc67
TL
24#include <boost/algorithm/string/classification.hpp>
25#include <boost/algorithm/string/split.hpp>
7c673cae 26#include <boost/config.hpp>
7c673cae
FG
27#include <boost/noncopyable.hpp>
28#include <boost/scoped_ptr.hpp>
7c673cae 29
20effc67 30#include <boost/geometry/core/static_assert.hpp>
7c673cae
FG
31#include <boost/geometry/core/tags.hpp>
32#include <boost/geometry/core/tag_cast.hpp>
7c673cae
FG
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
46namespace boost { namespace geometry
47{
48
49
50#ifndef DOXYGEN_NO_DISPATCH
51namespace dispatch
52{
53
54
55template <typename GeometryTag, typename Geometry, typename SvgPoint>
56struct svg_map
57{
20effc67
TL
58 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
59 "Not or not yet implemented for this Geometry type.",
60 GeometryTag, Geometry);
7c673cae
FG
61};
62
63
64template <typename Point, typename SvgPoint>
65struct 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
78template <typename BoxSeg1, typename BoxSeg2, typename SvgPoint>
79struct 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
98template <typename Box, typename SvgPoint>
99struct svg_map<box_tag, Box, SvgPoint>
100 : svg_map_box_seg<Box, model::box<SvgPoint>, SvgPoint>
101{};
102
103template <typename Segment, typename SvgPoint>
104struct svg_map<segment_tag, Segment, SvgPoint>
105 : svg_map_box_seg<Segment, model::segment<SvgPoint>, SvgPoint>
106{};
107
108
109template <typename Range1, typename Range2, typename SvgPoint>
110struct 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
123template <typename Ring, typename SvgPoint>
124struct svg_map<ring_tag, Ring, SvgPoint>
125 : svg_map_range<Ring, model::ring<SvgPoint>, SvgPoint>
126{};
127
128
129template <typename Linestring, typename SvgPoint>
130struct svg_map<linestring_tag, Linestring, SvgPoint>
131 : svg_map_range<Linestring, model::linestring<SvgPoint>, SvgPoint>
132{};
133
134
135template <typename Polygon, typename SvgPoint>
136struct 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
150template <typename Multi, typename SvgPoint>
151struct 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
179template <typename SvgPoint, typename Geometry>
180struct 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,
20effc67 196 typename std::remove_const<Geometry>::type,
7c673cae
FG
197 SvgPoint
198 >::apply(stream, style, size, geometry, strategy);
199 }
200};
201
202template <typename SvgPoint, BOOST_VARIANT_ENUM_PARAMS(typename T)>
203struct 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
246template <typename SvgPoint, typename Geometry, typename TransformStrategy>
247inline 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*/
267template
268<
269 typename Point,
270 bool SameScale = true,
271 typename SvgCoordinateType = double
272>
273class 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;
1e59de90
TL
295
296 SvgCoordinateType const m_width;
297 SvgCoordinateType const m_height;
298 calculation_type const m_scale{1.0};
299
300 void scale_bounding_box()
301 {
302 if (m_scale != 1.0 && m_scale > 0)
303 {
304 // Zoom out (scale < 1) or zoom in (scale > 1).
305 // The default is 0.95, giving a small margin around geometries.
306 auto& b = m_bounding_box;
307 auto const w = geometry::get<1, 0>(b) - geometry::get<0, 0>(b);
308 auto const h = geometry::get<1, 1>(b) - geometry::get<0, 1>(b);
309
310 auto const& m = (std::max)(w, h) * (1.0 - m_scale);
311 geometry::set<0, 0>(b, geometry::get<0, 0>(b) - m);
312 geometry::set<0, 1>(b, geometry::get<0, 1>(b) - m);
313 geometry::set<1, 0>(b, geometry::get<1, 0>(b) + m);
314 geometry::set<1, 1>(b, geometry::get<1, 1>(b) + m);
315 }
316 }
7c673cae
FG
317
318 void init_matrix()
319 {
320 if (! m_matrix)
321 {
1e59de90 322 scale_bounding_box();
7c673cae
FG
323 m_matrix.reset(new transformer_type(m_bounding_box,
324 m_width, m_height));
7c673cae
FG
325 }
326 }
327
1e59de90
TL
328 void write_header(std::string const& width_height)
329 {
330 m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
331 << std::endl
332 << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
333 << std::endl
334 << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
335 << std::endl
336 << "<svg " << width_height << " version=\"1.1\""
337 << std::endl
338 << "xmlns=\"http://www.w3.org/2000/svg\""
339 << std::endl
340 << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
341 << ">"
342 << std::endl;
343 }
344
7c673cae
FG
345public :
346
347 /*!
1e59de90
TL
348 \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
349 Should be called explicitly.
350 \param stream Output stream, should be a stream already open
351 \param width Width of the SVG map (in SVG pixels)
352 \param height Height of the SVG map (in SVG pixels)
353 \param scale Scale factor of the automatically determined bounding box.
354 If the factor is less than 1.0, there will be a margin around the
355 geometries. A factor of 0.95 is often a convenient margin. If the
356 factor is more than 1.0, the SVG map is zoomed and not all
357 geometries will be visible.
358 \param width_height Optional information to increase width and/or height
359 */
360 svg_mapper(std::ostream& stream
361 , SvgCoordinateType width
362 , SvgCoordinateType height
363 , calculation_type scale
364 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
365 : m_stream(stream)
366 , m_width(width)
367 , m_height(height)
368 , m_scale(scale)
369 {
370 assign_inverse(m_bounding_box);
371 write_header(width_height);
372 }
373
374 /*!
375 \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
7c673cae
FG
376 Should be called explicitly.
377 \param stream Output stream, should be a stream already open
378 \param width Width of the SVG map (in SVG pixels)
379 \param height Height of the SVG map (in SVG pixels)
380 \param width_height Optional information to increase width and/or height
381 */
382 svg_mapper(std::ostream& stream
383 , SvgCoordinateType width
384 , SvgCoordinateType height
385 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
386 : m_stream(stream)
387 , m_width(width)
388 , m_height(height)
7c673cae
FG
389 {
390 assign_inverse(m_bounding_box);
1e59de90 391 write_header(width_height);
7c673cae
FG
392 }
393
394 /*!
395 \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
396 */
397 virtual ~svg_mapper()
398 {
399 m_stream << "</svg>" << std::endl;
400 }
401
402 /*!
403 \brief Adds a geometry to the transformation matrix. After doing this,
404 the specified geometry can be mapped fully into the SVG map
405 \tparam Geometry \tparam_geometry
406 \param geometry \param_geometry
407 */
408 template <typename Geometry>
409 void add(Geometry const& geometry)
410 {
411 if (! geometry::is_empty(geometry))
412 {
413 expand(m_bounding_box,
414 return_envelope
415 <
416 model::box<Point>
417 >(geometry));
418 }
419 }
420
421 /*!
422 \brief Maps a geometry into the SVG map using the specified style
423 \tparam Geometry \tparam_geometry
424 \param geometry \param_geometry
425 \param style String containing verbatim SVG style information
426 \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
427 specify linewidth in the SVG style information
428 */
429 template <typename Geometry>
430 void map(Geometry const& geometry, std::string const& style,
431 double size = -1.0)
432 {
433 init_matrix();
434 svg_map<svg_point_type>(m_stream, style, size, geometry, *m_matrix);
435 }
436
437 /*!
438 \brief Adds a text to the SVG map
439 \tparam TextPoint \tparam_point
440 \param point Location of the text (in map units)
441 \param s The text itself
442 \param style String containing verbatim SVG style information, of the text
443 \param offset_x Offset in SVG pixels, defaults to 0
444 \param offset_y Offset in SVG pixels, defaults to 0
445 \param lineheight Line height in SVG pixels, in case the text contains \n
446 */
447 template <typename TextPoint>
448 void text(TextPoint const& point, std::string const& s,
449 std::string const& style,
450 double offset_x = 0.0, double offset_y = 0.0,
451 double lineheight = 10.0)
452 {
453 init_matrix();
454 svg_point_type map_point;
455 transform(point, map_point, *m_matrix);
456 m_stream
457 << "<text style=\"" << style << "\""
458 << " x=\"" << get<0>(map_point) + offset_x << "\""
459 << " y=\"" << get<1>(map_point) + offset_y << "\""
460 << ">";
461 if (s.find("\n") == std::string::npos)
462 {
463 m_stream << s;
464 }
465 else
466 {
467 // Multi-line modus
468
469 std::vector<std::string> splitted;
470 boost::split(splitted, s, boost::is_any_of("\n"));
471 for (std::vector<std::string>::const_iterator it
472 = splitted.begin();
473 it != splitted.end();
474 ++it, offset_y += lineheight)
475 {
476 m_stream
477 << "<tspan x=\"" << get<0>(map_point) + offset_x
478 << "\""
479 << " y=\"" << get<1>(map_point) + offset_y
480 << "\""
481 << ">" << *it << "</tspan>";
482 }
483 }
484 m_stream << "</text>" << std::endl;
485 }
486};
487
488
489}} // namespace boost::geometry
490
491
492#endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP