+// return width of the tile in degrees
+double SGBucket::get_width() const {
+ return sg_bucket_span( get_center_lat() );
+}
+
+
+// return height of the tile in degrees
+double SGBucket::get_height() const {
+ return SG_BUCKET_SPAN;
+}
+
+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;
+ }
+
+ 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;
+
+ return get_width() * degree_width;
+}
+
+
+// return height of the tile in meters
+double SGBucket::get_height_m() const {
+ double perimeter = SG_EQUATORIAL_RADIUS_M * SGD_2PI;
+ double degree_height = perimeter / 360.0;
+
+ return SG_BUCKET_SPAN * degree_height;
+}
+
+unsigned int SGBucket::siblings( int dx, int dy, std::vector<SGBucket>& buckets ) const
+{
+ if (!isValid()) {
+ SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::sibling: requesting sibling of invalid bucket");
+ return 0;
+ }
+
+ double src_span = sg_bucket_span( get_center_lat() );
+
+ double clat = get_center_lat() + dy * SG_BUCKET_SPAN;
+ // return invalid here instead of clipping, so callers can discard
+ // invalid buckets without having to check if it's an existing one
+ if ((clat < -90.0) || (clat > 90.0)) {
+ return 0;
+ }
+
+ // find the lon span for the new latitude
+ double trg_span = sg_bucket_span( clat );
+
+ // if target span < src_span, return multiple buckets...
+ if ( trg_span < src_span ) {
+ // calc center longitude of westernmost sibling
+ double start_lon = get_center_lat() - src_span/2 + trg_span/2;
+
+ unsigned int num_buckets = src_span/trg_span;
+ for ( unsigned int x = 0; x < num_buckets; x++ ) {
+ double tmp = start_lon + x * trg_span;
+ tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
+
+ SGBucket b;
+ b.innerSet(tmp, clat);
+
+ buckets.push_back( b );
+ }
+ } else {
+ // just return the single sibling
+ double tmp = get_center_lon() + dx * trg_span;
+ tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
+
+ SGBucket b;
+ b.innerSet(tmp, clat);
+
+ buckets.push_back( b );
+ }
+
+ return buckets.size();
+}
+
+SGBucket SGBucket::sibling(int dx, int dy) const
+{
+ if (!isValid()) {
+ SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::sibling: requesting sibling of invalid bucket");
+ return SGBucket();
+ }
+
+ double clat = get_center_lat() + dy * SG_BUCKET_SPAN;
+ // return invalid here instead of clipping, so callers can discard
+ // invalid buckets without having to check if it's an existing one
+ if ((clat < -90.0) || (clat > 90.0)) {
+ return SGBucket();
+ }
+
+ // find the lon span for the new latitude
+ double span = sg_bucket_span( clat );
+
+ double tmp = get_center_lon() + dx * span;
+ tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
+
+ SGBucket b;
+ b.innerSet(tmp, clat);
+ return b;
+}
+
+std::string SGBucket::gen_index_str() const
+{
+ char tmp[20];
+ ::snprintf(tmp, 20, "%ld",
+ (((long)lon + 180) << 14) + ((lat + 90) << 6)
+ + (y << 3) + x);
+ return (std::string)tmp;
+}
+
+#ifndef NO_DEPRECATED_API