From 8c93d477ba9bb4746c4c2bb2f68d3afab0810bee Mon Sep 17 00:00:00 2001 From: sdikiy Date: Tue, 27 Mar 2012 16:12:31 +0300 Subject: [PATCH 1/3] accurate calculation of the centroid for small objects with large coordinates --- lib/OpenLayers/Geometry/LinearRing.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/OpenLayers/Geometry/LinearRing.js b/lib/OpenLayers/Geometry/LinearRing.js index 0a717aabe6..d94448ca6c 100644 --- a/lib/OpenLayers/Geometry/LinearRing.js +++ b/lib/OpenLayers/Geometry/LinearRing.js @@ -198,15 +198,23 @@ OpenLayers.Geometry.LinearRing = OpenLayers.Class( } else if (len > 2) { var sumX = 0.0; var sumY = 0.0; - for (var i = 0; i < this.components.length - 1; i++) { + var averX = 0.0; + var averY = 0.0; + for (var i = 0; i < len; i++) { + averX += this.components[i].x; + averY += this.components[i].y; + } + averX = averX / len; + averY = averY / len; + for (var i = 0; i < len - 1; i++) { var b = this.components[i]; var c = this.components[i+1]; - sumX += (b.x + c.x) * (b.x * c.y - c.x * b.y); - sumY += (b.y + c.y) * (b.x * c.y - c.x * b.y); + sumX += (b.x + c.x - 2 * averX) * ((b.x - averX) * (c.y - averY) - (c.x - averX) * (b.y - averY)); + sumY += (b.y + c.y - 2 * averY) * ((b.x - averX) * (c.y - averY) - (c.x - averX) * (b.y - averY)); } var area = -1 * this.getArea(); - var x = sumX / (6 * area); - var y = sumY / (6 * area); + var x = averX + sumX / (6 * area); + var y = averY + sumY / (6 * area); return new OpenLayers.Geometry.Point(x, y); } else { return null; From 23301e10eae30a7043b7a5e85b37031bb2616434 Mon Sep 17 00:00:00 2001 From: sdikiy Date: Fri, 30 Mar 2012 16:52:29 +0300 Subject: [PATCH 2/3] add new test for getCentroid --- tests/Geometry/Polygon.html | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/Geometry/Polygon.html b/tests/Geometry/Polygon.html index e28484d36e..0df0295d4b 100644 --- a/tests/Geometry/Polygon.html +++ b/tests/Geometry/Polygon.html @@ -386,18 +386,30 @@ } - function testGetCentroid(t) { - t.plan(4); + function test_getCentroid(t) { + t.plan(5); var bounds = new OpenLayers.Bounds(5, 10, 5, 10); var geometry = bounds.toGeometry(); var centroid = geometry.getCentroid(); t.eq(geometry.components[0].components.length, 2, "only two vertices since the box has left=right and bottom=top"); t.ok(centroid && centroid.x === 5 && centroid.y === 10, "getCentroid returns a point geometry even if the ring of the polygon has only 2 vertices"); - bounds = new OpenLayers.Bounds(0, 0, 10, 10); + bounds = new OpenLayers.Bounds(123456789.0, 123456789.0, 123456789.1, 123456789.1); geometry = bounds.toGeometry(); centroid = geometry.getCentroid(); t.eq(geometry.components[0].components.length, 5, "five vertices expected"); - t.ok(centroid && centroid.x === 5 && centroid.y === 5, "getCentroid returns the correct point geometry"); + var dX = Math.abs(centroid.x - 123456789.05); + var dY = Math.abs(centroid.y - 123456789.05); + t.ok(centroid && dX < 0.0001 && dY < 0.0001, " getCentroid returns the correct point geometry dX = " + dX + ", dY = " + dY); + + var components = [ + new OpenLayers.Geometry.Point(0,0), new OpenLayers.Geometry.Point(1,1), + new OpenLayers.Geometry.Point(0,1), new OpenLayers.Geometry.Point(1,0)]; + var linearRing = new OpenLayers.Geometry.LinearRing(components); + polygon = new OpenLayers.Geometry.Polygon([linearRing.clone()]); + centroid = polygon.getCentroid(); + var tX = centroid.x; + var tY = centroid.y; + t.ok( !isNaN(tX) && !isNaN(tY) && tX !== Infinity && tY !== Infinity, " getCentroid for wrong polygon works x = " + tX + ", y = " + tY); } From 0460bd2ae8bafb8d585a43f4e2f86f7b724999d5 Mon Sep 17 00:00:00 2001 From: sdikiy Date: Fri, 30 Mar 2012 23:20:21 +0300 Subject: [PATCH 3/3] change getCentroid --- lib/OpenLayers/Geometry/LinearRing.js | 35 +++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/OpenLayers/Geometry/LinearRing.js b/lib/OpenLayers/Geometry/LinearRing.js index 127c739486..21b5375654 100644 --- a/lib/OpenLayers/Geometry/LinearRing.js +++ b/lib/OpenLayers/Geometry/LinearRing.js @@ -198,23 +198,26 @@ OpenLayers.Geometry.LinearRing = OpenLayers.Class( } else if (len > 2) { var sumX = 0.0; var sumY = 0.0; - var averX = 0.0; - var averY = 0.0; - for (var i = 0; i < len; i++) { - averX += this.components[i].x; - averY += this.components[i].y; - } - averX = averX / len; - averY = averY / len; - for (var i = 0; i < len - 1; i++) { - var b = this.components[i]; - var c = this.components[i+1]; - sumX += (b.x + c.x - 2 * averX) * ((b.x - averX) * (c.y - averY) - (c.x - averX) * (b.y - averY)); - sumY += (b.y + c.y - 2 * averY) * ((b.x - averX) * (c.y - averY) - (c.x - averX) * (b.y - averY)); - } + var x0 = this.components[0].x; + var y0 = this.components[0].y; var area = -1 * this.getArea(); - var x = averX + sumX / (6 * area); - var y = averY + sumY / (6 * area); + if (area != 0) { + for (var i = 0; i < len - 1; i++) { + var b = this.components[i]; + var c = this.components[i+1]; + sumX += (b.x + c.x - 2 * x0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0)); + sumY += (b.y + c.y - 2 * y0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0)); + } + var x = x0 + sumX / (6 * area); + var y = y0 + sumY / (6 * area); + } else { + for (var i = 0; i < len - 1; i++) { + sumX += this.components[i].x; + sumY += this.components[i].y; + } + var x = sumX / (len - 1); + var y = sumY / (len - 1); + } return new OpenLayers.Geometry.Point(x, y); } else { return null;