1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. 4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. 5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. 6 7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library 8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. 9 10 // Use, modification and distribution is subject to the Boost Software License, 11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 12 // http://www.boost.org/LICENSE_1_0.txt) 13 14 #ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP 15 #define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP 16 17 18 #include <cstddef> 19 20 #include <boost/geometry/strategies/transform/matrix_transformers.hpp> 21 22 namespace boost { namespace geometry 23 { 24 25 // Silence warning C4127: conditional expression is constant 26 #if defined(_MSC_VER) 27 #pragma warning(push) 28 #pragma warning(disable : 4127) 29 #endif 30 31 namespace strategy { namespace transform 32 { 33 34 /*! 35 \brief Transformation strategy to map from one to another Cartesian coordinate system 36 \ingroup strategies 37 \tparam Mirror if true map is mirrored upside-down (in most cases pixels 38 are from top to bottom, while map is from bottom to top) 39 */ 40 template 41 < 42 typename CalculationType, 43 std::size_t Dimension1, 44 std::size_t Dimension2, 45 bool Mirror = false, 46 bool SameScale = true 47 > 48 class map_transformer 49 : public matrix_transformer<CalculationType, Dimension1, Dimension2> 50 { 51 typedef boost::qvm::mat<CalculationType, Dimension1 + 1, Dimension2 + 1> M; 52 typedef boost::qvm::mat<CalculationType, 3, 3> matrix33; 53 54 public : 55 template <typename B, typename D> map_transformer(B const & box,D const & width,D const & height)56 explicit inline map_transformer(B const& box, D const& width, D const& height) 57 { 58 set_transformation( 59 get<min_corner, 0>(box), get<min_corner, 1>(box), 60 get<max_corner, 0>(box), get<max_corner, 1>(box), 61 width, height); 62 } 63 64 template <typename W, typename D> map_transformer(W const & wx1,W const & wy1,W const & wx2,W const & wy2,D const & width,D const & height)65 explicit inline map_transformer(W const& wx1, W const& wy1, W const& wx2, W const& wy2, 66 D const& width, D const& height) 67 { 68 set_transformation(wx1, wy1, wx2, wy2, width, height); 69 } 70 71 72 private : 73 template <typename W, typename P, typename S> set_transformation_point(W const & wx,W const & wy,P const & px,P const & py,S const & scalex,S const & scaley)74 inline void set_transformation_point(W const& wx, W const& wy, 75 P const& px, P const& py, 76 S const& scalex, S const& scaley) 77 { 78 79 // Translate to a coordinate system centered on world coordinates (-wx, -wy) 80 matrix33 t1; 81 qvm::A<0,0>(t1) = 1; qvm::A<0,1>(t1) = 0; qvm::A<0,2>(t1) = -wx; 82 qvm::A<1,0>(t1) = 0; qvm::A<1,1>(t1) = 1; qvm::A<1,2>(t1) = -wy; 83 qvm::A<2,0>(t1) = 0; qvm::A<2,1>(t1) = 0; qvm::A<2,2>(t1) = 1; 84 85 // Scale the map 86 matrix33 s; 87 qvm::A<0,0>(s) = scalex; qvm::A<0,1>(s) = 0; qvm::A<0,2>(s) = 0; 88 qvm::A<1,0>(s) = 0; qvm::A<1,1>(s) = scaley; qvm::A<1,2>(s) = 0; 89 qvm::A<2,0>(s) = 0; qvm::A<2,1>(s) = 0; qvm::A<2,2>(s) = 1; 90 91 // Translate to a coordinate system centered on the specified pixels (+px, +py) 92 matrix33 t2; 93 qvm::A<0,0>(t2) = 1; qvm::A<0,1>(t2) = 0; qvm::A<0,2>(t2) = px; 94 qvm::A<1,0>(t2) = 0; qvm::A<1,1>(t2) = 1; qvm::A<1,2>(t2) = py; 95 qvm::A<2,0>(t2) = 0; qvm::A<2,1>(t2) = 0; qvm::A<2,2>(t2) = 1; 96 97 // Calculate combination matrix in two steps 98 this->m_matrix = s * t1; 99 this->m_matrix = t2 * this->m_matrix; 100 } 101 102 103 template <typename W, typename D> set_transformation(W const & wx1,W const & wy1,W const & wx2,W const & wy2,D const & width,D const & height)104 void set_transformation(W const& wx1, W const& wy1, W const& wx2, W const& wy2, 105 D const& width, D const& height) 106 { 107 D px1 = 0; 108 D py1 = 0; 109 D px2 = width; 110 D py2 = height; 111 112 // Get the same type, but at least a double 113 typedef typename select_most_precise<D, double>::type type; 114 115 116 // Calculate appropriate scale, take min because whole box must fit 117 // Scale is in PIXELS/MAPUNITS (meters) 118 W wdx = wx2 - wx1; 119 W wdy = wy2 - wy1; 120 type sx = (px2 - px1) / boost::numeric_cast<type>(wdx); 121 type sy = (py2 - py1) / boost::numeric_cast<type>(wdy); 122 123 if (SameScale) 124 { 125 type scale = (std::min)(sx, sy); 126 sx = scale; 127 sy = scale; 128 } 129 130 // Calculate centerpoints 131 W wtx = wx1 + wx2; 132 W wty = wy1 + wy2; 133 W two = 2; 134 W wmx = wtx / two; 135 W wmy = wty / two; 136 type pmx = (px1 + px2) / 2.0; 137 type pmy = (py1 + py2) / 2.0; 138 139 set_transformation_point(wmx, wmy, pmx, pmy, sx, sy); 140 141 if (Mirror) 142 { 143 // Mirror in y-direction 144 matrix33 m; 145 qvm::A<0,0>(m) = 1; qvm::A<0,1>(m) = 0; qvm::A<0,2>(m) = 0; 146 qvm::A<1,0>(m) = 0; qvm::A<1,1>(m) = -1; qvm::A<1,2>(m) = 0; 147 qvm::A<2,0>(m) = 0; qvm::A<2,1>(m) = 0; qvm::A<2,2>(m) = 1; 148 149 // Translate in y-direction such that it fits again 150 matrix33 y; 151 qvm::A<0,0>(y) = 1; qvm::A<0,1>(y) = 0; qvm::A<0,2>(y) = 0; 152 qvm::A<1,0>(y) = 0; qvm::A<1,1>(y) = 1; qvm::A<1,2>(y) = height; 153 qvm::A<2,0>(y) = 0; qvm::A<2,1>(y) = 0; qvm::A<2,2>(y) = 1; 154 155 // Calculate combination matrix in two steps 156 this->m_matrix = m * this->m_matrix; 157 this->m_matrix = y * this->m_matrix; 158 } 159 } 160 }; 161 162 163 }} // namespace strategy::transform 164 165 #if defined(_MSC_VER) 166 #pragma warning(pop) 167 #endif 168 169 }} // namespace boost::geometry 170 171 172 #endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP 173