@@ -55,9 +55,8 @@ function calcGeoJSON(calcTrace, topojson) {
55
55
var trace = calcTrace [ 0 ] . trace ;
56
56
var len = calcTrace . length ;
57
57
var features = getTopojsonFeatures ( trace , topojson ) ;
58
- var i , j , k , m ;
59
58
60
- for ( i = 0 ; i < len ; i ++ ) {
59
+ for ( var i = 0 ; i < len ; i ++ ) {
61
60
var calcPt = calcTrace [ i ] ;
62
61
var feature = locationToFeature ( trace . locationmode , calcPt . loc , features ) ;
63
62
@@ -66,48 +65,116 @@ function calcGeoJSON(calcTrace, topojson) {
66
65
continue ;
67
66
}
68
67
68
+
69
69
calcPt . geojson = feature ;
70
70
calcPt . ct = feature . properties . ct ;
71
71
calcPt . index = i ;
72
+ calcPt . _polygons = feature2polygons ( feature ) ;
73
+ }
74
+ }
72
75
73
- var geometry = feature . geometry ;
74
- var coords = geometry . coordinates ;
75
- calcPt . _polygons = [ ] ;
76
+ function feature2polygons ( feature ) {
77
+ var geometry = feature . geometry ;
78
+ var coords = geometry . coordinates ;
79
+ var loc = feature . id ;
80
+
81
+ var polygons = [ ] ;
82
+ var appendPolygon , j , k , m ;
83
+
84
+ function doesCrossAntiMerdian ( pts ) {
85
+ for ( var l = 0 ; l < pts . length - 1 ; l ++ ) {
86
+ if ( pts [ l ] [ 0 ] > 0 && pts [ l + 1 ] [ 0 ] < 0 ) return l ;
87
+ }
88
+ return null ;
89
+ }
76
90
91
+ if ( loc === 'RUS' || loc === 'FJI' ) {
77
92
// Russia and Fiji have landmasses that cross the antimeridian,
78
93
// we need to add +360 to their longitude coordinates, so that
79
94
// polygon 'contains' doesn't get confused when crossing the antimeridian.
80
95
//
81
96
// Note that other countries have polygons on either side of the antimeridian
82
97
// (e.g. some Aleutian island for the USA), but those don't confuse
83
98
// the 'contains' method; these are skipped here.
84
- if ( calcPt . loc === 'RUS' || calcPt . loc === 'FJI' ) {
85
- for ( j = 0 ; j < coords . length ; j ++ ) {
86
- for ( k = 0 ; k < coords [ j ] . length ; k ++ ) {
87
- for ( m = 0 ; m < coords [ j ] [ k ] . length ; m ++ ) {
88
- if ( coords [ j ] [ k ] [ m ] [ 0 ] < 0 ) {
89
- coords [ j ] [ k ] [ m ] [ 0 ] += 360 ;
90
- }
91
- }
99
+ appendPolygon = function ( _pts ) {
100
+ var pts ;
101
+
102
+ if ( doesCrossAntiMerdian ( _pts ) === null ) {
103
+ pts = _pts ;
104
+ } else {
105
+ pts = new Array ( _pts . length ) ;
106
+ for ( m = 0 ; m < _pts . length ; m ++ ) {
107
+ // do nut mutate calcdata[i][j].geojson !!
108
+ pts [ m ] = [
109
+ _pts [ m ] [ 0 ] < 0 ? _pts [ m ] [ 0 ] + 360 : _pts [ m ] [ 0 ] ,
110
+ _pts [ m ] [ 1 ]
111
+ ] ;
92
112
}
93
113
}
94
- }
95
114
96
- switch ( geometry . type ) {
97
- case 'MultiPolygon' :
98
- for ( j = 0 ; j < coords . length ; j ++ ) {
99
- for ( k = 0 ; k < coords [ j ] . length ; k ++ ) {
100
- calcPt . _polygons . push ( polygon . tester ( coords [ j ] [ k ] ) ) ;
101
- }
115
+ polygons . push ( polygon . tester ( pts ) ) ;
116
+ } ;
117
+ } else if ( loc === 'ATA' ) {
118
+ // Antarctica has a landmass that wraps around every longitudes which
119
+ // confuses the 'contains' methods.
120
+ appendPolygon = function ( pts ) {
121
+ var crossAntiMeridianIndex = doesCrossAntiMerdian ( pts ) ;
122
+
123
+ // polygon that do not cross anti-meridian need no special handling
124
+ if ( crossAntiMeridianIndex === null ) {
125
+ return polygons . push ( polygon . tester ( pts ) ) ;
126
+ }
127
+
128
+ // stitch polygon by adding pt over South Pole,
129
+ // so that it covers the projected region covers all latitudes
130
+ //
131
+ // Note that the algorithm below only works for polygons that
132
+ // start and end on longitude -180 (like the ones built by
133
+ // https://github.com/etpinard/sane-topojson).
134
+ var stitch = new Array ( pts . length + 1 ) ;
135
+ var si = 0 ;
136
+
137
+ for ( m = 0 ; m < pts . length ; m ++ ) {
138
+ if ( m > crossAntiMeridianIndex ) {
139
+ stitch [ si ++ ] = [ pts [ m ] [ 0 ] + 360 , pts [ m ] [ 1 ] ] ;
140
+ } else if ( m === crossAntiMeridianIndex ) {
141
+ stitch [ si ++ ] = pts [ m ] ;
142
+ stitch [ si ++ ] = [ pts [ m ] [ 0 ] , - 90 ] ;
143
+ } else {
144
+ stitch [ si ++ ] = pts [ m ] ;
102
145
}
103
- break ;
104
- case 'Polygon' :
105
- for ( j = 0 ; j < coords . length ; j ++ ) {
106
- calcPt . _polygons . push ( polygon . tester ( coords [ j ] ) ) ;
146
+ }
147
+
148
+ // polygon.tester by default appends pt[0] to the points list,
149
+ // we must remove it here, to avoid a jump in longitude from 180 to -180,
150
+ // that would confuse the 'contains' method
151
+ var tester = polygon . tester ( stitch ) ;
152
+ tester . pts . pop ( ) ;
153
+ polygons . push ( tester ) ;
154
+ } ;
155
+ } else {
156
+ // otherwise using same array ref is fine
157
+ appendPolygon = function ( pts ) {
158
+ polygons . push ( polygon . tester ( pts ) ) ;
159
+ } ;
160
+ }
161
+
162
+ switch ( geometry . type ) {
163
+ case 'MultiPolygon' :
164
+ for ( j = 0 ; j < coords . length ; j ++ ) {
165
+ for ( k = 0 ; k < coords [ j ] . length ; k ++ ) {
166
+ appendPolygon ( coords [ j ] [ k ] ) ;
107
167
}
108
- break ;
109
- }
168
+ }
169
+ break ;
170
+ case 'Polygon' :
171
+ for ( j = 0 ; j < coords . length ; j ++ ) {
172
+ appendPolygon ( coords [ j ] ) ;
173
+ }
174
+ break ;
110
175
}
176
+
177
+ return polygons ;
111
178
}
112
179
113
180
function style ( geo ) {
0 commit comments