File indexing completed on 2025-09-16 08:34:36
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef BOOST_GEOMETRY_IO_SVG_WRITE_HPP
0019 #define BOOST_GEOMETRY_IO_SVG_WRITE_HPP
0020
0021 #include <ostream>
0022 #include <string>
0023
0024 #include <boost/config.hpp>
0025 #include <boost/range/begin.hpp>
0026 #include <boost/range/end.hpp>
0027 #include <boost/range/value_type.hpp>
0028 #include <boost/variant/apply_visitor.hpp>
0029 #include <boost/variant/static_visitor.hpp>
0030 #include <boost/variant/variant_fwd.hpp>
0031
0032 #include <boost/geometry/core/exterior_ring.hpp>
0033 #include <boost/geometry/core/interior_rings.hpp>
0034 #include <boost/geometry/core/ring_type.hpp>
0035 #include <boost/geometry/core/static_assert.hpp>
0036
0037 #include <boost/geometry/geometries/concepts/check.hpp>
0038
0039
0040 namespace boost { namespace geometry
0041 {
0042
0043
0044 #ifndef DOXYGEN_NO_DETAIL
0045 namespace detail { namespace svg
0046 {
0047
0048
0049 template <typename Point>
0050 struct svg_point
0051 {
0052 template <typename Char, typename Traits>
0053 static inline void apply(std::basic_ostream<Char, Traits>& os,
0054 Point const& p, std::string const& style, double size)
0055 {
0056 os << "<circle cx=\"" << geometry::get<0>(p)
0057 << "\" cy=\"" << geometry::get<1>(p)
0058 << "\" r=\"" << (size < 0 ? 5 : size)
0059 << "\" style=\"" << style << "\"/>";
0060 }
0061 };
0062
0063
0064 template <typename Box>
0065 struct svg_box
0066 {
0067 template <typename Char, typename Traits>
0068 static inline void apply(std::basic_ostream<Char, Traits>& os,
0069 Box const& box, std::string const& style, double)
0070 {
0071
0072 BOOST_USING_STD_MAX();
0073
0074 using ct = coordinate_type_t<Box>;
0075 ct x = geometry::get<geometry::min_corner, 0>(box);
0076 ct y = geometry::get<geometry::min_corner, 1>(box);
0077 ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION (ct(1),
0078 geometry::get<geometry::max_corner, 0>(box) - x);
0079 ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (ct(1),
0080 geometry::get<geometry::max_corner, 1>(box) - y);
0081
0082 os << "<rect x=\"" << x << "\" y=\"" << y
0083 << "\" width=\"" << width << "\" height=\"" << height
0084 << "\" style=\"" << style << "\"/>";
0085 }
0086 };
0087
0088 template <typename Segment>
0089 struct svg_segment
0090 {
0091 template <typename Char, typename Traits>
0092 static inline void apply(std::basic_ostream<Char, Traits>& os,
0093 Segment const& segment, std::string const& style, double)
0094 {
0095 using ct = coordinate_type_t<Segment>;
0096 ct const x1 = geometry::get<0, 0>(segment);
0097 ct const y1 = geometry::get<0, 1>(segment);
0098 ct const x2 = geometry::get<1, 0>(segment);
0099 ct const y2 = geometry::get<1, 1>(segment);
0100
0101 os << "<line x1=\"" << x1 << "\" y1=\"" << y1
0102 << "\" x2=\"" << x2 << "\" y2=\"" << y2
0103 << "\" style=\"" << style << "\"/>";
0104 }
0105 };
0106
0107
0108
0109
0110
0111 template <typename Range, typename Policy>
0112 struct svg_range
0113 {
0114 template <typename Char, typename Traits>
0115 static inline void apply(std::basic_ostream<Char, Traits>& os,
0116 Range const& range, std::string const& style, double)
0117 {
0118 bool first = true;
0119
0120 os << "<" << Policy::prefix() << " points=\"";
0121
0122 for (auto it = boost::begin(range); it != boost::end(range); ++it, first = false)
0123 {
0124 os << (first ? "" : " " )
0125 << geometry::get<0>(*it)
0126 << ","
0127 << geometry::get<1>(*it);
0128 }
0129 os << "\" style=\"" << style << Policy::style() << "\"/>";
0130 }
0131 };
0132
0133
0134
0135 template <typename Polygon>
0136 struct svg_poly
0137 {
0138 template <typename Char, typename Traits>
0139 static inline void apply(std::basic_ostream<Char, Traits>& os,
0140 Polygon const& polygon, std::string const& style, double)
0141 {
0142 bool first = true;
0143 os << "<g fill-rule=\"evenodd\"><path d=\"";
0144
0145 auto const& ring = geometry::exterior_ring(polygon);
0146 for (auto it = boost::begin(ring); it != boost::end(ring); ++it, first = false)
0147 {
0148 os << (first ? "M" : " L") << " "
0149 << geometry::get<0>(*it)
0150 << ","
0151 << geometry::get<1>(*it);
0152 }
0153
0154
0155 {
0156 auto const& rings = interior_rings(polygon);
0157 for (auto rit = boost::begin(rings); rit != boost::end(rings); ++rit)
0158 {
0159 first = true;
0160 for (auto it = boost::begin(*rit); it != boost::end(*rit); ++it, first = false)
0161 {
0162 os << (first ? "M" : " L") << " "
0163 << geometry::get<0>(*it)
0164 << ","
0165 << geometry::get<1>(*it);
0166 }
0167 }
0168 }
0169 os << " z \" style=\"" << style << "\"/></g>";
0170
0171 }
0172 };
0173
0174
0175
0176 struct prefix_linestring
0177 {
0178 static inline const char* prefix() { return "polyline"; }
0179 static inline const char* style() { return ";fill:none"; }
0180 };
0181
0182
0183 struct prefix_ring
0184 {
0185 static inline const char* prefix() { return "polygon"; }
0186 static inline const char* style() { return ""; }
0187 };
0188
0189
0190 template <typename MultiGeometry, typename Policy>
0191 struct svg_multi
0192 {
0193 template <typename Char, typename Traits>
0194 static inline void apply(std::basic_ostream<Char, Traits>& os,
0195 MultiGeometry const& multi, std::string const& style, double size)
0196 {
0197 for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
0198 {
0199 Policy::apply(os, *it, style, size);
0200 }
0201 }
0202
0203 };
0204
0205
0206 }}
0207 #endif
0208
0209
0210 #ifndef DOXYGEN_NO_DISPATCH
0211 namespace dispatch
0212 {
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 template <typename Geometry, typename Tag = tag_t<Geometry>>
0223 struct svg
0224 {
0225 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
0226 "Not or not yet implemented for this Geometry type.",
0227 Geometry, Tag);
0228 };
0229
0230 template <typename Point>
0231 struct svg<Point, point_tag> : detail::svg::svg_point<Point> {};
0232
0233 template <typename Segment>
0234 struct svg<Segment, segment_tag> : detail::svg::svg_segment<Segment> {};
0235
0236 template <typename Box>
0237 struct svg<Box, box_tag> : detail::svg::svg_box<Box> {};
0238
0239 template <typename Linestring>
0240 struct svg<Linestring, linestring_tag>
0241 : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
0242
0243 template <typename Ring>
0244 struct svg<Ring, ring_tag>
0245 : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
0246
0247 template <typename Polygon>
0248 struct svg<Polygon, polygon_tag>
0249 : detail::svg::svg_poly<Polygon> {};
0250
0251 template <typename MultiPoint>
0252 struct svg<MultiPoint, multi_point_tag>
0253 : detail::svg::svg_multi
0254 <
0255 MultiPoint,
0256 detail::svg::svg_point
0257 <
0258 typename boost::range_value<MultiPoint>::type
0259 >
0260
0261 >
0262 {};
0263
0264 template <typename MultiLinestring>
0265 struct svg<MultiLinestring, multi_linestring_tag>
0266 : detail::svg::svg_multi
0267 <
0268 MultiLinestring,
0269 detail::svg::svg_range
0270 <
0271 typename boost::range_value<MultiLinestring>::type,
0272 detail::svg::prefix_linestring
0273 >
0274
0275 >
0276 {};
0277
0278 template <typename MultiPolygon>
0279 struct svg<MultiPolygon, multi_polygon_tag>
0280 : detail::svg::svg_multi
0281 <
0282 MultiPolygon,
0283 detail::svg::svg_poly
0284 <
0285 typename boost::range_value<MultiPolygon>::type
0286 >
0287
0288 >
0289 {};
0290
0291
0292 template <typename Geometry>
0293 struct devarianted_svg
0294 {
0295 template <typename OutputStream>
0296 static inline void apply(OutputStream& os,
0297 Geometry const& geometry,
0298 std::string const& style,
0299 double size)
0300 {
0301 svg<Geometry>::apply(os, geometry, style, size);
0302 }
0303 };
0304
0305 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
0306 struct devarianted_svg<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
0307 {
0308 template <typename OutputStream>
0309 struct visitor: static_visitor<void>
0310 {
0311 OutputStream& m_os;
0312 std::string const& m_style;
0313 double m_size;
0314
0315 visitor(OutputStream& os, std::string const& style, double size)
0316 : m_os(os)
0317 , m_style(style)
0318 , m_size(size)
0319 {}
0320
0321 template <typename Geometry>
0322 inline void operator()(Geometry const& geometry) const
0323 {
0324 devarianted_svg<Geometry>::apply(m_os, geometry, m_style, m_size);
0325 }
0326 };
0327
0328 template <typename OutputStream>
0329 static inline void apply(
0330 OutputStream& os,
0331 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
0332 std::string const& style,
0333 double size
0334 )
0335 {
0336 boost::apply_visitor(visitor<OutputStream>(os, style, size), geometry);
0337 }
0338 };
0339
0340 }
0341 #endif
0342
0343
0344
0345
0346
0347
0348
0349 template <typename Geometry>
0350 class svg_manipulator
0351 {
0352 public:
0353
0354 inline svg_manipulator(Geometry const& g, std::string const& style, double size)
0355 : m_geometry(g)
0356 , m_style(style)
0357 , m_size(size)
0358 {}
0359
0360 template <typename Char, typename Traits>
0361 inline friend std::basic_ostream<Char, Traits>& operator<<(
0362 std::basic_ostream<Char, Traits>& os, svg_manipulator const& m)
0363 {
0364 dispatch::devarianted_svg<Geometry>::apply(os,
0365 m.m_geometry,
0366 m.m_style,
0367 m.m_size);
0368 os.flush();
0369 return os;
0370 }
0371
0372 private:
0373 Geometry const& m_geometry;
0374 std::string const& m_style;
0375 double m_size;
0376 };
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 template <typename Geometry>
0388 inline svg_manipulator<Geometry> svg(Geometry const& geometry,
0389 std::string const& style, double size = -1.0)
0390 {
0391 concepts::check<Geometry const>();
0392
0393 return svg_manipulator<Geometry>(geometry, style, size);
0394 }
0395
0396 }}
0397
0398 #endif