Skip to content

Commit

Permalink
Remove antimeridian-polar cuts.
Browse files Browse the repository at this point in the history
See #49.

The threshold had to be rather low, 1e-2, for this to work with
world-atlas.
  • Loading branch information
jasondavies committed Mar 22, 2013
1 parent a18d629 commit 3902ee8
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
2 changes: 1 addition & 1 deletion examples/world-110m.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/world-50m.json

Large diffs are not rendered by default.

54 changes: 52 additions & 2 deletions lib/topojson/topology.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,59 @@ module.exports = function(objects, options) {
if (!system) { system = systems[oversize ? "cartesian" : "spherical"]; if (options) options["coordinate-system"] = system.name; }
if (system === systems.spherical && oversize) throw new Error("spherical coordinates outside of [±180°, ±90°]");

// When near the spherical coordinate limits, clamp to nice round values.
// This avoids quantized coordinates that are slightly outside the limits.
// Remove polar antimeridian cuts, i.e. all sequences:
// [±180°, *]+, [*, ±90°]+, [±180, *]+.
if (system === systems.spherical) {
each({
polygon: function(polygon) {
for (var j = 0, m = polygon.length; j < m; ++j) {
var line = polygon[j],
i = -1,
n = line.length,
a = false,
b = false,
c = false,
i0 = -1;
for (i = 0; i < n; ++i) {
var point = line[i],
antimeridian = Math.abs(Math.abs(point[0]) - 180) < 1e-2,
polar = Math.abs(Math.abs(point[1]) - 90) < 1e-2;
if (antimeridian || polar) {
if (!(a || b || c)) i0 = i;
if (antimeridian) {
if (a) c = true;
else a = true;
}
if (polar) b = true;
}
if (!antimeridian && !polar || i === n - 1) {
if (a && b && c) {
line.splice(i0, i - i0);
n -= i - i0;
i = i0;
}
a = b = c = false;
}
}
}
}
});

// Recompute bounding box.
x1 = y1 = -(x0 = y0 = Infinity);
each({
point: function(point) {
var x = point[0],
y = point[1];
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
});

// When near the spherical coordinate limits, clamp to nice round values.
// This avoids quantized coordinates that are slightly outside the limits.
if (x0 < -180 + ε) x0 = -180;
if (x1 > 180 - ε) x1 = 180;
if (y0 < -90 + ε) y0 = -90;
Expand Down
39 changes: 39 additions & 0 deletions test/topology-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,45 @@ suite.addBatch({
]);
assert.deepEqual(topology.objects.abe, {type: "LineString", arcs: [0, 1]});
assert.deepEqual(topology.objects.bcdb, {type: "Polygon", arcs: [[2]]});
},

//
// A-----B-----C-----D-----E
// | |
// | |
// J-----I-----H-----G-----F
"a polygon surrounding the South pole with a cut along the antimeridian": function() {
var topology = topojson.topology({
polygon: {type: "Polygon", coordinates: [[
[-180, -80], [-90, -80], [0, -80], [90, -80], [180, -80],
[180, -90], [90, -90], [0, -90], [-90, -90], [-180, -90],
[-180, -80]
]]}}, {quantization: 4});
assert.deepEqual(topology.arcs, [
[[0, 0], [1, 0], [1, 0], [1, 0], [-3, 0]]
]);
assert.deepEqual(topology.objects.polygon, {type: "Polygon", arcs: [[0]]});
},

//
// B-----C-----D-----E-----F
// | |
// | |
// A G
// | |
// | |
// L-----K-----J-----I-----H
"a large polygon surrounding the South pole with a cut along the antimeridian": function() {
var topology = topojson.topology({
polygon: {type: "Polygon", coordinates: [[
[-180, -85], [-180, -80], [-90, -80], [0, -80], [90, -80], [180, -80],
[180, -85], [180, -90], [90, -90], [0, -90], [-90, -90], [-180, -90],
[-180, -85]
]]}}, {quantization: 4});
assert.deepEqual(topology.arcs, [
[[0, 0], [0, 3], [1, 0], [1, 0], [1, 0], [-3, -3]]
]);
assert.deepEqual(topology.objects.polygon, {type: "Polygon", arcs: [[0]]});
}
}
});
Expand Down

0 comments on commit 3902ee8

Please sign in to comment.