+// default constructor
+SGBucket::SGBucket() {
+}
+
+
+// constructor for specified location
+SGBucket::SGBucket(const double dlon, const double dlat) {
+ set_bucket(dlon, dlat);
+}
+
+SGBucket::SGBucket(const SGGeod& geod) {
+ set_bucket(geod);
+}
+
+// create an impossible bucket if false
+SGBucket::SGBucket(const bool is_good) {
+ set_bucket(0.0, 0.0);
+ if ( !is_good ) {
+ lon = -1000;
+ }
+}
+
+
+// Parse a unique scenery tile index and find the lon, lat, x, and y
+SGBucket::SGBucket(const long int bindex) {
+ long int index = bindex;
+
+ lon = index >> 14;
+ index -= lon << 14;
+ lon -= 180;
+
+ lat = index >> 6;
+ index -= lat << 6;
+ lat -= 90;
+
+ y = index >> 3;
+ index -= y << 3;
+
+ x = index;
+}
+
+
+// Set the bucket params for the specified lat and lon
+void SGBucket::set_bucket( double *lonlat ) {
+ set_bucket( lonlat[0], lonlat[1] );
+}
+
+
+// Set the bucket params for the specified lat and lon
+void SGBucket::set_bucket( double dlon, double dlat ) {
+ //
+ // latitude first
+ //
+ double span = sg_bucket_span( dlat );
+ double diff = dlon - (double)(int)dlon;
+
+ // cout << "diff = " << diff << " span = " << span << endl;
+
+ /* Calculate the greatest integral longitude less than
+ * or equal to the given longitude (floor(dlon)),
+ * but attribute coordinates near the east border
+ * to the next tile.
+ */
+ if ( (dlon >= 0) || (fabs(diff) < SG_EPSILON) ) {
+ lon = (int)dlon;
+ } else {
+ lon = (int)dlon - 1;
+ }
+
+ // find subdivision or super lon if needed
+ if ( span < SG_EPSILON ) {
+ /* sg_bucket_span() never returns 0.0
+ * or anything near it, so this really
+ * should not occur at any time.
+ */
+ // polar cap
+ lon = 0;
+ x = 0;
+ } else if ( span <= 1.0 ) {
+ /* We have more than one tile per degree of
+ * longitude, so we need an x offset.
+ */
+ x = (int)((dlon - lon) / span);
+ } else {
+ /* We have one or more degrees per tile,
+ * so we need to find the base longitude
+ * of that tile.
+ *
+ * First we calculate the integral base longitude
+ * (e.g. -85.5 => -86) and then find the greatest
+ * multiple of span that is less than or equal to
+ * that longitude.
+ *
+ * That way, the Greenwich Meridian is always
+ * a tile border.
+ *
+ * This gets us into trouble with the polar caps,
+ * which have width 360 and thus either span
+ * the range from 0 to 360 or from -360 to 0
+ * degrees, depending on whether lon is positive
+ * or negative!
+ *
+ * We also get into trouble with the 8 degree tiles
+ * north of 88N and south of 88S, because the west-
+ * and east-most tiles in that range will cover 184W
+ * to 176W and 176E to 184E respectively, with their
+ * center at 180E/W!
+ */
+ lon=(int)floor(floor((lon+SG_EPSILON)/span)*span);
+ /* Correct the polar cap issue */
+ if ( lon < -180 ) {
+ lon = -180;
+ }
+ x = 0;
+ }
+
+ //
+ // then latitude
+ //
+ diff = dlat - (double)(int)dlat;
+
+ /* Again, a modified floor() function (see longitude) */
+ if ( (dlat >= 0) || (fabs(diff) < SG_EPSILON) ) {
+ lat = (int)dlat;
+ } else {
+ lat = (int)dlat - 1;
+ }
+ /* Latitude base and offset are easier, as
+ * tiles always are 1/8 degree of latitude wide.
+ */
+ y = (int)((dlat - lat) * 8);
+}
+
+
+void SGBucket::set_bucket(const SGGeod& geod)
+{
+ set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
+}
+