]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/map/projection.hxx
Canvas: Respect clipping while event handling.
[simgear.git] / simgear / canvas / elements / map / projection.hxx
1 // Geographic projections for Canvas map element
2 //
3 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #ifndef CANVAS_MAP_PROJECTION_HXX_
20 #define CANVAS_MAP_PROJECTION_HXX_
21
22 #include <simgear/math/SGMisc.hxx>
23
24 namespace simgear
25 {
26 namespace canvas
27 {
28
29   /**
30    * Base class for all projections
31    */
32   class Projection
33   {
34     public:
35       struct ScreenPosition
36       {
37         ScreenPosition() {}
38
39         ScreenPosition(double x, double y):
40           x(x),
41           y(y)
42         {}
43
44         double x, y;
45       };
46
47       virtual ~Projection() {}
48
49       void setScreenRange(double range)
50       {
51         _screen_range = range;
52       }
53
54       virtual ScreenPosition worldToScreen(double x, double y) = 0;
55
56     protected:
57
58       double _screen_range;
59   };
60
61   /**
62    * Base class for horizontal projections
63    */
64   class HorizontalProjection:
65     public Projection
66   {
67     public:
68
69       HorizontalProjection():
70         _cos_rot(1),
71         _sin_rot(0),
72         _range(5)
73       {
74         setScreenRange(200);
75       }
76
77       /**
78        * Set world position of center point used for the projection
79        */
80       void setWorldPosition(double lat, double lon)
81       {
82         _ref_lat = SGMiscd::deg2rad(lat);
83         _ref_lon = SGMiscd::deg2rad(lon);
84       }
85
86       /**
87        * Set up heading
88        */
89       void setOrientation(float hdg)
90       {
91         hdg = SGMiscf::deg2rad(hdg);
92         _sin_rot = sin(hdg);
93         _cos_rot = cos(hdg);
94       }
95
96       void setRange(double range)
97       {
98         _range = range;
99       }
100
101       /**
102        * Transform given world position to screen position
103        *
104        * @param lat   Latitude in degrees
105        * @param lon   Longitude in degrees
106        */
107       ScreenPosition worldToScreen(double lat, double lon)
108       {
109         lat = SGMiscd::deg2rad(lat);
110         lon = SGMiscd::deg2rad(lon);
111         ScreenPosition pos = project(lat, lon);
112         double scale = _screen_range / _range;
113         pos.x *= scale;
114         pos.y *= scale;
115         return ScreenPosition
116         (
117           _cos_rot * pos.x - _sin_rot * pos.y,
118          -_sin_rot * pos.x - _cos_rot * pos.y
119         );
120       }
121
122     protected:
123
124       /**
125        * Project given geographic world position to screen space
126        *
127        * @param lat   Latitude in radians
128        * @param lon   Longitude in radians
129        */
130       virtual ScreenPosition project(double lat, double lon) const = 0;
131
132       double  _ref_lat,
133               _ref_lon,
134               _cos_rot,
135               _sin_rot,
136               _range;
137   };
138
139   /**
140    * Sanson-Flamsteed projection, relative to the projection center
141    */
142   class SansonFlamsteedProjection:
143     public HorizontalProjection
144   {
145     protected:
146
147       virtual ScreenPosition project(double lat, double lon) const
148       {
149         double d_lat = lat - _ref_lat,
150                d_lon = lon - _ref_lon;
151         double r = getEarthRadius(lat);
152
153         ScreenPosition pos;
154
155         pos.x = r * cos(lat) * d_lon;
156         pos.y = r * d_lat;
157
158         return pos;
159       }
160
161       /**
162        * Returns Earth radius at a given latitude (Ellipsoide equation with two
163        * equal axis)
164        */
165       float getEarthRadius(float lat) const
166       {
167         const float rec  = 6378137.f / 1852;      // earth radius, equator (?)
168         const float rpol = 6356752.314f / 1852;   // earth radius, polar   (?)
169
170         double a = cos(lat) / rec;
171         double b = sin(lat) / rpol;
172         return 1.0f / sqrt( a * a + b * b );
173       }
174   };
175
176 } // namespace canvas
177 } // namespace simgear
178
179 #endif /* CANVAS_MAP_PROJECTION_HXX_ */