Commit b89c2d97 authored by Jason Davies's avatar Jason Davies
Browse files

Fix clipExtent bug.

If a polygon does not intersect with the extent, but has one or more
rings inside the extent, then the extent should be checked to see
whether it is inside the polygon: if so, an additional exterior ring is
generated.

Previously, this check was only made if there were no visible rings at
all.

Fixes an issue noticed in #1453.
parent 7bb322f6
......@@ -3050,19 +3050,22 @@ d3 = function() {
},
polygonEnd: function() {
listener = listener_;
if ((segments = d3.merge(segments)).length) {
listener.polygonStart();
d3_geo_clipPolygon(segments, compare, inside, interpolate, listener);
listener.polygonEnd();
} else if (insidePolygon([ x0, y0 ])) {
listener.polygonStart(), listener.lineStart();
segments = d3.merge(segments);
var inside = clean && insidePolygon([ x0, y0 ]), visible = segments.length;
if (inside || visible) listener.polygonStart();
if (inside) {
listener.lineStart();
interpolate(null, null, 1, listener);
listener.lineEnd(), listener.polygonEnd();
listener.lineEnd();
}
if (visible) {
d3_geo_clipPolygon(segments, compare, pointInside, interpolate, listener);
}
if (inside || visible) listener.polygonEnd();
segments = polygon = ring = null;
}
};
function inside(point) {
function pointInside(point) {
var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]);
return i;
}
......@@ -3094,17 +3097,17 @@ d3 = function() {
listener.point(to[0], to[1]);
}
}
function visible(x, y) {
function pointVisible(x, y) {
return x0 <= x && x <= x1 && y0 <= y && y <= y1;
}
function point(x, y) {
if (visible(x, y)) listener.point(x, y);
if (pointVisible(x, y)) listener.point(x, y);
}
var x__, y__, v__, x_, y_, v_, first;
var x__, y__, v__, x_, y_, v_, first, clean;
function lineStart() {
clip.point = linePoint;
if (polygon) polygon.push(ring = []);
first = true;
first = clean = true;
v_ = false;
x_ = y_ = NaN;
}
......@@ -3120,7 +3123,7 @@ d3 = function() {
function linePoint(x, y) {
x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
var v = visible(x, y);
var v = pointVisible(x, y);
if (polygon) ring.push([ x, y ]);
if (first) {
x__ = x, y__ = y, v__ = v;
......@@ -3139,9 +3142,11 @@ d3 = function() {
}
listener.point(b[0], b[1]);
if (!v) listener.lineEnd();
clean = false;
} else if (v) {
listener.lineStart();
listener.point(x, y);
clean = false;
}
}
}
......
This diff is collapsed.
......@@ -46,20 +46,24 @@ function d3_geo_clipExtent(x0, y0, x1, y1) {
},
polygonEnd: function() {
listener = listener_;
if ((segments = d3.merge(segments)).length) {
listener.polygonStart();
d3_geo_clipPolygon(segments, compare, inside, interpolate, listener);
listener.polygonEnd();
} else if (insidePolygon([x0, y0])) {
listener.polygonStart(), listener.lineStart();
segments = d3.merge(segments);
var inside = clean && insidePolygon([x0, y0]),
visible = segments.length;
if (inside || visible) listener.polygonStart();
if (inside) {
listener.lineStart();
interpolate(null, null, 1, listener);
listener.lineEnd(), listener.polygonEnd();
listener.lineEnd();
}
if (visible) {
d3_geo_clipPolygon(segments, compare, pointInside, interpolate, listener);
}
if (inside || visible) listener.polygonEnd();
segments = polygon = ring = null;
}
};
function inside(point) {
function pointInside(point) {
var a = corner(point, -1),
i = insidePolygon([a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0]);
return i;
......@@ -101,22 +105,23 @@ function d3_geo_clipExtent(x0, y0, x1, y1) {
}
}
function visible(x, y) {
function pointVisible(x, y) {
return x0 <= x && x <= x1 && y0 <= y && y <= y1;
}
function point(x, y) {
if (visible(x, y)) listener.point(x, y);
if (pointVisible(x, y)) listener.point(x, y);
}
var x__, y__, v__, // first point
x_, y_, v_, // previous point
first;
first,
clean;
function lineStart() {
clip.point = linePoint;
if (polygon) polygon.push(ring = []);
first = true;
first = clean = true;
v_ = false;
x_ = y_ = NaN;
}
......@@ -137,7 +142,7 @@ function d3_geo_clipExtent(x0, y0, x1, y1) {
function linePoint(x, y) {
x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
var v = visible(x, y);
var v = pointVisible(x, y);
if (polygon) ring.push([x, y]);
if (first) {
x__ = x, y__ = y, v__ = v;
......@@ -158,9 +163,11 @@ function d3_geo_clipExtent(x0, y0, x1, y1) {
}
listener.point(b[0], b[1]);
if (!v) listener.lineEnd();
clean = false;
} else if (v) {
listener.lineStart();
listener.point(x, y);
clean = false;
}
}
}
......
......@@ -2,7 +2,7 @@ var fs = require("fs"),
d3 = require("../../");
var formatNumber = d3.format(",.02r"),
projection = d3.geo.stereographic().clipAngle(150),
projection = d3.geo.stereographic().clipAngle(150).clipExtent([[0, 0], [960, 500]]),
path = d3.geo.path().projection(projection),
graticule = d3.geo.graticule().step([1, 1]),
circle = d3.geo.circle().angle(30),
......
......@@ -109,6 +109,40 @@ suite.addBatch({
assert.isTrue(stream.valid);
clip.extent([[0, 0], [960, 500]]);
assert.isFalse(stream.valid);
},
"a polygon that encloses the extent, with a hole": function(d3) {
var clip = d3.geo.clipExtent().extent([[1, 1], [9, 9]]),
stream = clip.stream(testContext);
stream.polygonStart();
stream.lineStart();
stream.point(0, 0);
stream.point(10, 0);
stream.point(10, 10);
stream.point(0, 10);
stream.lineEnd();
stream.lineStart();
stream.point(4, 4);
stream.point(4, 6);
stream.point(6, 6);
stream.point(6, 4);
stream.lineEnd();
stream.polygonEnd();
assert.deepEqual(testContext.buffer(), [
{type: "polygonStart"},
{type: "lineStart"},
{type: "point", x: 1, y: 1},
{type: "point", x: 9, y: 1},
{type: "point", x: 9, y: 9},
{type: "point", x: 1, y: 9},
{type: "lineEnd"},
{type: "lineStart"},
{type: "point", x: 4, y: 4},
{type: "point", x: 4, y: 6},
{type: "point", x: 6, y: 6},
{type: "point", x: 6, y: 4},
{type: "lineEnd"},
{type: "polygonEnd"}
]);
}
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment