File indexing completed on 2025-01-18 09:35:35
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
0019 #define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
0020
0021 #include <cstdio>
0022 #include <memory>
0023 #include <type_traits>
0024 #include <vector>
0025
0026 #include <boost/algorithm/string/classification.hpp>
0027 #include <boost/algorithm/string/split.hpp>
0028 #include <boost/config.hpp>
0029 #include <boost/noncopyable.hpp>
0030
0031 #include <boost/geometry/core/static_assert.hpp>
0032 #include <boost/geometry/core/tags.hpp>
0033 #include <boost/geometry/core/tag_cast.hpp>
0034 #include <boost/geometry/algorithms/envelope.hpp>
0035 #include <boost/geometry/algorithms/expand.hpp>
0036 #include <boost/geometry/algorithms/is_empty.hpp>
0037 #include <boost/geometry/algorithms/transform.hpp>
0038 #include <boost/geometry/strategies/transform/map_transformer.hpp>
0039 #include <boost/geometry/views/segment_view.hpp>
0040
0041 #include <boost/geometry/io/svg/write.hpp>
0042
0043
0044 #include <boost/geometry/geometries/geometries.hpp>
0045
0046
0047 namespace boost { namespace geometry
0048 {
0049
0050
0051 #ifndef DOXYGEN_NO_DISPATCH
0052 namespace dispatch
0053 {
0054
0055
0056 template <typename GeometryTag, typename Geometry, typename SvgPoint>
0057 struct svg_map
0058 {
0059 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
0060 "Not or not yet implemented for this Geometry type.",
0061 GeometryTag, Geometry);
0062 };
0063
0064
0065 template <typename Point, typename SvgPoint>
0066 struct svg_map<point_tag, Point, SvgPoint>
0067 {
0068 template <typename TransformStrategy>
0069 static inline void apply(std::ostream& stream,
0070 std::string const& style, double size,
0071 Point const& point, TransformStrategy const& strategy)
0072 {
0073 SvgPoint ipoint;
0074 geometry::transform(point, ipoint, strategy);
0075 stream << geometry::svg(ipoint, style, size) << std::endl;
0076 }
0077 };
0078
0079 template <typename BoxSeg1, typename BoxSeg2, typename SvgPoint>
0080 struct svg_map_box_seg
0081 {
0082 template <typename TransformStrategy>
0083 static inline void apply(std::ostream& stream,
0084 std::string const& style, double size,
0085 BoxSeg1 const& box_seg, TransformStrategy const& strategy)
0086 {
0087 BoxSeg2 ibox_seg;
0088
0089
0090 #if defined(BOOST_GCC)
0091 geometry::assign_zero(ibox_seg);
0092 #endif
0093 geometry::transform(box_seg, ibox_seg, strategy);
0094
0095 stream << geometry::svg(ibox_seg, style, size) << std::endl;
0096 }
0097 };
0098
0099 template <typename Box, typename SvgPoint>
0100 struct svg_map<box_tag, Box, SvgPoint>
0101 : svg_map_box_seg<Box, model::box<SvgPoint>, SvgPoint>
0102 {};
0103
0104 template <typename Segment, typename SvgPoint>
0105 struct svg_map<segment_tag, Segment, SvgPoint>
0106 : svg_map_box_seg<Segment, model::segment<SvgPoint>, SvgPoint>
0107 {};
0108
0109
0110 template <typename Range1, typename Range2, typename SvgPoint>
0111 struct svg_map_range
0112 {
0113 template <typename TransformStrategy>
0114 static inline void apply(std::ostream& stream,
0115 std::string const& style, double size,
0116 Range1 const& range, TransformStrategy const& strategy)
0117 {
0118 Range2 irange;
0119 geometry::transform(range, irange, strategy);
0120 stream << geometry::svg(irange, style, size) << std::endl;
0121 }
0122 };
0123
0124 template <typename Ring, typename SvgPoint>
0125 struct svg_map<ring_tag, Ring, SvgPoint>
0126 : svg_map_range<Ring, model::ring<SvgPoint>, SvgPoint>
0127 {};
0128
0129
0130 template <typename Linestring, typename SvgPoint>
0131 struct svg_map<linestring_tag, Linestring, SvgPoint>
0132 : svg_map_range<Linestring, model::linestring<SvgPoint>, SvgPoint>
0133 {};
0134
0135
0136 template <typename Polygon, typename SvgPoint>
0137 struct svg_map<polygon_tag, Polygon, SvgPoint>
0138 {
0139 template <typename TransformStrategy>
0140 static inline void apply(std::ostream& stream,
0141 std::string const& style, double size,
0142 Polygon const& polygon, TransformStrategy const& strategy)
0143 {
0144 model::polygon<SvgPoint> ipoly;
0145 geometry::transform(polygon, ipoly, strategy);
0146 stream << geometry::svg(ipoly, style, size) << std::endl;
0147 }
0148 };
0149
0150
0151 template <typename Multi, typename SvgPoint>
0152 struct svg_map<multi_tag, Multi, SvgPoint>
0153 {
0154 typedef typename single_tag_of
0155 <
0156 typename geometry::tag<Multi>::type
0157 >::type stag;
0158
0159 template <typename TransformStrategy>
0160 static inline void apply(std::ostream& stream,
0161 std::string const& style, double size,
0162 Multi const& multi, TransformStrategy const& strategy)
0163 {
0164 for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
0165 {
0166 svg_map
0167 <
0168 stag,
0169 typename boost::range_value<Multi>::type,
0170 SvgPoint
0171 >::apply(stream, style, size, *it, strategy);
0172 }
0173 }
0174 };
0175
0176
0177 template <typename SvgPoint, typename Geometry>
0178 struct devarianted_svg_map
0179 {
0180 template <typename TransformStrategy>
0181 static inline void apply(std::ostream& stream,
0182 std::string const& style,
0183 double size,
0184 Geometry const& geometry,
0185 TransformStrategy const& strategy)
0186 {
0187 svg_map
0188 <
0189 typename tag_cast
0190 <
0191 typename tag<Geometry>::type,
0192 multi_tag
0193 >::type,
0194 typename std::remove_const<Geometry>::type,
0195 SvgPoint
0196 >::apply(stream, style, size, geometry, strategy);
0197 }
0198 };
0199
0200 template <typename SvgPoint, BOOST_VARIANT_ENUM_PARAMS(typename T)>
0201 struct devarianted_svg_map<SvgPoint, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
0202 {
0203 template <typename TransformStrategy>
0204 struct visitor: static_visitor<void>
0205 {
0206 std::ostream& m_os;
0207 std::string const& m_style;
0208 double m_size;
0209 TransformStrategy const& m_strategy;
0210
0211 visitor(std::ostream& os,
0212 std::string const& style,
0213 double size,
0214 TransformStrategy const& strategy)
0215 : m_os(os)
0216 , m_style(style)
0217 , m_size(size)
0218 , m_strategy(strategy)
0219 {}
0220
0221 template <typename Geometry>
0222 inline void operator()(Geometry const& geometry) const
0223 {
0224 devarianted_svg_map<SvgPoint, Geometry>::apply(m_os, m_style, m_size, geometry, m_strategy);
0225 }
0226 };
0227
0228 template <typename TransformStrategy>
0229 static inline void apply(std::ostream& stream,
0230 std::string const& style,
0231 double size,
0232 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
0233 TransformStrategy const& strategy)
0234 {
0235 boost::apply_visitor(visitor<TransformStrategy>(stream, style, size, strategy), geometry);
0236 }
0237 };
0238
0239
0240 }
0241 #endif
0242
0243
0244 template <typename SvgPoint, typename Geometry, typename TransformStrategy>
0245 inline void svg_map(std::ostream& stream,
0246 std::string const& style, double size,
0247 Geometry const& geometry, TransformStrategy const& strategy)
0248 {
0249 dispatch::devarianted_svg_map<SvgPoint, Geometry>::apply(stream,
0250 style, size, geometry, strategy);
0251 }
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 template
0266 <
0267 typename Point,
0268 bool SameScale = true,
0269 typename SvgCoordinateType = double
0270 >
0271 class svg_mapper : boost::noncopyable
0272 {
0273 typedef model::point<SvgCoordinateType, 2, cs::cartesian> svg_point_type;
0274
0275 typedef typename geometry::select_most_precise
0276 <
0277 typename coordinate_type<Point>::type,
0278 double
0279 >::type calculation_type;
0280
0281 typedef strategy::transform::map_transformer
0282 <
0283 calculation_type,
0284 geometry::dimension<Point>::type::value,
0285 geometry::dimension<Point>::type::value,
0286 true,
0287 SameScale
0288 > transformer_type;
0289
0290 model::box<Point> m_bounding_box;
0291 std::unique_ptr<transformer_type> m_matrix;
0292 std::ostream& m_stream;
0293
0294 SvgCoordinateType const m_width;
0295 SvgCoordinateType const m_height;
0296 calculation_type const m_scale{1.0};
0297
0298 void scale_bounding_box()
0299 {
0300 if (m_scale != 1.0 && m_scale > 0)
0301 {
0302
0303
0304 auto& b = m_bounding_box;
0305 auto const w = geometry::get<1, 0>(b) - geometry::get<0, 0>(b);
0306 auto const h = geometry::get<1, 1>(b) - geometry::get<0, 1>(b);
0307
0308 auto const& m = (std::max)(w, h) * (1.0 - m_scale);
0309 geometry::set<0, 0>(b, geometry::get<0, 0>(b) - m);
0310 geometry::set<0, 1>(b, geometry::get<0, 1>(b) - m);
0311 geometry::set<1, 0>(b, geometry::get<1, 0>(b) + m);
0312 geometry::set<1, 1>(b, geometry::get<1, 1>(b) + m);
0313 }
0314 }
0315
0316 void init_matrix()
0317 {
0318 if (! m_matrix)
0319 {
0320 scale_bounding_box();
0321 m_matrix.reset(new transformer_type(m_bounding_box,
0322 m_width, m_height));
0323 }
0324 }
0325
0326 void write_header(std::string const& width_height)
0327 {
0328 m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
0329 << std::endl
0330 << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
0331 << std::endl
0332 << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
0333 << std::endl
0334 << "<svg " << width_height << " version=\"1.1\""
0335 << std::endl
0336 << "xmlns=\"http://www.w3.org/2000/svg\""
0337 << std::endl
0338 << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
0339 << ">"
0340 << std::endl;
0341 }
0342
0343 public :
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 svg_mapper(std::ostream& stream
0359 , SvgCoordinateType width
0360 , SvgCoordinateType height
0361 , calculation_type scale
0362 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
0363 : m_stream(stream)
0364 , m_width(width)
0365 , m_height(height)
0366 , m_scale(scale)
0367 {
0368 assign_inverse(m_bounding_box);
0369 write_header(width_height);
0370 }
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380 svg_mapper(std::ostream& stream
0381 , SvgCoordinateType width
0382 , SvgCoordinateType height
0383 , std::string const& width_height = "width=\"100%\" height=\"100%\"")
0384 : m_stream(stream)
0385 , m_width(width)
0386 , m_height(height)
0387 {
0388 assign_inverse(m_bounding_box);
0389 write_header(width_height);
0390 }
0391
0392
0393
0394
0395 virtual ~svg_mapper()
0396 {
0397 m_stream << "</svg>" << std::endl;
0398 }
0399
0400
0401
0402
0403
0404
0405
0406 template <typename Geometry>
0407 void add(Geometry const& geometry)
0408 {
0409 if (! geometry::is_empty(geometry))
0410 {
0411 expand(m_bounding_box,
0412 return_envelope
0413 <
0414 model::box<Point>
0415 >(geometry));
0416 }
0417 }
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427 template <typename Geometry>
0428 void map(Geometry const& geometry, std::string const& style,
0429 double size = -1.0)
0430 {
0431 init_matrix();
0432 svg_map<svg_point_type>(m_stream, style, size, geometry, *m_matrix);
0433 }
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445 template <typename TextPoint>
0446 void text(TextPoint const& point, std::string const& s,
0447 std::string const& style,
0448 double offset_x = 0.0, double offset_y = 0.0,
0449 double lineheight = 10.0)
0450 {
0451 init_matrix();
0452 svg_point_type map_point;
0453 transform(point, map_point, *m_matrix);
0454 m_stream
0455 << "<text style=\"" << style << "\""
0456 << " x=\"" << get<0>(map_point) + offset_x << "\""
0457 << " y=\"" << get<1>(map_point) + offset_y << "\""
0458 << ">";
0459 if (s.find('\n') == std::string::npos)
0460 {
0461 m_stream << s;
0462 }
0463 else
0464 {
0465
0466
0467 std::vector<std::string> split;
0468 boost::split(split, s, boost::is_any_of("\n"));
0469 for (auto const& item : split)
0470 {
0471 m_stream
0472 << "<tspan x=\"" << get<0>(map_point) + offset_x
0473 << "\""
0474 << " y=\"" << get<1>(map_point) + offset_y
0475 << "\""
0476 << ">" << item << "</tspan>";
0477 offset_y += lineheight;
0478 }
0479 }
0480 m_stream << "</text>" << std::endl;
0481 }
0482 };
0483
0484
0485 }}
0486
0487
0488 #endif