Merge pull request #361 from sdikiy/patch-1

accurate calculation of the centroid for small objects with large coordinates (p=sdikiy,r=marcjansen,sbrunner)
This commit is contained in:
Marc Jansen
2012-04-03 11:58:57 -07:00
2 changed files with 35 additions and 12 deletions

View File

@@ -198,15 +198,26 @@ 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 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);
}
var x0 = this.components[0].x;
var y0 = this.components[0].y;
var area = -1 * this.getArea();
var x = sumX / (6 * area);
var y = 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;

View File

@@ -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);
}