1109e814b9e18986eb19ede182f1731d030881be
[platform/upstream/boost.git] / boost / geometry / strategies / transform / map_transformer.hpp
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 ublas_transformer<CalculationType, Dimension1, Dimension2>
50 {
51     typedef boost::numeric::ublas::matrix<CalculationType> M;
52
53 public :
54     template <typename B, typename D>
55     explicit inline map_transformer(B const& box, D const& width, D const& height)
56     {
57         set_transformation(
58                 get<min_corner, 0>(box), get<min_corner, 1>(box),
59                 get<max_corner, 0>(box), get<max_corner, 1>(box),
60                 width, height);
61     }
62
63     template <typename W, typename D>
64     explicit inline map_transformer(W const& wx1, W const& wy1, W const& wx2, W const& wy2,
65                         D const& width, D const& height)
66     {
67         set_transformation(wx1, wy1, wx2, wy2, width, height);
68     }
69
70
71 private :
72     template <typename W, typename P, typename S>
73     inline void set_transformation_point(W const& wx, W const& wy,
74         P const& px, P const& py,
75         S const& scalex, S const& scaley)
76     {
77
78         // Translate to a coordinate system centered on world coordinates (-wx, -wy)
79         M t1(3,3);
80         t1(0,0) = 1;   t1(0,1) = 0;   t1(0,2) = -wx;
81         t1(1,0) = 0;   t1(1,1) = 1;   t1(1,2) = -wy;
82         t1(2,0) = 0;   t1(2,1) = 0;   t1(2,2) = 1;
83
84         // Scale the map
85         M s(3,3);
86         s(0,0) = scalex;   s(0,1) = 0;   s(0,2) = 0;
87         s(1,0) = 0;    s(1,1) = scaley;  s(1,2) = 0;
88         s(2,0) = 0;    s(2,1) = 0;      s(2,2) = 1;
89
90         // Translate to a coordinate system centered on the specified pixels (+px, +py)
91         M t2(3, 3);
92         t2(0,0) = 1;   t2(0,1) = 0;   t2(0,2) = px;
93         t2(1,0) = 0;   t2(1,1) = 1;   t2(1,2) = py;
94         t2(2,0) = 0;   t2(2,1) = 0;   t2(2,2) = 1;
95
96         // Calculate combination matrix in two steps
97         this->m_matrix = boost::numeric::ublas::prod(s, t1);
98         this->m_matrix = boost::numeric::ublas::prod(t2, this->m_matrix);
99     }
100
101
102     template <typename W, typename D>
103     void set_transformation(W const& wx1, W const& wy1, W const& wx2, W const& wy2,
104                     D const& width, D const& height)
105     {
106         D px1 = 0;
107         D py1 = 0;
108         D px2 = width;
109         D py2 = height;
110
111         // Get the same type, but at least a double
112         typedef typename select_most_precise<D, double>::type type;
113
114
115         // Calculate appropriate scale, take min because whole box must fit
116         // Scale is in PIXELS/MAPUNITS (meters)
117         W wdx = wx2 - wx1;
118         W wdy = wy2 - wy1;
119         type sx = (px2 - px1) / boost::numeric_cast<type>(wdx);
120         type sy = (py2 - py1) / boost::numeric_cast<type>(wdy);
121
122         if (SameScale)
123         {
124             type scale = (std::min)(sx, sy);
125             sx = scale;
126             sy = scale;
127         }
128
129         // Calculate centerpoints
130         W wtx = wx1 + wx2;
131         W wty = wy1 + wy2;
132         W two = 2;
133         W wmx = wtx / two;
134         W wmy = wty / two;
135         type pmx = (px1 + px2) / 2.0;
136         type pmy = (py1 + py2) / 2.0;
137
138         set_transformation_point(wmx, wmy, pmx, pmy, sx, sy);
139
140         if (Mirror)
141         {
142             // Mirror in y-direction
143             M m(3,3);
144             m(0,0) = 1;   m(0,1) = 0;   m(0,2) = 0;
145             m(1,0) = 0;   m(1,1) = -1;  m(1,2) = 0;
146             m(2,0) = 0;   m(2,1) = 0;   m(2,2) = 1;
147
148             // Translate in y-direction such that it fits again
149             M y(3, 3);
150             y(0,0) = 1;   y(0,1) = 0;   y(0,2) = 0;
151             y(1,0) = 0;   y(1,1) = 1;   y(1,2) = height;
152             y(2,0) = 0;   y(2,1) = 0;   y(2,2) = 1;
153
154             // Calculate combination matrix in two steps
155             this->m_matrix = boost::numeric::ublas::prod(m, this->m_matrix);
156             this->m_matrix = boost::numeric::ublas::prod(y, this->m_matrix);
157         }
158     }
159 };
160
161
162 }} // namespace strategy::transform
163
164 #if defined(_MSC_VER)
165 #pragma warning(pop)
166 #endif
167
168 }} // namespace boost::geometry
169
170
171 #endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP