#endif
#include <cmath>
+#include <cstdio> // some platforms need this for ::snprintf
#include <iostream>
#include <simgear/misc/sg_path.hxx>
lat = -1000;
}
+#ifndef NO_DEPRECATED_API
+
// constructor for specified location
SGBucket::SGBucket(const double dlon, const double dlat) {
set_bucket(dlon, dlat);
}
+#endif
SGBucket::SGBucket(const SGGeod& geod) {
- set_bucket(geod.getLongitudeDeg(),
- geod.getLatitudeDeg());
+ innerSet(geod.getLongitudeDeg(),
+ geod.getLatitudeDeg());
}
// Parse a unique scenery tile index and find the lon, lat, x, and y
*/
static int floorWithEpsilon(double x)
{
- double diff = x - static_cast<int>(x);
- if ( (x >= 0.0) || (fabs(diff) < SG_EPSILON) ) {
- return static_cast<int>(x);
- } else {
- return static_cast<int>(x) - 1;
- }
+ return static_cast<int>(floor(x + SG_EPSILON));
+}
+
+#ifndef NO_DEPRECATED_API
+
+void SGBucket::set_bucket(double dlon, double dlat)
+{
+ innerSet(dlon, dlat);
}
+
+void SGBucket::set_bucket(const SGGeod& geod)
+{
+ innerSet(geod.getLongitudeDeg(), geod.getLatitudeDeg());
+}
+
+#endif
+
// Set the bucket params for the specified lat and lon
-void SGBucket::set_bucket( double dlon, double dlat )
+void SGBucket::innerSet( double dlon, double dlat )
{
if ((dlon < -180.0) || (dlon >= 180.0)) {
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::set_bucket: passed longitude:" << dlon);
/* We have more than one tile per degree of
* longitude, so we need an x offset.
*/
- x = (int)((dlon - lon) / span);
+ x = floorWithEpsilon((dlon - lon) / span);
} else {
/* We have one or more degrees per tile,
* so we need to find the base longitude
/* Latitude base and offset are easier, as
* tiles always are 1/8 degree of latitude wide.
*/
- y = (int)((dlat - lat) * 8);
+ y = floorWithEpsilon((dlat - lat) * 8);
}
}
-void SGBucket::set_bucket(const SGGeod& geod)
-{
- set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
-}
-
// Build the path name for this bucket
std::string SGBucket::gen_base_path() const {
// long int index;
main_lat *= -1;
}
- snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d",
+ ::snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d",
hem, top_lon, pole, top_lat,
hem, main_lon, pole, main_lat);
return SG_BUCKET_SPAN;
}
-
-// return width of the tile in meters
-double SGBucket::get_width_m() const {
- double clat = (int)get_center_lat();
- if ( clat > 0 ) {
- clat = (int)clat + 0.5;
- } else {
- clat = (int)clat - 0.5;
+double SGBucket::get_highest_lat() const
+{
+ unsigned char adjustedY = y;
+ if (lat >= 0) {
+ // tile is north of the equator, so we want the top edge. Add one
+ // to y to achieve this.
+ ++adjustedY;
}
- double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
+
+ return lat + (adjustedY / 8.0);
+}
+
+
+// return width of the tile in meters. This function is used by the
+// tile-manager to estimate how many tiles are in the view distance, so
+// we care about the smallest width, which occurs at the highest latitude.
+double SGBucket::get_width_m() const
+{
+ double clat_rad = get_highest_lat() * SGD_DEGREES_TO_RADIANS;
double cos_lat = cos( clat_rad );
+ if (fabs(cos_lat) < SG_EPSILON) {
+ // happens for polar tiles, since we pass in a latitude of 90
+ // return an arbitrary small value so all tiles are loaded
+ return 10.0;
+ }
+
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
double local_perimeter = local_radius * SGD_2PI;
double degree_width = local_perimeter / 360.0;
double tmp = get_center_lon() + dx * span;
tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
- return SGBucket(tmp, clat);
+
+ SGBucket b;
+ b.innerSet(tmp, clat);
+ return b;
}
std::string SGBucket::gen_index_str() const
{
char tmp[20];
- std::snprintf(tmp, 20, "%ld",
+ ::snprintf(tmp, 20, "%ld",
(((long)lon + 180) << 14) + ((lat + 90) << 6)
+ (y << 3) + x);
return (std::string)tmp;
}
+#ifndef NO_DEPRECATED_API
// find the bucket which is offset by the specified tile units in the
// X & Y direction. We need the current lon and lat to resolve
// ambiguities when going from a wider tile to a narrower one above or
return result;
}
-
+#endif
// calculate the offset between two buckets
void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector<SGBucket>& list ) {
double lon, lat, span;
- for (lat = min.getLatitudeDeg(); lat <= max.getLatitudeDeg(); lat += SG_BUCKET_SPAN) {
+ for (lat = min.getLatitudeDeg(); lat < max.getLatitudeDeg()+SG_BUCKET_SPAN; lat += SG_BUCKET_SPAN) {
span = sg_bucket_span( lat );
for (lon = min.getLongitudeDeg(); lon <= max.getLongitudeDeg(); lon += span)
{
- SGBucket b(lon, lat);
+ SGBucket b(SGGeod::fromDeg(lon, lat));
if (!b.isValid()) {
continue;
}