import “../arrays/merge”; import “../math/trigonometry”; import “clip”; import “clip-polygon”;
var d3_geo_clipViewMAX = 1e9;
function d3_geo_clipView(x0, y0, x1, y1) {
return function(listener) { var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; var clip = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { listener = bufferListener; segments = []; polygon = []; }, 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(); interpolate(null, null, 1, listener); listener.lineEnd(), listener.polygonEnd(); } segments = polygon = ring = null; } }; function inside(point) { var a = corner(point, -1), i = insidePolygon([a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0]); return i; } function insidePolygon(p) { var wn = 0, // the winding number counter n = polygon.length, y = p[1]; for (var i = 0; i < n; ++i) { for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { b = v[j]; if (a[1] <= y) { if (b[1] > y && isLeft(a, b, p) > 0) ++wn; } else { if (b[1] <= y && isLeft(a, b, p) < 0) --wn; } a = b; } } return wn !== 0; } function isLeft(a, b, c) { return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); } function interpolate(from, to, direction, listener) { var a = 0, a1 = 0; if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { do { listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); } while ((a = (a + direction + 4) % 4) !== a1); } else { listener.point(to[0], to[1]); } } function visible(x, y) { return x0 <= x && x <= x1 && y0 <= y && y <= y1; } function point(x, y) { if (visible(x, y)) listener.point(x, y); } var x__, y__, v__, // first point x_, y_, v_, // previous point first; function lineStart() { clip.point = linePoint; if (polygon) polygon.push(ring = []); first = true; v_ = false; x_ = y_ = NaN; } function lineEnd() { // TODO rather than special-case polygons, simply handle them separately. // Ideally, coincident intersection points should be jittered to avoid // clipping issues. if (segments) { linePoint(x__, y__); if (v__ && v_) bufferListener.rejoin(); segments.push(bufferListener.buffer()); } clip.point = point; if (v_) listener.lineEnd(); } function linePoint(x, y) { x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); var v = visible(x, y); if (polygon) ring.push([x, y]); if (first) { x__ = x, y__ = y, v__ = v; first = false; if (v) { listener.lineStart(); listener.point(x, y); } } else { if (v && v_) listener.point(x, y); else { var a = [x_, y_], b = [x, y]; if (clipLine(a, b)) { if (!v_) { listener.lineStart(); listener.point(a[0], a[1]); } listener.point(b[0], b[1]); if (!v) listener.lineEnd(); } else if (v) { listener.lineStart(); listener.point(x, y); } } } x_ = x, y_ = y, v_ = v; } return clip; }; function corner(p, direction) { return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; // Math.abs(p[1] - y1) < ε } function compare(a, b) { return comparePoints(a.point, b.point); } function comparePoints(a, b) { var ca = corner(a, 1), cb = corner(b, 1); return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; } // Liang–Barsky line clipping. function clipLine(a, b) { var dx = b[0] - a[0], dy = b[1] - a[1], t = [0, 1]; if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { if (t[1] < 1) { b[0] = a[0] + t[1] * dx; b[1] = a[1] + t[1] * dy; } if (t[0] > 0) { a[0] += t[0] * dx; a[1] += t[0] * dy; } return true; } return false; }
}
function d3_geo_clipViewT(num, denominator, t) {
if (Math.abs(denominator) < ε) return num <= 0; var u = num / denominator; if (denominator > 0) { if (u > t[1]) return false; if (u > t[0]) t[0] = u; } else { if (u < t[0]) return false; if (u < t[1]) t[1] = u; } return true;
}