@@ -186,7 +186,8 @@ d3 = function() {
186186 return entries ;
187187 } ;
188188 d3 . merge = function ( arrays ) {
189- return Array . prototype . concat . apply ( [ ] , arrays ) ;
189+ var n = arrays . length ;
190+ return n ? n > 1 ? Array . prototype . concat . apply ( [ ] , arrays ) : arrays [ 0 ] : [ ] ;
190191 } ;
191192 d3 . range = function ( start , stop , step ) {
192193 if ( arguments . length < 3 ) {
@@ -2611,16 +2612,15 @@ d3 = function() {
26112612 function d3_true ( ) {
26122613 return true ;
26132614 }
2614- function d3_geo_clipPolygon ( segments , compare , clipStartInside , interpolate , listener ) {
2615- var subject = [ ] , clip = [ ] ;
2616- segments . forEach ( function ( segment ) {
2617- if ( ( n = segment . length - 1 ) <= 0 ) return ;
2618- var n , p0 = segment [ 0 ] , p1 = segment [ n ] ;
2615+ function d3_geo_clipPolygon ( segments , compare , clipStartInside , pointInPolygon , interpolate , listener ) {
2616+ var subject = [ ] , clip = [ ] , rings = [ ] , n = segments . length ;
2617+ for ( var i = 0 ; i < n ; ++ i ) {
2618+ var segment = segments [ i ] ;
2619+ if ( ( m = segment . length - 1 ) <= 0 ) continue ;
2620+ var m , p0 = segment [ 0 ] , p1 = segment [ m ] ;
26192621 if ( d3_geo_sphericalEqual ( p0 , p1 ) ) {
2620- listener . lineStart ( ) ;
2621- for ( var i = 0 ; i < n ; ++ i ) listener . point ( ( p0 = segment [ i ] ) [ 0 ] , p0 [ 1 ] ) ;
2622- listener . lineEnd ( ) ;
2623- return ;
2622+ rings . push ( segment ) ;
2623+ continue ;
26242624 }
26252625 var a = {
26262626 point : p0 ,
@@ -2659,43 +2659,83 @@ d3 = function() {
26592659 a . other = b ;
26602660 subject . push ( a ) ;
26612661 clip . push ( b ) ;
2662- } ) ;
2663- clip . sort ( compare ) ;
2664- d3_geo_clipPolygonLinkCircular ( subject ) ;
2665- d3_geo_clipPolygonLinkCircular ( clip ) ;
2666- if ( ! subject . length ) return ;
2667- for ( var i = 0 , entry = clipStartInside , n = clip . length ; i < n ; ++ i ) {
2668- clip [ i ] . entry = entry = ! entry ;
2669- }
2670- var start = subject [ 0 ] , current , points , point ;
2671- while ( 1 ) {
2672- current = start ;
2673- while ( current . visited ) if ( ( current = current . next ) === start ) return ;
2674- points = current . points ;
2675- listener . lineStart ( ) ;
2676- do {
2677- current . visited = current . other . visited = true ;
2678- if ( current . entry ) {
2679- if ( current . subject ) {
2680- for ( var i = 0 ; i < points . length ; i ++ ) listener . point ( ( point = points [ i ] ) [ 0 ] , point [ 1 ] ) ;
2662+ }
2663+ if ( subject . length ) {
2664+ clip . sort ( compare ) ;
2665+ d3_geo_clipPolygonLinkCircular ( subject ) ;
2666+ d3_geo_clipPolygonLinkCircular ( clip ) ;
2667+ for ( var i = 0 , entry = clipStartInside , n = clip . length ; i < n ; ++ i ) {
2668+ clip [ i ] . entry = entry = ! entry ;
2669+ }
2670+ var start = subject [ 0 ] , current , points , point , listener_ = listener ;
2671+ if ( rings . length ) listener = d3_geo_clipBufferListener ( ) ;
2672+ while ( 1 ) {
2673+ current = start ;
2674+ while ( current . visited ) if ( ( current = current . next ) === start ) break ;
2675+ if ( current . visited ) break ;
2676+ points = current . points ;
2677+ listener . polygonStart ( ) ;
2678+ listener . lineStart ( ) ;
2679+ do {
2680+ current . visited = current . other . visited = true ;
2681+ if ( current . entry ) {
2682+ if ( current . subject ) {
2683+ for ( var i = 0 ; i < points . length ; i ++ ) listener . point ( ( point = points [ i ] ) [ 0 ] , point [ 1 ] ) ;
2684+ } else {
2685+ interpolate ( current . point , current . next . point , 1 , listener ) ;
2686+ }
2687+ current = current . next ;
26812688 } else {
2682- interpolate ( current . point , current . next . point , 1 , listener ) ;
2689+ if ( current . subject ) {
2690+ points = current . prev . points ;
2691+ for ( var i = points . length ; -- i >= 0 ; ) listener . point ( ( point = points [ i ] ) [ 0 ] , point [ 1 ] ) ;
2692+ } else {
2693+ interpolate ( current . point , current . prev . point , - 1 , listener ) ;
2694+ }
2695+ current = current . prev ;
26832696 }
2684- current = current . next ;
2685- } else {
2686- if ( current . subject ) {
2687- points = current . prev . points ;
2688- for ( var i = points . length ; -- i >= 0 ; ) listener . point ( ( point = points [ i ] ) [ 0 ] , point [ 1 ] ) ;
2689- } else {
2690- interpolate ( current . point , current . prev . point , - 1 , listener ) ;
2697+ current = current . other ;
2698+ points = current . points ;
2699+ } while ( ! current . visited ) ;
2700+ listener . lineEnd ( ) ;
2701+ listener . polygonEnd ( ) ;
2702+ }
2703+ if ( n = rings . length ) {
2704+ var exteriors = listener . buffer ( ) ;
2705+ listener = listener_ ;
2706+ for ( var j = 0 , m = exteriors . length ; j < m ; ++ j ) {
2707+ var exterior = exteriors [ j ] ;
2708+ listener . polygonStart ( ) ;
2709+ d3_geo_clipPolygonStreamRing ( exterior , listener ) ;
2710+ for ( var i = 0 ; i < n ; ++ i ) {
2711+ var ring = rings [ i ] ;
2712+ if ( ring && pointInPolygon ( ring [ 0 ] , [ exterior ] ) ) {
2713+ d3_geo_clipPolygonStreamRing ( ring , listener ) ;
2714+ rings [ i ] = null ;
2715+ }
26912716 }
2692- current = current . prev ;
2717+ listener . polygonEnd ( ) ;
26932718 }
2694- current = current . other ;
2695- points = current . points ;
2696- } while ( ! current . visited ) ;
2697- listener . lineEnd ( ) ;
2719+ }
2720+ } else if ( ( n = rings . length ) || clipStartInside ) {
2721+ listener . polygonStart ( ) ;
2722+ if ( clipStartInside ) {
2723+ listener . lineStart ( ) ;
2724+ interpolate ( null , null , 1 , listener ) ;
2725+ listener . lineEnd ( ) ;
2726+ }
2727+ for ( var i = 0 ; i < n ; ++ i ) {
2728+ d3_geo_clipPolygonStreamRing ( rings [ i ] , listener ) ;
2729+ }
2730+ listener . polygonEnd ( ) ;
2731+ }
2732+ }
2733+ function d3_geo_clipPolygonStreamRing ( ring , listener ) {
2734+ listener . lineStart ( ) ;
2735+ for ( var i = 0 , n = ring . length - 1 , p ; i < n ; ++ i ) {
2736+ listener . point ( ( p = ring [ i ] ) [ 0 ] , p [ 1 ] ) ;
26982737 }
2738+ listener . lineEnd ( ) ;
26992739 }
27002740 function d3_geo_clipPolygonLinkCircular ( array ) {
27012741 if ( ! ( n = array . length ) ) return ;
@@ -2721,22 +2761,12 @@ d3 = function() {
27212761 clip . lineEnd = ringEnd ;
27222762 segments = [ ] ;
27232763 polygon = [ ] ;
2724- listener . polygonStart ( ) ;
27252764 } ,
27262765 polygonEnd : function ( ) {
27272766 clip . point = point ;
27282767 clip . lineStart = lineStart ;
27292768 clip . lineEnd = lineEnd ;
2730- segments = d3 . merge ( segments ) ;
2731- var clipStartInside = d3_geo_pointInPolygon ( rotatedClipStart , polygon ) ;
2732- if ( segments . length ) {
2733- d3_geo_clipPolygon ( segments , d3_geo_clipSort , clipStartInside , interpolate , listener ) ;
2734- } else if ( clipStartInside ) {
2735- listener . lineStart ( ) ;
2736- interpolate ( null , null , 1 , listener ) ;
2737- listener . lineEnd ( ) ;
2738- }
2739- listener . polygonEnd ( ) ;
2769+ d3_geo_clipPolygon ( d3 . merge ( segments ) , d3_geo_clipSort , d3_geo_pointInPolygon ( rotatedClipStart , polygon ) , d3_geo_pointInPolygon , interpolate , listener ) ;
27402770 segments = polygon = null ;
27412771 } ,
27422772 sphere : function ( ) {
@@ -2777,19 +2807,11 @@ d3 = function() {
27772807 function ringEnd ( ) {
27782808 pointRing ( ring [ 0 ] [ 0 ] , ring [ 0 ] [ 1 ] ) ;
27792809 ringListener . lineEnd ( ) ;
2780- var clean = ringListener . clean ( ) , ringSegments = buffer . buffer ( ) , segment , n = ringSegments . length ;
2810+ var clean = ringListener . clean ( ) , ringSegments = buffer . buffer ( ) , n = ringSegments . length ;
27812811 ring . pop ( ) ;
27822812 polygon . push ( ring ) ;
27832813 ring = null ;
27842814 if ( ! n ) return ;
2785- if ( clean & 1 ) {
2786- segment = ringSegments [ 0 ] ;
2787- var n = segment . length - 1 , i = - 1 , point ;
2788- listener . lineStart ( ) ;
2789- while ( ++ i < n ) listener . point ( ( point = segment [ i ] ) [ 0 ] , point [ 1 ] ) ;
2790- listener . lineEnd ( ) ;
2791- return ;
2792- }
27932815 if ( n > 1 && clean & 2 ) ringSegments . push ( ringSegments . pop ( ) . concat ( ringSegments . shift ( ) ) ) ;
27942816 segments . push ( ringSegments . filter ( d3_geo_clipSegmentLength1 ) ) ;
27952817 }
@@ -2809,6 +2831,8 @@ d3 = function() {
28092831 line . push ( [ λ , φ ] ) ;
28102832 } ,
28112833 lineEnd : d3_noop ,
2834+ polygonStart : d3_noop ,
2835+ polygonEnd : d3_noop ,
28122836 buffer : function ( ) {
28132837 var buffer = lines ;
28142838 lines = [ ] ;
@@ -3047,25 +3071,11 @@ d3 = function() {
30473071 clean = true ;
30483072 } ,
30493073 polygonEnd : function ( ) {
3050- listener = listener_ ;
3051- segments = d3 . merge ( segments ) ;
3052- var clipStartInside = insidePolygon ( [ x0 , y1 ] ) , inside = clean && clipStartInside , visible = segments . length ;
3053- if ( inside || visible ) {
3054- listener . polygonStart ( ) ;
3055- if ( inside ) {
3056- listener . lineStart ( ) ;
3057- interpolate ( null , null , 1 , listener ) ;
3058- listener . lineEnd ( ) ;
3059- }
3060- if ( visible ) {
3061- d3_geo_clipPolygon ( segments , compare , clipStartInside , interpolate , listener ) ;
3062- }
3063- listener . polygonEnd ( ) ;
3064- }
3074+ d3_geo_clipPolygon ( d3 . merge ( segments ) , compare , pointInPolygon ( [ x0 , y1 ] , polygon ) , pointInPolygon , interpolate , listener = listener_ ) ;
30653075 segments = polygon = ring = null ;
30663076 }
30673077 } ;
3068- function insidePolygon ( p ) {
3078+ function pointInPolygon ( p , polygon ) {
30693079 var wn = 0 , n = polygon . length , y = p [ 1 ] ;
30703080 for ( var i = 0 ; i < n ; ++ i ) {
30713081 for ( var j = 1 , v = polygon [ i ] , m = v . length , a = v [ 0 ] , b ; j < m ; ++ j ) {
0 commit comments