]> git.mxchange.org Git - simgear.git/blob - simgear/bucket/newbucket.cxx
MacOS tweaks contributed by Darrell Walisser.
[simgear.git] / simgear / bucket / newbucket.cxx
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 library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA  02111-1307, USA.
22  *
23  * $Id$
24  **************************************************************************/
25
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31
32 #include <math.h>
33
34 #include <simgear/misc/fgpath.hxx>
35
36 #include "newbucket.hxx"
37
38
39 // default constructor
40 SGBucket::SGBucket() {
41 }
42
43
44 // constructor for specified location
45 SGBucket::SGBucket(const double dlon, const double dlat) {
46     set_bucket(dlon, dlat);
47 }
48
49
50 // create an impossible bucket if false
51 SGBucket::SGBucket(const bool is_good) {
52     set_bucket(0.0, 0.0);
53     if ( !is_good ) {
54         lon = -1000;
55     }
56 }
57
58
59 // Parse a unique scenery tile index and find the lon, lat, x, and y
60 SGBucket::SGBucket(const long int bindex) {
61     long int index = bindex;
62         
63     lon = index >> 14;
64     index -= lon << 14;
65     lon -= 180;
66
67     lat = index >> 6;
68     index -= lat << 6;
69     lat -= 90;
70
71     y = index >> 3;
72     index -= y << 3;
73
74     x = index;
75 }
76
77
78 // default destructor
79 SGBucket::~SGBucket() {
80 }
81
82
83 // Set the bucket params for the specified lat and lon
84 void SGBucket::set_bucket( double *lonlat ) {
85     set_bucket( lonlat[0], lonlat[1] );
86 }       
87
88
89 // Set the bucket params for the specified lat and lon
90 void SGBucket::set_bucket( double dlon, double dlat ) {
91     //
92     // latitude first
93     //
94     double span = sg_bucket_span( dlat );
95     double diff = dlon - (double)(int)dlon;
96
97     // cout << "diff = " << diff << "  span = " << span << endl;
98
99     if ( (dlon >= 0) || (fabs(diff) < FG_EPSILON) ) {
100         lon = (int)dlon;
101     } else {
102         lon = (int)dlon - 1;
103     }
104
105     // find subdivision or super lon if needed
106     if ( span < FG_EPSILON ) {
107         // polar cap
108         lon = 0;
109         x = 0;
110     } else if ( span <= 1.0 ) {
111         x = (int)((dlon - lon) / span);
112     } else {
113         if ( (dlon >= 0) || (fabs(diff) < FG_EPSILON) ) {
114             lon = (int)( (int)(lon / span) * span);
115         } else {
116             // cout << " lon = " << lon 
117             //  << "  tmp = " << (int)((lon-1) / span) << endl;
118             lon = (int)( (int)((lon + 1) / span) * span - span);
119             if ( lon < -180 ) {
120                 lon = -180;
121             }
122         }
123         x = 0;
124     }
125
126     //
127     // then latitude
128     //
129     diff = dlat - (double)(int)dlat;
130
131     if ( (dlat >= 0) || (fabs(diff) < FG_EPSILON) ) {
132         lat = (int)dlat;
133     } else {
134         lat = (int)dlat - 1;
135     }
136     y = (int)((dlat - lat) * 8);
137 }
138
139
140 // Build the path name for this bucket
141 string SGBucket::gen_base_path() const {
142     // long int index;
143     int top_lon, top_lat, main_lon, main_lat;
144     char hem, pole;
145     char raw_path[256];
146
147     top_lon = lon / 10;
148     main_lon = lon;
149     if ( (lon < 0) && (top_lon * 10 != lon) ) {
150         top_lon -= 1;
151     }
152     top_lon *= 10;
153     if ( top_lon >= 0 ) {
154         hem = 'e';
155     } else {
156         hem = 'w';
157         top_lon *= -1;
158     }
159     if ( main_lon < 0 ) {
160         main_lon *= -1;
161     }
162     
163     top_lat = lat / 10;
164     main_lat = lat;
165     if ( (lat < 0) && (top_lat * 10 != lat) ) {
166         top_lat -= 1;
167     }
168     top_lat *= 10;
169     if ( top_lat >= 0 ) {
170         pole = 'n';
171     } else {
172         pole = 's';
173         top_lat *= -1;
174     }
175     if ( main_lat < 0 ) {
176         main_lat *= -1;
177     }
178
179     sprintf(raw_path, "%c%03d%c%02d/%c%03d%c%02d", 
180             hem, top_lon, pole, top_lat, 
181             hem, main_lon, pole, main_lat);
182
183     FGPath path( raw_path );
184
185     return path.str();
186 }
187
188
189 // return width of the tile in degrees
190 double SGBucket::get_width() const {
191     return sg_bucket_span( get_center_lat() );
192 }
193
194
195 // return height of the tile in degrees
196 double SGBucket::get_height() const {
197     return SG_BUCKET_SPAN;
198 }
199
200
201 // return width of the tile in meters
202 double SGBucket::get_width_m() const {
203     double clat = (int)get_center_lat();
204     if ( clat > 0 ) {
205         clat = (int)clat + 0.5;
206     } else {
207         clat = (int)clat - 0.5;
208     }
209     double clat_rad = clat * DEG_TO_RAD;
210     double cos_lat = cos( clat_rad );
211     double local_radius = cos_lat * EQUATORIAL_RADIUS_M;
212     double local_perimeter = 2.0 * local_radius * FG_PI;
213     double degree_width = local_perimeter / 360.0;
214
215     return sg_bucket_span( get_center_lat() ) * degree_width;
216 }
217
218
219 // return height of the tile in meters
220 double SGBucket::get_height_m() const {
221     double perimeter = 2.0 * EQUATORIAL_RADIUS_M * FG_PI;
222     double degree_height = perimeter / 360.0;
223
224     return SG_BUCKET_SPAN * degree_height;
225 }
226
227
228 // find the bucket which is offset by the specified tile units in the
229 // X & Y direction.  We need the current lon and lat to resolve
230 // ambiguities when going from a wider tile to a narrower one above or
231 // below.  This assumes that we are feeding in
232 SGBucket sgBucketOffset( double dlon, double dlat, int dx, int dy ) {
233     SGBucket result( dlon, dlat );
234     double clat = result.get_center_lat() + dy * SG_BUCKET_SPAN;
235
236     // walk dy units in the lat direction
237     result.set_bucket( dlon, clat );
238
239     // find the lon span for the new latitude
240     double span = sg_bucket_span( clat );
241
242     // walk dx units in the lon direction
243     double tmp = dlon + dx * span;
244     while ( tmp < -180.0 ) {
245         tmp += 360.0;
246     }
247     while ( tmp >= 180.0 ) {
248         tmp -= 360.0;
249     }
250     result.set_bucket( tmp, clat );
251
252     return result;
253 }
254
255
256 // calculate the offset between two buckets
257 void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
258
259     // Latitude difference
260     double c1_lat = b1.get_center_lat();
261     double c2_lat = b2.get_center_lat();
262     double diff_lat = c2_lat - c1_lat;
263
264 #ifdef HAVE_RINT
265     *dy = (int)rint( diff_lat / SG_BUCKET_SPAN );
266 #else
267     if ( diff_lat > 0 ) {
268         *dy = (int)( diff_lat / SG_BUCKET_SPAN + 0.5 );
269     } else {
270         *dy = (int)( diff_lat / SG_BUCKET_SPAN - 0.5 );
271     }
272 #endif
273
274     // longitude difference
275     double c1_lon = b1.get_center_lon();
276     double c2_lon = b2.get_center_lon();
277     double diff_lon = c2_lon - c1_lon;
278     double span;
279     if ( sg_bucket_span(c1_lat) <= sg_bucket_span(c2_lat) ) {
280         span = sg_bucket_span(c1_lat);
281     } else {
282         span = sg_bucket_span(c2_lat);
283     }
284
285 #ifdef HAVE_RINT
286     *dx = (int)rint( diff_lon / span );
287 #else
288     if ( diff_lon > 0 ) {
289         *dx = (int)( diff_lon / span + 0.5 );
290     } else {
291         *dx = (int)( diff_lon / span - 0.5 );
292     }
293 #endif
294 }
295
296