Fix #1951 by rounding all floats passed to Bounds.initialize() and

LonLat.initialize() to 14 significant figures.

Added an OpenLayers.Util.toFloat() function, and changed the LonLat constructor
and the Bounds constructor to truncate all float parameters to 14 significant
figures to avoid numeric comparison errors caused by floating point precision
loss. See the comments around the definition of
OpenLayers.Util.DEFAULT_PRECISION for how it works.

Also refactored Bounds.intersectBounds() for readability, and added a
Bounds.touchesBounds() in the process. After tweaking the tests for
Layer.SphericalMercator and Format.WKT (because they were expecting too many
significant figures), all tests pass.



git-svn-id: http://svn.openlayers.org/trunk/openlayers@9022 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Schuyler Erle
2009-03-11 22:45:32 +00:00
parent 9afcb939be
commit e89774d568
8 changed files with 135 additions and 59 deletions

View File

@@ -4,7 +4,7 @@
<script type="text/javascript">
var bounds;
function test_Bounds_constructor (t) {
t.plan( 17 );
t.plan( 21 );
bounds = new OpenLayers.Bounds();
t.ok( bounds instanceof OpenLayers.Bounds, "new OpenLayers.Bounds returns Bounds object" );
@@ -36,6 +36,14 @@
var center = new OpenLayers.LonLat(5,3);
var boundsCenter = bounds.getCenterLonLat();
t.ok( boundsCenter.equals(center), "bounds.getCenterLonLat() has correct value" );
// This is an actual use case with Mercator projection at global scale
bounds = new OpenLayers.Bounds(-40075016.67999999,-20037508.339999992,
40075016.67999999,20037508.339999992);
t.eq( bounds.left, -40075016.68, "bounds.left adjusted for floating precision");
t.eq( bounds.bottom, -20037508.34, "bounds.bottom adjusted for floating precision");
t.eq( bounds.right, 40075016.68, "bounds.right adjusted for floating precision");
t.eq( bounds.top, 20037508.34, "bounds.top adjusted for floating precision");
}
function test_Bounds_constructorFromStrings(t) {
@@ -91,13 +99,13 @@
var ring = poly.components[0];
t.eq(ring.components.length, 5,
"four sided polygon created");
t.eq(ring.components[0].x, minx,
t.eq(ring.components[0].x, OpenLayers.Util.toFloat(minx),
"bounds left preserved");
t.eq(ring.components[0].y, miny,
t.eq(ring.components[0].y, OpenLayers.Util.toFloat(miny),
"bounds bottom preserved");
t.eq(ring.components[2].x, maxx,
t.eq(ring.components[2].x, OpenLayers.Util.toFloat(maxx),
"bounds left preserved");
t.eq(ring.components[2].y, maxy,
t.eq(ring.components[2].y, OpenLayers.Util.toFloat(maxy),
"bounds bottom preserved");
}
@@ -157,7 +165,7 @@
}
function test_Bounds_intersectsBounds(t) {
t.plan( 17 );
t.plan( 19 );
var aBounds = new OpenLayers.Bounds(-180, -90, 180, 90);
@@ -194,6 +202,13 @@
t.eq( aBounds.intersectsBounds(bBounds, true), false, "(" + aBounds.toBBOX() + ") does not intersect (" + bBounds.toBBOX() + "), inclusive is true" );
t.eq( aBounds.intersectsBounds(bBounds, false), false, "(" + aBounds.toBBOX() + ") does not intersect (" + bBounds.toBBOX() + "), inclusive is false" );
// This is an actual use case with Mercator tiles at global scale
var merc_aBounds = new OpenLayers.Bounds(-40075016.67999999,20037508.339999992,
-20037508.339999992,40075016.67999999),
merc_bBounds = new OpenLayers.Bounds(-20037508.34,-20037508.34,
20037508.34,20037508.34);
t.eq( merc_aBounds.intersectsBounds(merc_bBounds, true), true, "intersect shouldn't fall prey to floating point errors, inclusive is true");
t.eq( merc_aBounds.intersectsBounds(merc_bBounds, false), false, "intersect shouldn't fall prey to floating point errors, inclusive is false");
}
function test_Bounds_containsBounds(t) {
@@ -282,7 +297,7 @@
var boundsA = new OpenLayers.Bounds(1,2,3,4);
var boundsB = new OpenLayers.Bounds(1,2,3,4);
var boundsC = new OpenLayers.Bounds(1,5,3,4);
t.ok( boundsA.equals(boundsB), "equals() returns true on two equal bounds." );
t.ok( !boundsA.equals(boundsC), "equals() returns false on two different bounds." );
t.ok( !boundsA.equals(null), "equals() returns false on comparison to null");

View File

@@ -6,12 +6,17 @@
var lonlat;
function test_LonLat_constructor (t) {
t.plan( 4 );
t.plan( 6 );
lonlat = new OpenLayers.LonLat(6, 5);
t.ok( lonlat instanceof OpenLayers.LonLat, "new OpenLayers.LonLat returns LonLat object" );
t.eq( lonlat.CLASS_NAME, "OpenLayers.LonLat", "lonlat.CLASS_NAME is set correctly");
t.eq( lonlat.lon, 6, "lonlat.lon is set correctly");
t.eq( lonlat.lat, 5, "lonlat.lat is set correctly");
// possible global Mercator projection values
lonlat = new OpenLayers.LonLat(20037508.33999999, -20037508.33999999);
t.eq( lonlat.lon, 20037508.34, "lonlat.lon rounds correctly");
t.eq( lonlat.lat, -20037508.34, "lonlat.lat rounds correctly");
}
function test_LonLat_constructorFromStrings (t) {

View File

@@ -226,7 +226,7 @@
var points = {
src: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(-87.9, 41.9)),
dest: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(-9784983.239366667, 5146011.678566458))
dest: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(-9784983.2393667, 5146011.6785665))
};
var format = new OpenLayers.Format.WKT({

View File

@@ -38,8 +38,8 @@
t.eq(sw.lon, -180, "Southwest lon correct");
t.eq(ne.lon, 180, "Northeast lon correct");
t.eq(sw.lat, -85.05112877980659, "Southwest lat correct");
t.eq(ne.lat, 85.05112877980660, "Northeast lat correct");
t.eq(sw.lat, -85.051128779807, "Southwest lat correct");
t.eq(ne.lat, 85.051128779807, "Northeast lat correct");
}
function strToFixed(str, dig) {

View File

@@ -806,6 +806,16 @@
}
function test_toFloat(t) {
t.plan(2);
// actual possible computed Mercator tile coordinates, more or less
var a1=40075016.67999999, b1=-20037508.33999999,
a2=40075016.68, b2=-20037508.34;
t.eq(OpenLayers.Util.toFloat(a1), OpenLayers.Util.toFloat(a2),
"toFloat rounds large floats correctly #1");
t.eq(OpenLayers.Util.toFloat(b1), OpenLayers.Util.toFloat(b2),
"toFloat rounds large floats correctly #2");
}
</script>
</head>
<body>