svg_mapper.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  4. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
  9. #define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
  10. #include <cstdio>
  11. #include <vector>
  12. #include <boost/mpl/assert.hpp>
  13. #include <boost/noncopyable.hpp>
  14. #include <boost/scoped_ptr.hpp>
  15. #include <boost/type_traits/is_same.hpp>
  16. #include <boost/type_traits/remove_const.hpp>
  17. #include <boost/algorithm/string/split.hpp>
  18. #include <boost/algorithm/string/classification.hpp>
  19. #include <boost/geometry/core/tags.hpp>
  20. #include <boost/geometry/core/tag_cast.hpp>
  21. #include <boost/geometry/algorithms/envelope.hpp>
  22. #include <boost/geometry/algorithms/expand.hpp>
  23. #include <boost/geometry/algorithms/transform.hpp>
  24. #include <boost/geometry/algorithms/num_points.hpp>
  25. #include <boost/geometry/strategies/transform.hpp>
  26. #include <boost/geometry/strategies/transform/map_transformer.hpp>
  27. #include <boost/geometry/views/segment_view.hpp>
  28. #include <boost/geometry/multi/core/tags.hpp>
  29. #include <boost/geometry/multi/algorithms/envelope.hpp>
  30. #include <boost/geometry/multi/algorithms/num_points.hpp>
  31. #include <boost/geometry/io/svg/write_svg.hpp>
  32. // Helper geometries (all points are transformed to integer-points)
  33. #include <boost/geometry/geometries/geometries.hpp>
  34. namespace boost { namespace geometry
  35. {
  36. #ifndef DOXYGEN_NO_DETAIL
  37. namespace detail { namespace svg
  38. {
  39. typedef model::point<int, 2, cs::cartesian> svg_point_type;
  40. }}
  41. #endif
  42. #ifndef DOXYGEN_NO_DISPATCH
  43. namespace dispatch
  44. {
  45. template <typename GeometryTag, typename Geometry>
  46. struct svg_map
  47. {
  48. BOOST_MPL_ASSERT_MSG
  49. (
  50. false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
  51. , (Geometry)
  52. );
  53. };
  54. template <typename Point>
  55. struct svg_map<point_tag, Point>
  56. {
  57. template <typename TransformStrategy>
  58. static inline void apply(std::ostream& stream,
  59. std::string const& style, int size,
  60. Point const& point, TransformStrategy const& strategy)
  61. {
  62. detail::svg::svg_point_type ipoint;
  63. geometry::transform(point, ipoint, strategy);
  64. stream << geometry::svg(ipoint, style, size) << std::endl;
  65. }
  66. };
  67. template <typename Box>
  68. struct svg_map<box_tag, Box>
  69. {
  70. template <typename TransformStrategy>
  71. static inline void apply(std::ostream& stream,
  72. std::string const& style, int size,
  73. Box const& box, TransformStrategy const& strategy)
  74. {
  75. model::box<detail::svg::svg_point_type> ibox;
  76. geometry::transform(box, ibox, strategy);
  77. stream << geometry::svg(ibox, style, size) << std::endl;
  78. }
  79. };
  80. template <typename Range1, typename Range2>
  81. struct svg_map_range
  82. {
  83. template <typename TransformStrategy>
  84. static inline void apply(std::ostream& stream,
  85. std::string const& style, int size,
  86. Range1 const& range, TransformStrategy const& strategy)
  87. {
  88. Range2 irange;
  89. geometry::transform(range, irange, strategy);
  90. stream << geometry::svg(irange, style, size) << std::endl;
  91. }
  92. };
  93. template <typename Segment>
  94. struct svg_map<segment_tag, Segment>
  95. {
  96. template <typename TransformStrategy>
  97. static inline void apply(std::ostream& stream,
  98. std::string const& style, int size,
  99. Segment const& segment, TransformStrategy const& strategy)
  100. {
  101. typedef segment_view<Segment> view_type;
  102. view_type range(segment);
  103. svg_map_range
  104. <
  105. view_type,
  106. model::linestring<detail::svg::svg_point_type>
  107. >::apply(stream, style, size, range, strategy);
  108. }
  109. };
  110. template <typename Ring>
  111. struct svg_map<ring_tag, Ring>
  112. : svg_map_range<Ring, model::ring<detail::svg::svg_point_type> >
  113. {};
  114. template <typename Linestring>
  115. struct svg_map<linestring_tag, Linestring>
  116. : svg_map_range<Linestring, model::linestring<detail::svg::svg_point_type> >
  117. {};
  118. template <typename Polygon>
  119. struct svg_map<polygon_tag, Polygon>
  120. {
  121. template <typename TransformStrategy>
  122. static inline void apply(std::ostream& stream,
  123. std::string const& style, int size,
  124. Polygon const& polygon, TransformStrategy const& strategy)
  125. {
  126. model::polygon<detail::svg::svg_point_type> ipoly;
  127. geometry::transform(polygon, ipoly, strategy);
  128. stream << geometry::svg(ipoly, style, size) << std::endl;
  129. }
  130. };
  131. template <typename Multi>
  132. struct svg_map<multi_tag, Multi>
  133. {
  134. typedef typename single_tag_of
  135. <
  136. typename geometry::tag<Multi>::type
  137. >::type stag;
  138. template <typename TransformStrategy>
  139. static inline void apply(std::ostream& stream,
  140. std::string const& style, int size,
  141. Multi const& multi, TransformStrategy const& strategy)
  142. {
  143. for (typename boost::range_iterator<Multi const>::type it
  144. = boost::begin(multi);
  145. it != boost::end(multi);
  146. ++it)
  147. {
  148. svg_map
  149. <
  150. stag,
  151. typename boost::range_value<Multi>::type
  152. >::apply(stream, style, size, *it, strategy);
  153. }
  154. }
  155. };
  156. } // namespace dispatch
  157. #endif
  158. template <typename Geometry, typename TransformStrategy>
  159. inline void svg_map(std::ostream& stream,
  160. std::string const& style, int size,
  161. Geometry const& geometry, TransformStrategy const& strategy)
  162. {
  163. dispatch::svg_map
  164. <
  165. typename tag_cast
  166. <
  167. typename tag<Geometry>::type,
  168. multi_tag
  169. >::type,
  170. typename boost::remove_const<Geometry>::type
  171. >::apply(stream, style, size, geometry, strategy);
  172. }
  173. /*!
  174. \brief Helper class to create SVG maps
  175. \tparam Point Point type, for input geometries.
  176. \tparam SameScale Boolean flag indicating if horizontal and vertical scale should
  177. be the same. The default value is true
  178. \ingroup svg
  179. \qbk{[include reference/io/svg.qbk]}
  180. */
  181. template <typename Point, bool SameScale = true>
  182. class svg_mapper : boost::noncopyable
  183. {
  184. typedef typename geometry::select_most_precise
  185. <
  186. typename coordinate_type<Point>::type,
  187. double
  188. >::type calculation_type;
  189. typedef strategy::transform::map_transformer
  190. <
  191. calculation_type,
  192. geometry::dimension<Point>::type::value,
  193. geometry::dimension<Point>::type::value,
  194. true,
  195. SameScale
  196. > transformer_type;
  197. model::box<Point> m_bounding_box;
  198. boost::scoped_ptr<transformer_type> m_matrix;
  199. std::ostream& m_stream;
  200. int m_width, m_height;
  201. std::string m_width_height; // for <svg> tag only, defaults to 2x 100%
  202. void init_matrix()
  203. {
  204. if (! m_matrix)
  205. {
  206. m_matrix.reset(new transformer_type(m_bounding_box,
  207. m_width, m_height));
  208. m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
  209. << std::endl
  210. << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
  211. << std::endl
  212. << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
  213. << std::endl
  214. << "<svg " << m_width_height << " version=\"1.1\""
  215. << std::endl
  216. << "xmlns=\"http://www.w3.org/2000/svg\""
  217. << std::endl
  218. << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
  219. << ">"
  220. << std::endl;
  221. }
  222. }
  223. public :
  224. /*!
  225. \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
  226. Should be called explicitly.
  227. \param stream Output stream, should be a stream already open
  228. \param width Width of the SVG map (in SVG pixels)
  229. \param height Height of the SVG map (in SVG pixels)
  230. \param width_height Optional information to increase width and/or height
  231. */
  232. explicit svg_mapper(std::ostream& stream, int width, int height
  233. , std::string const& width_height = "width=\"100%\" height=\"100%\"")
  234. : m_stream(stream)
  235. , m_width(width)
  236. , m_height(height)
  237. , m_width_height(width_height)
  238. {
  239. assign_inverse(m_bounding_box);
  240. }
  241. /*!
  242. \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
  243. */
  244. virtual ~svg_mapper()
  245. {
  246. m_stream << "</svg>" << std::endl;
  247. }
  248. /*!
  249. \brief Adds a geometry to the transformation matrix. After doing this,
  250. the specified geometry can be mapped fully into the SVG map
  251. \tparam Geometry \tparam_geometry
  252. \param geometry \param_geometry
  253. */
  254. template <typename Geometry>
  255. void add(Geometry const& geometry)
  256. {
  257. if (num_points(geometry) > 0)
  258. {
  259. expand(m_bounding_box,
  260. return_envelope
  261. <
  262. model::box<Point>
  263. >(geometry));
  264. }
  265. }
  266. /*!
  267. \brief Maps a geometry into the SVG map using the specified style
  268. \tparam Geometry \tparam_geometry
  269. \param geometry \param_geometry
  270. \param style String containing verbatim SVG style information
  271. \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
  272. specify linewidth in the SVG style information
  273. */
  274. template <typename Geometry>
  275. void map(Geometry const& geometry, std::string const& style,
  276. int size = -1)
  277. {
  278. init_matrix();
  279. svg_map(m_stream, style, size, geometry, *m_matrix);
  280. }
  281. /*!
  282. \brief Adds a text to the SVG map
  283. \tparam TextPoint \tparam_point
  284. \param point Location of the text (in map units)
  285. \param s The text itself
  286. \param style String containing verbatim SVG style information, of the text
  287. \param offset_x Offset in SVG pixels, defaults to 0
  288. \param offset_y Offset in SVG pixels, defaults to 0
  289. \param lineheight Line height in SVG pixels, in case the text contains \n
  290. */
  291. template <typename TextPoint>
  292. void text(TextPoint const& point, std::string const& s,
  293. std::string const& style,
  294. int offset_x = 0, int offset_y = 0, int lineheight = 10)
  295. {
  296. init_matrix();
  297. detail::svg::svg_point_type map_point;
  298. transform(point, map_point, *m_matrix);
  299. m_stream
  300. << "<text style=\"" << style << "\""
  301. << " x=\"" << get<0>(map_point) + offset_x << "\""
  302. << " y=\"" << get<1>(map_point) + offset_y << "\""
  303. << ">";
  304. if (s.find("\n") == std::string::npos)
  305. {
  306. m_stream << s;
  307. }
  308. else
  309. {
  310. // Multi-line modus
  311. std::vector<std::string> splitted;
  312. boost::split(splitted, s, boost::is_any_of("\n"));
  313. for (std::vector<std::string>::const_iterator it
  314. = splitted.begin();
  315. it != splitted.end();
  316. ++it, offset_y += lineheight)
  317. {
  318. m_stream
  319. << "<tspan x=\"" << get<0>(map_point) + offset_x
  320. << "\""
  321. << " y=\"" << get<1>(map_point) + offset_y
  322. << "\""
  323. << ">" << *it << "</tspan>";
  324. }
  325. }
  326. m_stream << "</text>" << std::endl;
  327. }
  328. };
  329. }} // namespace boost::geometry
  330. #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP