X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fbucket%2Fnewbucket.cxx;h=97b09490208aaa4f4df4ffd9f3313e6f540a10b2;hb=6672a1212cfccb2a08be21ff5271eae9b6f91b2a;hp=1e59205a255f6ba3c1981ce6c9965f614c7240a2;hpb=574d459f4ecf400e8eac762a910a71597fe35321;p=simgear.git diff --git a/simgear/bucket/newbucket.cxx b/simgear/bucket/newbucket.cxx index 1e59205a..97b09490 100644 --- a/simgear/bucket/newbucket.cxx +++ b/simgear/bucket/newbucket.cxx @@ -28,6 +28,7 @@ #endif #include +#include // some platforms need this for ::snprintf #include #include @@ -63,14 +64,17 @@ void SGBucket::make_bad() 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 @@ -98,16 +102,26 @@ SGBucket::SGBucket(const long int bindex) { */ static int floorWithEpsilon(double x) { - double diff = x - static_cast(x); - if ( (x >= 0.0) || (fabs(diff) < SG_EPSILON) ) { - return static_cast(x); - } else { - return static_cast(x) - 1; - } + return static_cast(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); @@ -133,7 +147,7 @@ void SGBucket::set_bucket( double dlon, double dlat ) /* 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 @@ -166,15 +180,10 @@ void SGBucket::set_bucket( double dlon, double dlat ) /* 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; @@ -214,7 +223,7 @@ std::string SGBucket::gen_base_path() const { 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); @@ -235,17 +244,32 @@ double SGBucket::get_height() const { 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; @@ -262,6 +286,54 @@ double SGBucket::get_height_m() const { return SG_BUCKET_SPAN * degree_height; } +unsigned int SGBucket::siblings( int dx, int dy, std::vector& 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()) { @@ -281,7 +353,10 @@ SGBucket SGBucket::sibling(int dx, int dy) const 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 @@ -293,6 +368,7 @@ std::string SGBucket::gen_index_str() const 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 @@ -319,7 +395,7 @@ SGBucket sgBucketOffset( double dlon, double dlat, int dx, int dy ) { return result; } - +#endif // calculate the offset between two buckets void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) { @@ -380,11 +456,11 @@ void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) { void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector& 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; }