]> git.mxchange.org Git - simgear.git/blob - Lib/Bucket/newbucket.hxx
Tweaks for poles.
[simgear.git] / Lib / Bucket / newbucket.hxx
1 /**************************************************************************
2  * newbucket.hxx -- new bucket routines for better world modeling
3  *
4  * Written by Curtis L. Olson, started February 1999.
5  *
6  * Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $Id$
23  **************************************************************************/
24
25
26 #ifndef _NEWBUCKET_HXX
27 #define _NEWBUCKET_HXX
28
29 #include <Include/compiler.h>
30
31 #include STL_STRING
32
33 #ifdef FG_HAVE_STD_INCLUDES
34 #  include <cstdio> // sprintf()
35 #  include <iostream>
36 #else
37 #  include <stdio.h> // sprintf()
38 #  include <iostream.h>
39 #endif
40
41 FG_USING_STD(string);
42
43 #if ! defined( FG_HAVE_NATIVE_SGI_COMPILERS )
44 FG_USING_STD(ostream);
45 #endif
46
47 #ifdef __MWERKS__
48 #include <math.h>
49 #include <stdio.h>
50 #endif
51
52 #include <Include/fg_constants.h>
53
54
55 #define FG_BUCKET_SPAN      0.125   // 1/8 of a degree
56 #define FG_HALF_BUCKET_SPAN 0.0625  // 1/2 of 1/8 of a degree = 1/16 = 0.0625
57
58 class FGBucket;
59 ostream& operator<< ( ostream&, const FGBucket& );
60 bool operator== ( const FGBucket&, const FGBucket& );
61
62 class FGBucket {
63
64 private:
65     double cx, cy;  // centerpoint (lon, lat) in degrees of bucket
66     int lon;        // longitude index (-180 to 179)
67     int lat;        // latitude index (-90 to 89)
68     int x;          // x subdivision (0 to 7)
69     int y;          // y subdivision (0 to 7)
70
71 public:
72     
73     // default constructor
74     FGBucket();
75
76     // create a bucket which would contain the specified lon/lat
77     FGBucket(const double lon, const double lat);
78
79     // create a bucket based on "long int" index
80     FGBucket(const long int bindex);
81
82     // create an impossible bucket if false
83     FGBucket(const bool is_good);
84
85     ~FGBucket();
86
87     // Set the bucket params for the specified lat and lon
88     void set_bucket( double dlon, double dlat );
89     void make_bad ( void );
90
91     // Generate the unique scenery tile index for this bucket
92     long int gen_index();
93     string gen_index_str() const;
94
95     // Build the path name for this bucket
96     string gen_base_path() const;
97
98     // return the center lon of a tile
99     double get_center_lon() const;
100
101     // return width of the tile
102     double get_width() const;
103
104     // return the center lat of a tile
105     double get_center_lat() const;
106
107     // return height of the tile
108     double get_height() const;
109
110     // Informational methods
111     inline int get_lon() const { return lon; }
112     inline int get_lat() const { return lat; }
113     inline int get_x() const { return x; }
114     inline int get_y() const { return y; }
115
116     // friends
117     friend ostream& operator<< ( ostream&, const FGBucket& );
118     friend bool operator== ( const FGBucket&, const FGBucket& );
119 };
120
121
122 // return the horizontal tile span factor based on latitude
123 inline double bucket_span( double l ) {
124     if ( l >= 89.0 ) {
125         return 360.0;
126     } else if ( l >= 88.0 ) {
127         return 8.0;
128     } else if ( l >= 86.0 ) {
129         return 4.0;
130     } else if ( l >= 83.0 ) {
131         return 2.0;
132     } else if ( l >= 76.0 ) {
133         return 1.0;
134     } else if ( l >= 62.0 ) {
135         return 0.5;
136     } else if ( l >= 22.0 ) {
137         return 0.25;
138     } else if ( l >= -22.0 ) {
139         return 0.125;
140     } else if ( l >= -62.0 ) {
141         return 0.25;
142     } else if ( l >= -76.0 ) {
143         return 0.5;
144     } else if ( l >= -83.0 ) {
145         return 1.0;
146     } else if ( l >= -86.0 ) {
147         return 2.0;
148     } else if ( l >= -88.0 ) {
149         return 4.0;
150     } else if ( l >= -89.0 ) {
151         return 8.0;
152     } else {
153         return 360.0;
154     }
155 }
156
157
158 // Set the bucket params for the specified lat and lon
159 inline void FGBucket::set_bucket( double dlon, double dlat ) {
160     //
161     // latitude first
162     //
163     double span = bucket_span( dlat );
164     double diff = dlon - (double)(int)dlon;
165
166     // cout << "diff = " << diff << "  span = " << span << endl;
167
168     if ( (dlon >= 0) || (fabs(diff) < FG_EPSILON) ) {
169         lon = (int)dlon;
170     } else {
171         lon = (int)dlon - 1;
172     }
173
174     // find subdivision or super lon if needed
175     if ( span < FG_EPSILON ) {
176         // polar cap
177         lon = 0;
178         x = 0;
179     } else if ( span <= 1.0 ) {
180         x = (int)((dlon - lon) / span);
181     } else {
182         if ( (dlon >= 0) || (fabs(diff) < FG_EPSILON) ) {
183             lon = (int)( (int)(lon / span) * span);
184         } else {
185             // cout << " lon = " << lon 
186             //  << "  tmp = " << (int)((lon-1) / span) << endl;
187             lon = (int)( (int)((lon + 1) / span) * span - span);
188             if ( lon < -180 ) {
189                 lon = -180;
190             }
191         }
192         x = 0;
193     }
194
195     //
196     // then latitude
197     //
198     diff = dlat - (double)(int)dlat;
199
200     if ( (dlat >= 0) || (fabs(diff) < FG_EPSILON) ) {
201         lat = (int)dlat;
202     } else {
203         lat = (int)dlat - 1;
204     }
205     y = (int)((dlat - lat) * 8);
206 }
207
208
209 // default constructor
210 inline FGBucket::FGBucket() {}
211
212
213 // constructor for specified location
214 inline FGBucket::FGBucket(const double dlon, const double dlat) {
215     set_bucket(dlon, dlat);
216 }
217
218
219 // create an impossible bucket if false
220 inline FGBucket::FGBucket(const bool is_good) {
221     set_bucket(0.0, 0.0);
222     if ( !is_good ) {
223         lon = -1000;
224     }
225 }
226     
227
228 // Parse a unique scenery tile index and find the lon, lat, x, and y
229 inline FGBucket::FGBucket(const long int bindex) {
230     long int index = bindex;
231
232     lon = index >> 14;
233     index -= lon << 14;
234     lon -= 180;
235     
236     lat = index >> 6;
237     index -= lat << 6;
238     lat -= 90;
239     
240     y = index >> 3;
241     index -= y << 3;
242
243     x = index;
244 }
245
246
247 // default destructor
248 inline FGBucket::~FGBucket() {}
249
250
251 // Generate the unique scenery tile index for this bucket
252 // 
253 // The index is constructed as follows:
254 // 
255 // 9 bits - to represent 360 degrees of longitude (-180 to 179)
256 // 8 bits - to represent 180 degrees of latitude (-90 to 89)
257 //
258 // Each 1 degree by 1 degree tile is further broken down into an 8x8
259 // grid.  So we also need:
260 //
261 // 3 bits - to represent x (0 to 7)
262 // 3 bits - to represent y (0 to 7)
263
264 inline long int FGBucket::gen_index() {
265     return ((lon + 180) << 14) + ((lat + 90) << 6) + (y << 3) + x;
266 }
267
268 inline string FGBucket::gen_index_str() const {
269     char tmp[20];
270     sprintf(tmp, "%ld", 
271             (((long)lon + 180) << 14) + ((lat + 90) << 6) + (y << 3) + x);
272     return (string)tmp;
273 }
274
275
276 // return the center lon of a tile
277 inline double FGBucket::get_center_lon() const {
278     double span = bucket_span( lat + y / 8.0 + FG_HALF_BUCKET_SPAN );
279
280     if ( span >= 1.0 ) {
281         return lon + span / 2.0;
282     } else {
283         return lon + x * span + span / 2.0;
284     }
285 }
286
287
288 // return width of the tile
289 inline double FGBucket::get_width() const {
290     return bucket_span( get_center_lat() );
291 }
292
293
294 // return the center lat of a tile
295 inline double FGBucket::get_center_lat() const {
296     return lat + y / 8.0 + FG_HALF_BUCKET_SPAN;
297 }
298
299
300 // return height of the tile
301 inline double FGBucket::get_height() const {
302     return FG_BUCKET_SPAN;
303 }
304
305
306 // create an impossible bucket
307 inline void FGBucket::make_bad( void ) {
308     set_bucket(0.0, 0.0);
309         lon = -1000;
310 }
311     
312
313 // offset a bucket struct by the specified tile units in the X & Y
314 // direction
315 FGBucket fgBucketOffset( double dlon, double dlat, int x, int y );
316
317
318 // calculate the offset between two buckets
319 void fgBucketDiff( const FGBucket& b1, const FGBucket& b2, int *dx, int *dy );
320
321
322 /*
323 // Given a lat/lon, fill in the local tile index array
324 void fgBucketGenIdxArray(fgBUCKET *p1, fgBUCKET *tiles, int width, int height);
325 */
326
327
328 inline ostream&
329 operator<< ( ostream& out, const FGBucket& b )
330 {
331     return out << b.lon << ":" << b.x << ", " << b.lat << ":" << b.y;
332 }
333
334
335 inline bool
336 operator== ( const FGBucket& b1, const FGBucket& b2 )
337 {
338     return ( b1.lon == b2.lon &&
339              b1.lat == b2.lat &&
340              b1.x == b2.x &&
341              b1.y == b2.y );
342 }
343
344
345 #endif // _NEWBUCKET_HXX
346
347