Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-30 08:18:02

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
0005 
0006 // This file was modified by Oracle on 2015-2021.
0007 // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
0008 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0009 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0010 
0011 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
0012 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
0013 
0014 // Use, modification and distribution is subject to the Boost Software License,
0015 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0016 // http://www.boost.org/LICENSE_1_0.txt)
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 // Helper geometries (all points are transformed to svg-points)
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         // Fix bug in gcc compiler warning for possible uninitialization
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           geometry::tag_t<Multi>
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                 tag_cast_t<tag_t<Geometry>, multi_tag>,
0190                 typename std::remove_const<Geometry>::type,
0191                 SvgPoint
0192             >::apply(stream, style, size, geometry, strategy);
0193     }
0194 };
0195 
0196 template <typename SvgPoint, BOOST_VARIANT_ENUM_PARAMS(typename T)>
0197 struct devarianted_svg_map<SvgPoint, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
0198 {
0199     template <typename TransformStrategy>
0200     struct visitor: static_visitor<void>
0201     {
0202         std::ostream& m_os;
0203         std::string const& m_style;
0204         double m_size;
0205         TransformStrategy const& m_strategy;
0206 
0207         visitor(std::ostream& os,
0208                 std::string const& style,
0209                 double size,
0210                 TransformStrategy const& strategy)
0211             : m_os(os)
0212             , m_style(style)
0213             , m_size(size)
0214             , m_strategy(strategy)
0215         {}
0216 
0217         template <typename Geometry>
0218         inline void operator()(Geometry const& geometry) const
0219         {
0220             devarianted_svg_map<SvgPoint, Geometry>::apply(m_os, m_style, m_size, geometry, m_strategy);
0221         }
0222     };
0223 
0224     template <typename TransformStrategy>
0225     static inline void apply(std::ostream& stream,
0226                              std::string const& style,
0227                              double size,
0228                              variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
0229                              TransformStrategy const& strategy)
0230     {
0231         boost::apply_visitor(visitor<TransformStrategy>(stream, style, size, strategy), geometry);
0232     }
0233 };
0234 
0235 
0236 } // namespace dispatch
0237 #endif
0238 
0239 
0240 template <typename SvgPoint, typename Geometry, typename TransformStrategy>
0241 inline void svg_map(std::ostream& stream,
0242             std::string const& style, double size,
0243             Geometry const& geometry, TransformStrategy const& strategy)
0244 {
0245     dispatch::devarianted_svg_map<SvgPoint, Geometry>::apply(stream,
0246             style, size, geometry, strategy);
0247 }
0248 
0249 
0250 /*!
0251 \brief Helper class to create SVG maps
0252 \tparam Point Point type, for input geometries.
0253 \tparam SameScale Boolean flag indicating if horizontal and vertical scale should
0254     be the same. The default value is true
0255 \tparam SvgCoordinateType Coordinate type of SVG points. SVG is capable to
0256     use floating point coordinates. Therefore the default value is double
0257 \ingroup svg
0258 
0259 \qbk{[include reference/io/svg.qbk]}
0260 */
0261 template
0262 <
0263     typename Point,
0264     bool SameScale = true,
0265     typename SvgCoordinateType = double
0266 >
0267 class svg_mapper : boost::noncopyable
0268 {
0269     typedef model::point<SvgCoordinateType, 2, cs::cartesian> svg_point_type;
0270 
0271     typedef typename geometry::select_most_precise
0272         <
0273             coordinate_type_t<Point>,
0274             double
0275         >::type calculation_type;
0276 
0277     typedef strategy::transform::map_transformer
0278         <
0279             calculation_type,
0280             geometry::dimension<Point>::type::value,
0281             geometry::dimension<Point>::type::value,
0282             true,
0283             SameScale
0284         > transformer_type;
0285 
0286     model::box<Point> m_bounding_box;
0287     std::unique_ptr<transformer_type> m_matrix;
0288     std::ostream& m_stream;
0289 
0290     SvgCoordinateType const m_width;
0291     SvgCoordinateType const m_height;
0292     calculation_type const m_scale{1.0};
0293 
0294     void scale_bounding_box()
0295     {
0296         if (m_scale != 1.0 && m_scale > 0)
0297         {
0298             // Zoom out (scale < 1) or zoom in (scale > 1).
0299             // The default is 0.95, giving a small margin around geometries.
0300             auto& b = m_bounding_box;
0301             auto const w = geometry::get<1, 0>(b) - geometry::get<0, 0>(b);
0302             auto const h = geometry::get<1, 1>(b) - geometry::get<0, 1>(b);
0303 
0304             auto const& m = (std::max)(w, h) * (1.0 - m_scale);
0305             geometry::set<0, 0>(b, geometry::get<0, 0>(b) - m);
0306             geometry::set<0, 1>(b, geometry::get<0, 1>(b) - m);
0307             geometry::set<1, 0>(b, geometry::get<1, 0>(b) + m);
0308             geometry::set<1, 1>(b, geometry::get<1, 1>(b) + m);
0309         }
0310     }
0311 
0312     void init_matrix()
0313     {
0314         if (! m_matrix)
0315         {
0316             scale_bounding_box();
0317             m_matrix.reset(new transformer_type(m_bounding_box,
0318                             m_width, m_height));
0319         }
0320     }
0321 
0322     void write_header(std::string const& width_height)
0323     {
0324         m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
0325             << std::endl
0326             << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
0327             << std::endl
0328             << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
0329             << std::endl
0330             << "<svg " << width_height << " version=\"1.1\""
0331             << std::endl
0332             << "xmlns=\"http://www.w3.org/2000/svg\""
0333             << std::endl
0334             << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
0335             << ">"
0336             << std::endl;
0337     }
0338 
0339 public :
0340 
0341     /*!
0342     \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
0343          Should be called explicitly.
0344     \param stream Output stream, should be a stream already open
0345     \param width Width of the SVG map (in SVG pixels)
0346     \param height Height of the SVG map (in SVG pixels)
0347     \param scale Scale factor of the automatically determined bounding box.
0348             If the factor is less than 1.0, there will be a margin around the
0349             geometries. A factor of 0.95 is often a convenient margin. If the
0350             factor is more than 1.0, the SVG map is zoomed and not all
0351             geometries will be visible.
0352     \param width_height Optional information to increase width and/or height
0353     */
0354     svg_mapper(std::ostream& stream
0355         , SvgCoordinateType width
0356         , SvgCoordinateType height
0357         , calculation_type scale
0358         , std::string const& width_height = "width=\"100%\" height=\"100%\"")
0359         : m_stream(stream)
0360         , m_width(width)
0361         , m_height(height)
0362         , m_scale(scale)
0363     {
0364         assign_inverse(m_bounding_box);
0365         write_header(width_height);
0366     }
0367 
0368     /*!
0369     \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
0370          Should be called explicitly.
0371     \param stream Output stream, should be a stream already open
0372     \param width Width of the SVG map (in SVG pixels)
0373     \param height Height of the SVG map (in SVG pixels)
0374     \param width_height Optional information to increase width and/or height
0375     */
0376     svg_mapper(std::ostream& stream
0377         , SvgCoordinateType width
0378         , SvgCoordinateType height
0379         , std::string const& width_height = "width=\"100%\" height=\"100%\"")
0380         : m_stream(stream)
0381         , m_width(width)
0382         , m_height(height)
0383     {
0384         assign_inverse(m_bounding_box);
0385         write_header(width_height);
0386     }
0387 
0388     /*!
0389     \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
0390     */
0391     virtual ~svg_mapper()
0392     {
0393         m_stream << "</svg>" << std::endl;
0394     }
0395 
0396     /*!
0397     \brief Adds a geometry to the transformation matrix. After doing this,
0398         the specified geometry can be mapped fully into the SVG map
0399     \tparam Geometry \tparam_geometry
0400     \param geometry \param_geometry
0401     */
0402     template <typename Geometry>
0403     void add(Geometry const& geometry)
0404     {
0405         if (! geometry::is_empty(geometry))
0406         {
0407             expand(m_bounding_box,
0408                 return_envelope
0409                     <
0410                         model::box<Point>
0411                     >(geometry));
0412         }
0413     }
0414 
0415     /*!
0416     \brief Maps a geometry into the SVG map using the specified style
0417     \tparam Geometry \tparam_geometry
0418     \param geometry \param_geometry
0419     \param style String containing verbatim SVG style information
0420     \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
0421         specify linewidth in the SVG style information
0422     */
0423     template <typename Geometry>
0424     void map(Geometry const& geometry, std::string const& style,
0425                 double size = -1.0)
0426     {
0427         init_matrix();
0428         svg_map<svg_point_type>(m_stream, style, size, geometry, *m_matrix);
0429     }
0430 
0431     /*!
0432     \brief Adds a text to the SVG map
0433     \tparam TextPoint \tparam_point
0434     \param point Location of the text (in map units)
0435     \param s The text itself
0436     \param style String containing verbatim SVG style information, of the text
0437     \param offset_x Offset in SVG pixels, defaults to 0
0438     \param offset_y Offset in SVG pixels, defaults to 0
0439     \param lineheight Line height in SVG pixels, in case the text contains \n
0440     */
0441     template <typename TextPoint>
0442     void text(TextPoint const& point, std::string const& s,
0443                 std::string const& style,
0444                 double offset_x = 0.0, double offset_y = 0.0,
0445                 double lineheight = 10.0)
0446     {
0447         init_matrix();
0448         svg_point_type map_point;
0449         transform(point, map_point, *m_matrix);
0450         m_stream
0451             << "<text style=\"" << style << "\""
0452             << " x=\"" << get<0>(map_point) + offset_x << "\""
0453             << " y=\"" << get<1>(map_point) + offset_y << "\""
0454             << ">";
0455         if (s.find('\n') == std::string::npos)
0456         {
0457              m_stream  << s;
0458         }
0459         else
0460         {
0461             // Multi-line modus
0462 
0463             std::vector<std::string> split;
0464             boost::split(split, s, boost::is_any_of("\n"));
0465             for (auto const& item : split)
0466             {
0467                  m_stream
0468                     << "<tspan x=\"" << get<0>(map_point) + offset_x
0469                     << "\""
0470                     << " y=\"" << get<1>(map_point) + offset_y
0471                     << "\""
0472                     << ">" << item << "</tspan>";
0473                 offset_y += lineheight;
0474             }
0475         }
0476         m_stream << "</text>" << std::endl;
0477     }
0478 };
0479 
0480 
0481 }} // namespace boost::geometry
0482 
0483 
0484 #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP