Skip to content
Browse files

Remove antimeridian-polar cuts.

See #49.

The threshold had to be rather low, 1e-2, for this to work with
world-atlas.
  • Loading branch information...
1 parent a18d629 commit 3902ee86a1a12b599f5cdf7d62acfcded7d1095a @jasondavies jasondavies committed Mar 22, 2013
Showing with 93 additions and 4 deletions.
  1. +1 −1 examples/world-110m.json
  2. +1 −1 examples/world-50m.json
  3. +52 −2 lib/topojson/topology.js
  4. +39 −0 test/topology-test.js
View
2 examples/world-110m.json
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
2 examples/world-50m.json
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
54 lib/topojson/topology.js
@@ -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;
View
39 test/topology-test.js
@@ -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]]});
}
}
});

0 comments on commit 3902ee8

Please sign in to comment.
Something went wrong with that request. Please try again.