@@ -2493,7 +2493,7 @@ d3 = function() {
24932493 a . next = b = array [ 0 ] ;
24942494 b . prev = a ;
24952495 }
2496- function d3_geo_clip ( pointVisible , clipLine , interpolate ) {
2496+ function d3_geo_clip ( pointVisible , clipLine , interpolate , polygonContains ) {
24972497 return function ( listener ) {
24982498 var line = clipLine ( listener ) ;
24992499 var clip = {
@@ -2504,9 +2504,8 @@ d3 = function() {
25042504 clip . point = pointRing ;
25052505 clip . lineStart = ringStart ;
25062506 clip . lineEnd = ringEnd ;
2507- invisible = false ;
2508- invisibleArea = visibleArea = 0 ;
25092507 segments = [ ] ;
2508+ polygon = [ ] ;
25102509 listener . polygonStart ( ) ;
25112510 } ,
25122511 polygonEnd : function ( ) {
@@ -2516,13 +2515,13 @@ d3 = function() {
25162515 segments = d3 . merge ( segments ) ;
25172516 if ( segments . length ) {
25182517 d3_geo_clipPolygon ( segments , d3_geo_clipSort , null , interpolate , listener ) ;
2519- } else if ( visibleArea < - ε || invisible && invisibleArea < - ε ) {
2518+ } else if ( polygonContains ( polygon ) ) {
25202519 listener . lineStart ( ) ;
25212520 interpolate ( null , null , 1 , listener ) ;
25222521 listener . lineEnd ( ) ;
25232522 }
25242523 listener . polygonEnd ( ) ;
2525- segments = null ;
2524+ segments = polygon = null ;
25262525 } ,
25272526 sphere : function ( ) {
25282527 listener . polygonStart ( ) ;
@@ -2546,8 +2545,8 @@ d3 = function() {
25462545 clip . point = point ;
25472546 line . lineEnd ( ) ;
25482547 }
2549- var segments , visibleArea , invisibleArea , invisible ;
2550- var buffer = d3_geo_clipBufferListener ( ) , ringListener = clipLine ( buffer ) , ring ;
2548+ var segments ;
2549+ var buffer = d3_geo_clipBufferListener ( ) , ringListener = clipLine ( buffer ) , polygon , ring ;
25512550 function pointRing ( λ , φ ) {
25522551 ringListener . point ( λ , φ ) ;
25532552 ring . push ( [ λ , φ ] ) ;
@@ -2560,16 +2559,12 @@ d3 = function() {
25602559 pointRing ( ring [ 0 ] [ 0 ] , ring [ 0 ] [ 1 ] ) ;
25612560 ringListener . lineEnd ( ) ;
25622561 var clean = ringListener . clean ( ) , ringSegments = buffer . buffer ( ) , segment , n = ringSegments . length ;
2563- if ( ! n ) {
2564- invisible = true ;
2565- invisibleArea += d3_geo_clipAreaRing ( ring , - 1 ) ;
2566- ring = null ;
2567- return ;
2568- }
2562+ ring . pop ( ) ;
2563+ polygon . push ( ring ) ;
25692564 ring = null ;
2565+ if ( ! n ) return ;
25702566 if ( clean & 1 ) {
25712567 segment = ringSegments [ 0 ] ;
2572- visibleArea += d3_geo_clipAreaRing ( segment , 1 ) ;
25732568 var n = segment . length - 1 , i = - 1 , point ;
25742569 listener . lineStart ( ) ;
25752570 while ( ++ i < n ) listener . point ( ( point = segment [ i ] ) [ 0 ] , point [ 1 ] ) ;
@@ -2606,26 +2601,40 @@ d3 = function() {
26062601 }
26072602 } ;
26082603 }
2609- function d3_geo_clipAreaRing ( ring , invisible ) {
2610- if ( ! ( n = ring . length ) ) return 0 ;
2611- var n , i = 0 , area = 0 , p = ring [ 0 ] , λ = p [ 0 ] , φ = p [ 1 ] , cosφ = Math . cos ( φ ) , x0 = Math . atan2 ( invisible * Math . sin ( λ ) * cosφ , Math . sin ( φ ) ) , y0 = 1 - invisible * Math . cos ( λ ) * cosφ , x1 = x0 , x , y ;
2612- while ( ++ i < n ) {
2613- p = ring [ i ] ;
2614- cosφ = Math . cos ( φ = p [ 1 ] ) ;
2615- x = Math . atan2 ( invisible * Math . sin ( λ = p [ 0 ] ) * cosφ , Math . sin ( φ ) ) ;
2616- y = 1 - invisible * Math . cos ( λ ) * cosφ ;
2617- if ( Math . abs ( y0 - 2 ) < ε && Math . abs ( y - 2 ) < ε ) continue ;
2618- if ( Math . abs ( y ) < ε || Math . abs ( y0 ) < ε ) { } else if ( Math . abs ( Math . abs ( x - x0 ) - π ) < ε ) {
2619- if ( y + y0 > 2 ) area += 4 * ( x - x0 ) ;
2620- } else if ( Math . abs ( y0 - 2 ) < ε ) area += 4 * ( x - x1 ) ; else area += ( ( 3 * π + x - x0 ) % ( 2 * π ) - π ) * ( y0 + y ) ;
2621- x1 = x0 , x0 = x , y0 = y ;
2622- }
2623- return area ;
2624- }
26252604 function d3_geo_clipSort ( a , b ) {
26262605 return ( ( a = a . point ) [ 0 ] < 0 ? a [ 1 ] - π / 2 - ε : π / 2 - a [ 1 ] ) - ( ( b = b . point ) [ 0 ] < 0 ? b [ 1 ] - π / 2 - ε : π / 2 - b [ 1 ] ) ;
26272606 }
2628- var d3_geo_clipAntimeridian = d3_geo_clip ( d3_true , d3_geo_clipAntimeridianLine , d3_geo_clipAntimeridianInterpolate ) ;
2607+ function d3_geo_pointInPolygon ( point , polygon ) {
2608+ var meridian = point [ 0 ] , parallel = point [ 1 ] , meridianNormal = [ Math . sin ( meridian ) , - Math . cos ( meridian ) , 0 ] , polarAngle = 0 , polar = false , southPole = false , winding = 0 , area = 0 ;
2609+ for ( var i = 0 , n = polygon . length ; i < n ; ++ i ) {
2610+ var ring = polygon [ i ] , m = ring . length ;
2611+ if ( ! m ) continue ;
2612+ var point0 = ring [ 0 ] , λ0 = point0 [ 0 ] , φ0 = point0 [ 1 ] / 2 + π / 4 , sinφ0 = Math . sin ( φ0 ) , cosφ0 = Math . cos ( φ0 ) , j = 1 ;
2613+ while ( true ) {
2614+ if ( j === m ) j = 0 ;
2615+ point = ring [ j ] ;
2616+ var λ = point [ 0 ] , φ = point [ 1 ] / 2 + π / 4 , sinφ = Math . sin ( φ ) , cosφ = Math . cos ( φ ) , dλ = λ - λ0 , antimeridian = Math . abs ( dλ ) > π , k = sinφ0 * sinφ ;
2617+ area += Math . atan2 ( k * Math . sin ( dλ ) , cosφ0 * cosφ + k * Math . cos ( dλ ) ) ;
2618+ if ( Math . abs ( φ ) < ε ) southPole = true ;
2619+ polarAngle += antimeridian ? dλ + ( dλ >= 0 ? 2 : - 2 ) * π : dλ ;
2620+ if ( antimeridian ^ λ0 >= meridian ^ λ >= meridian ) {
2621+ var arc = d3_geo_cartesianCross ( d3_geo_cartesian ( point0 ) , d3_geo_cartesian ( point ) ) ;
2622+ d3_geo_cartesianNormalize ( arc ) ;
2623+ var intersection = d3_geo_cartesianCross ( meridianNormal , arc ) ;
2624+ d3_geo_cartesianNormalize ( intersection ) ;
2625+ var φarc = ( antimeridian ^ dλ >= 0 ? - 1 : 1 ) * d3_asin ( intersection [ 2 ] ) ;
2626+ if ( parallel > φarc ) {
2627+ winding += antimeridian ^ dλ >= 0 ? 1 : - 1 ;
2628+ }
2629+ }
2630+ if ( ! j ++ ) break ;
2631+ λ0 = λ , sinφ0 = sinφ , cosφ0 = cosφ , point0 = point ;
2632+ }
2633+ if ( Math . abs ( polarAngle ) > ε ) polar = true ;
2634+ }
2635+ return ( ! southPole && ! polar && area < 0 || polarAngle < - ε ) ^ winding & 1 ;
2636+ }
2637+ var d3_geo_clipAntimeridian = d3_geo_clip ( d3_true , d3_geo_clipAntimeridianLine , d3_geo_clipAntimeridianInterpolate , d3_geo_clipAntimeridianPolygonContains ) ;
26292638 function d3_geo_clipAntimeridianLine ( listener ) {
26302639 var λ0 = NaN , φ0 = NaN , sλ0 = NaN , clean ;
26312640 return {
@@ -2692,9 +2701,13 @@ d3 = function() {
26922701 listener . point ( to [ 0 ] , to [ 1 ] ) ;
26932702 }
26942703 }
2704+ var d3_geo_clipAntimeridianPoint = [ - π , 0 ] ;
2705+ function d3_geo_clipAntimeridianPolygonContains ( polygon ) {
2706+ return d3_geo_pointInPolygon ( d3_geo_clipAntimeridianPoint , polygon ) ;
2707+ }
26952708 function d3_geo_clipCircle ( radius ) {
2696- var cr = Math . cos ( radius ) , smallRadius = cr > 0 , notHemisphere = Math . abs ( cr ) > ε , interpolate = d3_geo_circleInterpolate ( radius , 6 * d3_radians ) ;
2697- return d3_geo_clip ( visible , clipLine , interpolate ) ;
2709+ var cr = Math . cos ( radius ) , smallRadius = cr > 0 , point = [ radius , 0 ] , notHemisphere = Math . abs ( cr ) > ε , interpolate = d3_geo_circleInterpolate ( radius , 6 * d3_radians ) ;
2710+ return d3_geo_clip ( visible , clipLine , interpolate , polygonContains ) ;
26982711 function visible ( λ , φ ) {
26992712 return Math . cos ( λ ) * Math . cos ( φ ) > cr ;
27002713 }
@@ -2787,6 +2800,9 @@ d3 = function() {
27872800 if ( φ < - r ) code |= 4 ; else if ( φ > r ) code |= 8 ;
27882801 return code ;
27892802 }
2803+ function polygonContains ( polygon ) {
2804+ return d3_geo_pointInPolygon ( point , polygon ) ;
2805+ }
27902806 }
27912807 var d3_geo_clipViewMAX = 1e9 ;
27922808 function d3_geo_clipView ( x0 , y0 , x1 , y1 ) {
0 commit comments