Better handling of ambiguous centroids.

Rather than doing something like picking the last seen point, return
an undefined centroid if it is ambiguous.

Users can decide what to do, e.g. when picking an origin for a rotating
globe, using the last coordinate in a MultiPoint or LineString seems
reasonable in an ambiguous situation.
This commit is contained in:
Jason Davies 2012-12-13 12:48:36 +00:00
Родитель b87bcbc22a
Коммит 3d84b49ae4
4 изменённых файлов: 30 добавлений и 12 удалений

5
d3.js поставляемый
Просмотреть файл

@ -5891,7 +5891,10 @@
d3.geo.centroid = function(object) { d3.geo.centroid = function(object) {
d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
d3.geo.stream(object, d3_geo_centroid); d3.geo.stream(object, d3_geo_centroid);
return d3_geo_centroidW ? [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)))) * d3_degrees ] : null; var m;
if (d3_geo_centroidW && Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) {
return [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees ];
}
}; };
var d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ; var d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ;
var d3_geo_centroid = { var d3_geo_centroid = {

2
d3.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,12 +1,15 @@
d3.geo.centroid = function(object) { d3.geo.centroid = function(object) {
d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
d3.geo.stream(object, d3_geo_centroid); d3.geo.stream(object, d3_geo_centroid);
// TODO fallback to [0, 0] e.g. for sphere, equator?
// TODO mixed geometries // TODO mixed geometries
return d3_geo_centroidW ? [ var m;
Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, if (d3_geo_centroidW &&
Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)))) * d3_degrees Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) {
] : null; return [
Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees,
Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees
];
}
}; };
var d3_geo_centroidW, var d3_geo_centroidW,

Просмотреть файл

@ -13,9 +13,21 @@ suite.addBatch({
"Point": function(centroid) { "Point": function(centroid) {
assert.deepEqual(centroid({type: "Point", coordinates: [0, 0]}), [0, 0]); assert.deepEqual(centroid({type: "Point", coordinates: [0, 0]}), [0, 0]);
}, },
"MultiPoint": function(centroid) { "MultiPoint": {
assert.inDelta(centroid({type: "MultiPoint", coordinates: [[0, 0], [1, 2]]}), [0.499847, 1.000038], 1e-6); "": function(centroid) {
assert.deepEqual(centroid({type: "MultiPoint", coordinates: [[179, 0], [-179, 0]]}), [180, 0]); assert.inDelta(centroid({type: "MultiPoint", coordinates: [[0, 0], [1, 2]]}), [0.499847, 1.000038], 1e-6);
},
"antimeridian": function(centroid) {
assert.deepEqual(centroid({type: "MultiPoint", coordinates: [[179, 0], [-179, 0]]}), [180, 0]);
},
"rings": {
"equator": function(centroid) {
assert.isUndefined(centroid({type: "MultiPoint", coordinates: [[0, 0], [90, 0], [180, 0], [-90, 0]]}));
},
"polar": function(centroid) {
assert.isUndefined(centroid({type: "MultiPoint", coordinates: [[0, 0], [0, 90], [180, 0], [0, -90]]}));
}
}
}, },
"LineString": function(centroid) { "LineString": function(centroid) {
assert.inDelta(centroid({type: "LineString", coordinates: [[0, 0], [1, 0]]}), [.5, 0], 1e-6); assert.inDelta(centroid({type: "LineString", coordinates: [[0, 0], [1, 0]]}), [.5, 0], 1e-6);
@ -25,8 +37,8 @@ suite.addBatch({
assert.inDelta(centroid({type: "LineString", coordinates: [[-60, -1], [60, 1]]}), [0, 0], 1e-6); assert.inDelta(centroid({type: "LineString", coordinates: [[-60, -1], [60, 1]]}), [0, 0], 1e-6);
assert.inDelta(centroid({type: "LineString", coordinates: [[179, -1], [-179, 1]]}), [180, 0], 1e-6); assert.inDelta(centroid({type: "LineString", coordinates: [[179, -1], [-179, 1]]}), [180, 0], 1e-6);
assert.inDelta(centroid({type: "LineString", coordinates: [[-179, 0], [0, 0], [179, 0]]}), [0, 0], 1e-6); assert.inDelta(centroid({type: "LineString", coordinates: [[-179, 0], [0, 0], [179, 0]]}), [0, 0], 1e-6);
assert.inDelta(centroid({type: "LineString", coordinates: [[0, -90], [0, 90]]}), [0, 0], 1e-6); assert.inDelta(centroid({type: "LineString", coordinates: [[-180, -90], [0, 0], [0, 90]]}), [0, 0], 1e-6);
assert.inDelta(centroid({type: "LineString", coordinates: [[-180, -90], [0, 90]]}), [-90, 0], 1e-6); assert.isUndefined(centroid({type: "LineString", coordinates: [[0, -90], [0, 90]]}));
}, },
"MultiLineString": function(centroid) { "MultiLineString": function(centroid) {
assert.inDelta(centroid({type: "MultiLineString", coordinates: [[[0, 0], [0, 2]]]}), [0, 1], 1e-6); assert.inDelta(centroid({type: "MultiLineString", coordinates: [[[0, 0], [0, 2]]]}), [0, 1], 1e-6);