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