As is traditional, a follow-up to my own posting of last week. Can
someone take a look at this please?
SGBucket::set_bucket(double dlon, double dlat) has some bugs,
especially evident at high latitudes. For example, try this test,
which consists of 3 closely-spaced points:
SGBucket b1(-179.5, 87.5);
printf("b1: lon = %d, lat = %d\n", b1.get_chunk_lon(), b1.get_chunk_lat());
SGBucket b2(-179.0, 87.5);
printf("b2: lon = %d, lat = %d\n", b2.get_chunk_lon(), b2.get_chunk_lat());
SGBucket b3(-178.5, 87.5);
printf("b3: lon = %d, lat = %d\n", b3.get_chunk_lon(), b3.get_chunk_lat());
The output will be:
b1: lon = -180, lat = 87
b2: lon = -176, lat = 87
b3: lon = -180, lat = 87
Both b1 and b3 are correctly placed in the same chunk. However, b2,
which is in-between, is placed in a different chunk!
I've checked the code for set_bucket(), but I don't really understand
it. I wrote a replacement, given below. I've done many tests; where
they disagreed, my routine has been correct. This is not proof of
course, and I encourage people to check it for errors. In any case,
it is clear that we need to fix the current set_bucket().
Note that my routine differs in two other ways from the current
set_bucket():
(1) It sets cx and cy (the centre of the bucket).
Right now these member variables are unused in SGBucket. Setting
them in set_bucket() seems like a good thing to do, because it's
easy to do there, and we can then change get_center_lon() and
get_center_lat() to much simpler routines:
inline double get_center_lon() const { return cx; }
inline double get_center_lat() const { return cy; }
If we do decide to use and set cx and cy, then we would also need
to add code to the end of
SGBucket::SGBucket(const long int bindex)
to initialize cx and xy:
// Calculate the center of the bucket.
double span = sg_bucket_span(lat);
cx = lon + (x * span) + (span / 2.0);
cy = lat + (y * SG_BUCKET_SPAN) + SG_HALF_BUCKET_SPAN;
(2) It never lets a bucket cross the line of +/-180 degrees longitude.
Dealing with the +/-180 degree line is tricky. Unless you are
very very careful, it'll get you. For example, if your scenery
crosses +/-180, then lon + 1.0 is not always greater than lon
(179.5 + 1.0 = -179.5).
A quick check through the Terragear code indicates that, for
example, BuildTiles/Main/main.cxx makes this mistake in
actual_load_landcover() (I haven't run a test to confirm this, so
don't kill me if I'm wrong).
In any case, it's much better to never cross +/-180, which ensures
that you never have to be careful in the first place.
This makes my set_bucket() differ from the current set_bucket()
for the last two "rows" at the poles, when the bucket span is 8
degrees and 360 degrees, so tile naming will change in those
areas. This will cause temporary disruption, but I think it will
be minimal, since people rarely fly there.
Now the routine:
void set_bucket(double dlon, double dlat)
{
double span = sg_bucket_span(dlat);
// Note: the span always divides into 360.0, but not 180.0 (ie,
// when the span is 8.0).
double diff = fmod(dlon + 180.0, span);
// Calculate the lat, lon of the chunk.
lon = floor(dlon - diff);
lat = floor(dlat);
// Get our subdivision in the chunk.
x = 0;
if (span < 1.0) {
x = floor((dlon - lon) / span);
}
y = floor((dlat - lat) / SG_BUCKET_SPAN);
// Calculate the center of the bucket.
cx = lon + (x * span) + (span / 2.0);
cy = lat + (y * SG_BUCKET_SPAN) + SG_HALF_BUCKET_SPAN;
}
I should also add that the documentation for get_corner() says that it
returns the *center* of the bucket, which is wrong. It might be a
good idea to explain what the 'num' parameter is really supposed to
do. Here's what I think it does:
num == 0 -> return SW corner
num == 1 -> return SE corner
num == 2 -> return NE corner
num == 3 -> return NW corner
--
Brian Schack
19 Xǔchāng Street 2Fphone: 2381 4727
Taipei 100 fax:2381 2145
TAIWAN
--
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
___
Flightgear-devel mailing list
Flightgear-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/flightgear-devel