|
3047 | 3047 | }
|
3048 | 3048 | };
|
3049 | 3049 | }
|
3050 |
| - function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { |
3051 |
| - return function(sink) { |
3052 |
| - var line = clipLine(sink); |
3053 |
| - var clip = { |
3054 |
| - point: point, |
3055 |
| - lineStart: lineStart, |
3056 |
| - lineEnd: lineEnd, |
3057 |
| - polygonStart: function() { |
3058 |
| - clip.point = pointRing; |
3059 |
| - clip.lineStart = ringStart; |
3060 |
| - clip.lineEnd = ringEnd; |
3061 |
| - segments = []; |
3062 |
| - polygon = []; |
3063 |
| - }, |
3064 |
| - polygonEnd: function() { |
3065 |
| - clip.point = point; |
3066 |
| - clip.lineStart = lineStart; |
3067 |
| - clip.lineEnd = lineEnd; |
3068 |
| - segments = d3.merge(segments); |
3069 |
| - var clipStartInside = d3_geo_pointInPolygon(clipStart, polygon); |
3070 |
| - if (segments.length) { |
3071 |
| - if (!polygonStarted) sink.polygonStart(), polygonStarted = true; |
3072 |
| - d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, sink); |
3073 |
| - } else if (clipStartInside) { |
3074 |
| - if (!polygonStarted) sink.polygonStart(), polygonStarted = true; |
3075 |
| - sink.lineStart(); |
3076 |
| - interpolate(null, null, 1, sink); |
3077 |
| - sink.lineEnd(); |
3078 |
| - } |
3079 |
| - if (polygonStarted) sink.polygonEnd(), polygonStarted = false; |
3080 |
| - segments = polygon = null; |
3081 |
| - }, |
3082 |
| - sphere: function() { |
3083 |
| - sink.polygonStart(); |
| 3050 | + function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart, sink) { |
| 3051 | + var line = clipLine(sink); |
| 3052 | + var clip = { |
| 3053 | + point: point, |
| 3054 | + lineStart: lineStart, |
| 3055 | + lineEnd: lineEnd, |
| 3056 | + polygonStart: function() { |
| 3057 | + clip.point = pointRing; |
| 3058 | + clip.lineStart = ringStart; |
| 3059 | + clip.lineEnd = ringEnd; |
| 3060 | + segments = []; |
| 3061 | + polygon = []; |
| 3062 | + }, |
| 3063 | + polygonEnd: function() { |
| 3064 | + clip.point = point; |
| 3065 | + clip.lineStart = lineStart; |
| 3066 | + clip.lineEnd = lineEnd; |
| 3067 | + segments = d3.merge(segments); |
| 3068 | + var clipStartInside = d3_geo_pointInPolygon(clipStart, polygon); |
| 3069 | + if (segments.length) { |
| 3070 | + if (!polygonStarted) sink.polygonStart(), polygonStarted = true; |
| 3071 | + d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, sink); |
| 3072 | + } else if (clipStartInside) { |
| 3073 | + if (!polygonStarted) sink.polygonStart(), polygonStarted = true; |
3084 | 3074 | sink.lineStart();
|
3085 | 3075 | interpolate(null, null, 1, sink);
|
3086 | 3076 | sink.lineEnd();
|
3087 |
| - sink.polygonEnd(); |
3088 | 3077 | }
|
3089 |
| - }; |
3090 |
| - function point(λ, φ) { |
3091 |
| - if (pointVisible(λ, φ)) sink.point(λ, φ); |
3092 |
| - } |
3093 |
| - function pointLine(λ, φ) { |
3094 |
| - line.point(λ, φ); |
3095 |
| - } |
3096 |
| - function lineStart() { |
3097 |
| - clip.point = pointLine; |
3098 |
| - line.lineStart(); |
| 3078 | + if (polygonStarted) sink.polygonEnd(), polygonStarted = false; |
| 3079 | + segments = polygon = null; |
| 3080 | + }, |
| 3081 | + sphere: function() { |
| 3082 | + sink.polygonStart(); |
| 3083 | + sink.lineStart(); |
| 3084 | + interpolate(null, null, 1, sink); |
| 3085 | + sink.lineEnd(); |
| 3086 | + sink.polygonEnd(); |
3099 | 3087 | }
|
3100 |
| - function lineEnd() { |
3101 |
| - clip.point = point; |
3102 |
| - line.lineEnd(); |
3103 |
| - } |
3104 |
| - var segments; |
3105 |
| - var buffer = d3_geo_clipBufferSink(), ringSink = clipLine(buffer), polygonStarted = false, polygon, ring; |
3106 |
| - function pointRing(λ, φ) { |
3107 |
| - ring.push([ λ, φ ]); |
3108 |
| - ringSink.point(λ, φ); |
3109 |
| - } |
3110 |
| - function ringStart() { |
3111 |
| - ringSink.lineStart(); |
3112 |
| - ring = []; |
3113 |
| - } |
3114 |
| - function ringEnd() { |
3115 |
| - pointRing(ring[0][0], ring[0][1]); |
3116 |
| - ringSink.lineEnd(); |
3117 |
| - var clean = ringSink.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; |
3118 |
| - ring.pop(); |
3119 |
| - polygon.push(ring); |
3120 |
| - ring = null; |
3121 |
| - if (!n) return; |
3122 |
| - if (clean & 1) { |
3123 |
| - segment = ringSegments[0]; |
3124 |
| - var n = segment.length - 1, i = -1, point; |
3125 |
| - if (n > 0) { |
3126 |
| - if (!polygonStarted) sink.polygonStart(), polygonStarted = true; |
3127 |
| - sink.lineStart(); |
3128 |
| - while (++i < n) sink.point((point = segment[i])[0], point[1]); |
3129 |
| - sink.lineEnd(); |
3130 |
| - } |
3131 |
| - return; |
| 3088 | + }; |
| 3089 | + function point(λ, φ) { |
| 3090 | + if (pointVisible(λ, φ)) sink.point(λ, φ); |
| 3091 | + } |
| 3092 | + function pointLine(λ, φ) { |
| 3093 | + line.point(λ, φ); |
| 3094 | + } |
| 3095 | + function lineStart() { |
| 3096 | + clip.point = pointLine; |
| 3097 | + line.lineStart(); |
| 3098 | + } |
| 3099 | + function lineEnd() { |
| 3100 | + clip.point = point; |
| 3101 | + line.lineEnd(); |
| 3102 | + } |
| 3103 | + var segments; |
| 3104 | + var buffer = d3_geo_clipBufferSink(), ringSink = clipLine(buffer), polygonStarted = false, polygon, ring; |
| 3105 | + function pointRing(λ, φ) { |
| 3106 | + ring.push([ λ, φ ]); |
| 3107 | + ringSink.point(λ, φ); |
| 3108 | + } |
| 3109 | + function ringStart() { |
| 3110 | + ringSink.lineStart(); |
| 3111 | + ring = []; |
| 3112 | + } |
| 3113 | + function ringEnd() { |
| 3114 | + pointRing(ring[0][0], ring[0][1]); |
| 3115 | + ringSink.lineEnd(); |
| 3116 | + var clean = ringSink.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; |
| 3117 | + ring.pop(); |
| 3118 | + polygon.push(ring); |
| 3119 | + ring = null; |
| 3120 | + if (!n) return; |
| 3121 | + if (clean & 1) { |
| 3122 | + segment = ringSegments[0]; |
| 3123 | + var n = segment.length - 1, i = -1, point; |
| 3124 | + if (n > 0) { |
| 3125 | + if (!polygonStarted) sink.polygonStart(), polygonStarted = true; |
| 3126 | + sink.lineStart(); |
| 3127 | + while (++i < n) sink.point((point = segment[i])[0], point[1]); |
| 3128 | + sink.lineEnd(); |
3132 | 3129 | }
|
3133 |
| - if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); |
3134 |
| - segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); |
| 3130 | + return; |
3135 | 3131 | }
|
3136 |
| - return clip; |
3137 |
| - }; |
| 3132 | + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); |
| 3133 | + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); |
| 3134 | + } |
| 3135 | + return clip; |
3138 | 3136 | }
|
3139 | 3137 | function d3_geo_clipSegmentLength1(segment) {
|
3140 | 3138 | return segment.length > 1;
|
|
3228 | 3226 | }
|
3229 | 3227 | return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ winding & 1;
|
3230 | 3228 | }
|
3231 |
| - d3.geo.clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]); |
3232 |
| - function d3_geo_clipAntimeridianLine(listener) { |
| 3229 | + d3.geo.clipAntimeridian = function(sink) { |
| 3230 | + return d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ], sink); |
| 3231 | + }; |
| 3232 | + function d3_geo_clipAntimeridianLine(sink) { |
3233 | 3233 | var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
|
3234 | 3234 | return {
|
3235 | 3235 | lineStart: function() {
|
3236 |
| - listener.lineStart(); |
| 3236 | + sink.lineStart(); |
3237 | 3237 | clean = 1;
|
3238 | 3238 | },
|
3239 | 3239 | point: function(λ1, φ1) {
|
3240 | 3240 | var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0);
|
3241 | 3241 | if (abs(dλ - π) < ε) {
|
3242 |
| - listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); |
3243 |
| - listener.point(sλ0, φ0); |
3244 |
| - listener.lineEnd(); |
3245 |
| - listener.lineStart(); |
3246 |
| - listener.point(sλ1, φ0); |
3247 |
| - listener.point(λ1, φ0); |
| 3242 | + sink.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); |
| 3243 | + sink.point(sλ0, φ0); |
| 3244 | + sink.lineEnd(); |
| 3245 | + sink.lineStart(); |
| 3246 | + sink.point(sλ1, φ0); |
| 3247 | + sink.point(λ1, φ0); |
3248 | 3248 | clean = 0;
|
3249 | 3249 | } else if (sλ0 !== sλ1 && dλ >= π) {
|
3250 | 3250 | if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
|
3251 | 3251 | if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
|
3252 | 3252 | φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
|
3253 |
| - listener.point(sλ0, φ0); |
3254 |
| - listener.lineEnd(); |
3255 |
| - listener.lineStart(); |
3256 |
| - listener.point(sλ1, φ0); |
| 3253 | + sink.point(sλ0, φ0); |
| 3254 | + sink.lineEnd(); |
| 3255 | + sink.lineStart(); |
| 3256 | + sink.point(sλ1, φ0); |
3257 | 3257 | clean = 0;
|
3258 | 3258 | }
|
3259 |
| - listener.point(λ0 = λ1, φ0 = φ1); |
| 3259 | + sink.point(λ0 = λ1, φ0 = φ1); |
3260 | 3260 | sλ0 = sλ1;
|
3261 | 3261 | },
|
3262 | 3262 | lineEnd: function() {
|
3263 |
| - listener.lineEnd(); |
| 3263 | + sink.lineEnd(); |
3264 | 3264 | λ0 = φ0 = NaN;
|
3265 | 3265 | },
|
3266 | 3266 | clean: function() {
|
|
3272 | 3272 | var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
|
3273 | 3273 | return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
|
3274 | 3274 | }
|
3275 |
| - function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { |
| 3275 | + function d3_geo_clipAntimeridianInterpolate(from, to, direction, sink) { |
3276 | 3276 | var φ;
|
3277 | 3277 | if (from == null) {
|
3278 | 3278 | φ = direction * halfπ;
|
3279 |
| - listener.point(-π, φ); |
3280 |
| - listener.point(0, φ); |
3281 |
| - listener.point(π, φ); |
3282 |
| - listener.point(π, 0); |
3283 |
| - listener.point(π, -φ); |
3284 |
| - listener.point(0, -φ); |
3285 |
| - listener.point(-π, -φ); |
3286 |
| - listener.point(-π, 0); |
3287 |
| - listener.point(-π, φ); |
| 3279 | + sink.point(-π, φ); |
| 3280 | + sink.point(0, φ); |
| 3281 | + sink.point(π, φ); |
| 3282 | + sink.point(π, 0); |
| 3283 | + sink.point(π, -φ); |
| 3284 | + sink.point(0, -φ); |
| 3285 | + sink.point(-π, -φ); |
| 3286 | + sink.point(-π, 0); |
| 3287 | + sink.point(-π, φ); |
3288 | 3288 | } else if (abs(from[0] - to[0]) > ε) {
|
3289 | 3289 | var s = from[0] < to[0] ? π : -π;
|
3290 | 3290 | φ = direction * s / 2;
|
3291 |
| - listener.point(-s, φ); |
3292 |
| - listener.point(0, φ); |
3293 |
| - listener.point(s, φ); |
| 3291 | + sink.point(-s, φ); |
| 3292 | + sink.point(0, φ); |
| 3293 | + sink.point(s, φ); |
3294 | 3294 | } else {
|
3295 |
| - listener.point(to[0], to[1]); |
| 3295 | + sink.point(to[0], to[1]); |
3296 | 3296 | }
|
3297 | 3297 | }
|
| 3298 | + function d3_geo_circleInterpolate(radius, precision) { |
| 3299 | + var cr = Math.cos(radius), sr = Math.sin(radius); |
| 3300 | + return function(from, to, direction, sink) { |
| 3301 | + var step = direction * precision; |
| 3302 | + if (from != null) { |
| 3303 | + from = d3_geo_circleInterpolateAngle(cr, from); |
| 3304 | + to = d3_geo_circleInterpolateAngle(cr, to); |
| 3305 | + if (direction > 0 ? from < to : from > to) from += direction * τ; |
| 3306 | + } else { |
| 3307 | + from = radius + direction * τ; |
| 3308 | + to = radius - .5 * step; |
| 3309 | + } |
| 3310 | + for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) { |
| 3311 | + sink.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); |
| 3312 | + } |
| 3313 | + }; |
| 3314 | + } |
| 3315 | + function d3_geo_circleInterpolateAngle(cr, point) { |
| 3316 | + var a = d3_geo_cartesian(point); |
| 3317 | + a[0] -= cr; |
| 3318 | + d3_geo_cartesianNormalize(a); |
| 3319 | + var angle = d3_acos(-a[1]); |
| 3320 | + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); |
| 3321 | + } |
| 3322 | + d3.geo.clipCircle = function(radius, sink) { |
| 3323 | + var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); |
| 3324 | + return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ], sink); |
| 3325 | + function visible(λ, φ) { |
| 3326 | + return Math.cos(λ) * Math.cos(φ) > cr; |
| 3327 | + } |
| 3328 | + function clipLine(sink) { |
| 3329 | + var point0, c0, v0, v00, clean; |
| 3330 | + return { |
| 3331 | + lineStart: function() { |
| 3332 | + v00 = v0 = false; |
| 3333 | + clean = 1; |
| 3334 | + }, |
| 3335 | + point: function(λ, φ) { |
| 3336 | + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; |
| 3337 | + if (!point0 && (v00 = v0 = v)) sink.lineStart(); |
| 3338 | + if (v !== v0) { |
| 3339 | + point2 = intersect(point0, point1); |
| 3340 | + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { |
| 3341 | + point1[0] += ε; |
| 3342 | + point1[1] += ε; |
| 3343 | + v = visible(point1[0], point1[1]); |
| 3344 | + } |
| 3345 | + } |
| 3346 | + if (v !== v0) { |
| 3347 | + clean = 0; |
| 3348 | + if (v) { |
| 3349 | + sink.lineStart(); |
| 3350 | + point2 = intersect(point1, point0); |
| 3351 | + sink.point(point2[0], point2[1]); |
| 3352 | + } else { |
| 3353 | + point2 = intersect(point0, point1); |
| 3354 | + sink.point(point2[0], point2[1]); |
| 3355 | + sink.lineEnd(); |
| 3356 | + } |
| 3357 | + point0 = point2; |
| 3358 | + } else if (notHemisphere && point0 && smallRadius ^ v) { |
| 3359 | + var t; |
| 3360 | + if (!(c & c0) && (t = intersect(point1, point0, true))) { |
| 3361 | + clean = 0; |
| 3362 | + if (smallRadius) { |
| 3363 | + sink.lineStart(); |
| 3364 | + sink.point(t[0][0], t[0][1]); |
| 3365 | + sink.point(t[1][0], t[1][1]); |
| 3366 | + sink.lineEnd(); |
| 3367 | + } else { |
| 3368 | + sink.point(t[1][0], t[1][1]); |
| 3369 | + sink.lineEnd(); |
| 3370 | + sink.lineStart(); |
| 3371 | + sink.point(t[0][0], t[0][1]); |
| 3372 | + } |
| 3373 | + } |
| 3374 | + } |
| 3375 | + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { |
| 3376 | + sink.point(point1[0], point1[1]); |
| 3377 | + } |
| 3378 | + point0 = point1, v0 = v, c0 = c; |
| 3379 | + }, |
| 3380 | + lineEnd: function() { |
| 3381 | + if (v0) sink.lineEnd(); |
| 3382 | + point0 = null; |
| 3383 | + }, |
| 3384 | + clean: function() { |
| 3385 | + return clean | (v00 && v0) << 1; |
| 3386 | + } |
| 3387 | + }; |
| 3388 | + } |
| 3389 | + function intersect(a, b, two) { |
| 3390 | + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); |
| 3391 | + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; |
| 3392 | + if (!determinant) return !two && a; |
| 3393 | + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); |
| 3394 | + d3_geo_cartesianAdd(A, B); |
| 3395 | + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); |
| 3396 | + if (t2 < 0) return; |
| 3397 | + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); |
| 3398 | + d3_geo_cartesianAdd(q, A); |
| 3399 | + q = d3_geo_spherical(q); |
| 3400 | + if (!two) return q; |
| 3401 | + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; |
| 3402 | + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; |
| 3403 | + var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε; |
| 3404 | + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; |
| 3405 | + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { |
| 3406 | + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); |
| 3407 | + d3_geo_cartesianAdd(q1, A); |
| 3408 | + return [ q, d3_geo_spherical(q1) ]; |
| 3409 | + } |
| 3410 | + } |
| 3411 | + function code(λ, φ) { |
| 3412 | + var r = smallRadius ? radius : π - radius, code = 0; |
| 3413 | + if (λ < -r) code |= 1; else if (λ > r) code |= 2; |
| 3414 | + if (φ < -r) code |= 4; else if (φ > r) code |= 8; |
| 3415 | + return code; |
| 3416 | + } |
| 3417 | + }; |
3298 | 3418 | d3.geo.graticule = function() {
|
3299 | 3419 | var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;
|
3300 | 3420 | function graticule() {
|
|
0 commit comments