Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:35

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           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 } // namespace dispatch
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 \brief Helper class to create SVG maps
0256 \tparam Point Point type, for input geometries.
0257 \tparam SameScale Boolean flag indicating if horizontal and vertical scale should
0258     be the same. The default value is true
0259 \tparam SvgCoordinateType Coordinate type of SVG points. SVG is capable to
0260     use floating point coordinates. Therefore the default value is double
0261 \ingroup svg
0262 
0263 \qbk{[include reference/io/svg.qbk]}
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             // Zoom out (scale < 1) or zoom in (scale > 1).
0303             // The default is 0.95, giving a small margin around geometries.
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     \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
0347          Should be called explicitly.
0348     \param stream Output stream, should be a stream already open
0349     \param width Width of the SVG map (in SVG pixels)
0350     \param height Height of the SVG map (in SVG pixels)
0351     \param scale Scale factor of the automatically determined bounding box.
0352             If the factor is less than 1.0, there will be a margin around the
0353             geometries. A factor of 0.95 is often a convenient margin. If the
0354             factor is more than 1.0, the SVG map is zoomed and not all
0355             geometries will be visible.
0356     \param width_height Optional information to increase width and/or height
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     \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
0374          Should be called explicitly.
0375     \param stream Output stream, should be a stream already open
0376     \param width Width of the SVG map (in SVG pixels)
0377     \param height Height of the SVG map (in SVG pixels)
0378     \param width_height Optional information to increase width and/or height
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     \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
0394     */
0395     virtual ~svg_mapper()
0396     {
0397         m_stream << "</svg>" << std::endl;
0398     }
0399 
0400     /*!
0401     \brief Adds a geometry to the transformation matrix. After doing this,
0402         the specified geometry can be mapped fully into the SVG map
0403     \tparam Geometry \tparam_geometry
0404     \param geometry \param_geometry
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     \brief Maps a geometry into the SVG map using the specified style
0421     \tparam Geometry \tparam_geometry
0422     \param geometry \param_geometry
0423     \param style String containing verbatim SVG style information
0424     \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
0425         specify linewidth in the SVG style information
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     \brief Adds a text to the SVG map
0437     \tparam TextPoint \tparam_point
0438     \param point Location of the text (in map units)
0439     \param s The text itself
0440     \param style String containing verbatim SVG style information, of the text
0441     \param offset_x Offset in SVG pixels, defaults to 0
0442     \param offset_y Offset in SVG pixels, defaults to 0
0443     \param lineheight Line height in SVG pixels, in case the text contains \n
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             // Multi-line modus
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 }} // namespace boost::geometry
0486 
0487 
0488 #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP