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; } (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, 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 2F phone: 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