@@ -66,6 +66,8 @@ struct reprojectionObj
66
66
projectionObj * in ;
67
67
projectionObj * out ;
68
68
PJ * pj ;
69
+ int should_do_line_cutting ;
70
+ shapeObj splitShape ;
69
71
int bFreePJ ;
70
72
};
71
73
@@ -366,6 +368,7 @@ reprojectionObj* msProjectCreateReprojector(projectionObj* in, projectionObj* ou
366
368
reprojectionObj * obj = (reprojectionObj * )msSmallCalloc (1 , sizeof (reprojectionObj ));
367
369
obj -> in = in ;
368
370
obj -> out = out ;
371
+ obj -> should_do_line_cutting = -1 ;
369
372
370
373
/* -------------------------------------------------------------------- */
371
374
/* If the source and destination are simple and equal, then do */
@@ -448,6 +451,7 @@ void msProjectDestroyReprojector(reprojectionObj* reprojector)
448
451
return ;
449
452
if ( reprojector -> bFreePJ )
450
453
proj_destroy (reprojector -> pj );
454
+ msFreeShape (& (reprojector -> splitShape ));
451
455
msFree (reprojector );
452
456
}
453
457
@@ -490,6 +494,8 @@ struct reprojectionObj
490
494
{
491
495
projectionObj * in ;
492
496
projectionObj * out ;
497
+ int should_do_line_cutting ;
498
+ shapeObj splitShape ;
493
499
int no_op ;
494
500
};
495
501
@@ -503,6 +509,7 @@ reprojectionObj* msProjectCreateReprojector(projectionObj* in, projectionObj* ou
503
509
obj = (reprojectionObj * )msSmallCalloc (1 , sizeof (reprojectionObj ));
504
510
obj -> in = in ;
505
511
obj -> out = out ;
512
+ obj -> should_do_line_cutting = -1 ;
506
513
507
514
/* -------------------------------------------------------------------- */
508
515
/* If the source and destination are equal, then do nothing. */
@@ -548,6 +555,7 @@ void msProjectDestroyReprojector(reprojectionObj* reprojector)
548
555
{
549
556
if ( !reprojector )
550
557
return ;
558
+ msFreeShape (& (reprojector -> splitShape ));
551
559
msFree (reprojector );
552
560
}
553
561
@@ -1134,6 +1142,96 @@ static int msProjectSegment( reprojectionObj* reprojector,
1134
1142
return MS_SUCCESS ;
1135
1143
}
1136
1144
1145
+ /************************************************************************/
1146
+ /* msProjectShapeShouldDoLineCutting() */
1147
+ /************************************************************************/
1148
+
1149
+ /* Detect projecting from north polar stereographic to longlat or EPSG:3857 */
1150
+ #ifdef USE_GEOS
1151
+ static int msProjectShapeShouldDoLineCutting (reprojectionObj * reprojector )
1152
+ {
1153
+ if ( reprojector -> should_do_line_cutting >= 0 )
1154
+ return reprojector -> should_do_line_cutting ;
1155
+
1156
+ projectionObj * in = reprojector -> in ;
1157
+ projectionObj * out = reprojector -> out ;
1158
+ if ( !(!in -> gt .need_geotransform && !msProjIsGeographicCRS (in ) &&
1159
+ (msProjIsGeographicCRS (out ) ||
1160
+ (out -> numargs == 1 && strcmp (out -> args [0 ], "init=epsg:3857" ) == 0 ))) )
1161
+ {
1162
+ reprojector -> should_do_line_cutting = MS_FALSE ;
1163
+ return MS_FALSE ;
1164
+ }
1165
+
1166
+ int srcIsPolar ;
1167
+ double extremeLongEasting ;
1168
+ if ( msProjIsGeographicCRS (out ) )
1169
+ {
1170
+ pointObj p ;
1171
+ double gt3 = out -> gt .need_geotransform ? out -> gt .geotransform [3 ] : 0.0 ;
1172
+ double gt4 = out -> gt .need_geotransform ? out -> gt .geotransform [4 ] : 0.0 ;
1173
+ double gt5 = out -> gt .need_geotransform ? out -> gt .geotransform [5 ] : 1.0 ;
1174
+ p .x = 0.0 ;
1175
+ p .y = 0.0 ;
1176
+ srcIsPolar = msProjectPointEx (reprojector , & p ) == MS_SUCCESS &&
1177
+ fabs (gt3 + p .x * gt4 + p .y * gt5 - 90 ) < 1e-8 ;
1178
+ extremeLongEasting = 180 ;
1179
+ }
1180
+ else
1181
+ {
1182
+ pointObj p1 ;
1183
+ pointObj p2 ;
1184
+ double gt1 = out -> gt .need_geotransform ? out -> gt .geotransform [1 ] : 1.0 ;
1185
+ p1 .x = 0.0 ;
1186
+ p1 .y = -0.1 ;
1187
+ p2 .x = 0.0 ;
1188
+ p2 .y = 0.1 ;
1189
+ srcIsPolar = msProjectPointEx (reprojector , & p1 ) == MS_SUCCESS &&
1190
+ msProjectPointEx (reprojector , & p2 ) == MS_SUCCESS &&
1191
+ fabs ((p1 .x - p2 .x ) * gt1 ) > 20e6 ;
1192
+ extremeLongEasting = 20037508.3427892 ;
1193
+ }
1194
+ if ( !srcIsPolar )
1195
+ {
1196
+ reprojector -> should_do_line_cutting = MS_FALSE ;
1197
+ return MS_FALSE ;
1198
+ }
1199
+
1200
+ pointObj p ;
1201
+ double invgt0 = out -> gt .need_geotransform ? out -> gt .invgeotransform [0 ] : 0.0 ;
1202
+ double invgt1 = out -> gt .need_geotransform ? out -> gt .invgeotransform [1 ] : 1.0 ;
1203
+ double invgt3 = out -> gt .need_geotransform ? out -> gt .invgeotransform [3 ] : 0.0 ;
1204
+ double invgt4 = out -> gt .need_geotransform ? out -> gt .invgeotransform [4 ] : 0.0 ;
1205
+
1206
+ lineObj newLine = {0 ,NULL };
1207
+ const double EPS = 1e-10 ;
1208
+
1209
+ p .x = invgt0 + - extremeLongEasting * (1 - EPS ) * invgt1 ;
1210
+ p .y = invgt3 + - extremeLongEasting * (1 - EPS ) * invgt4 ;
1211
+ msProjectPoint (out , in , & p );
1212
+ pointObj first = p ;
1213
+ msAddPointToLine (& newLine , & p );
1214
+
1215
+ p .x = invgt0 + extremeLongEasting * (1 - EPS ) * invgt1 ;
1216
+ p .y = invgt3 + extremeLongEasting * (1 - EPS ) * invgt4 ;
1217
+ msProjectPoint (out , in , & p );
1218
+ msAddPointToLine (& newLine , & p );
1219
+
1220
+ p .x = 0 ;
1221
+ p .y = 0 ;
1222
+ msAddPointToLine (& newLine , & p );
1223
+
1224
+ msAddPointToLine (& newLine , & first );
1225
+
1226
+ msInitShape (& (reprojector -> splitShape ));
1227
+ reprojector -> splitShape .type = MS_SHAPE_POLYGON ;
1228
+ msAddLineDirectly (& (reprojector -> splitShape ), & newLine );
1229
+
1230
+ reprojector -> should_do_line_cutting = MS_TRUE ;
1231
+ return MS_TRUE ;
1232
+ }
1233
+ #endif
1234
+
1137
1235
/************************************************************************/
1138
1236
/* msProjectShapeLine() */
1139
1237
/* */
@@ -1197,7 +1295,49 @@ msProjectShapeLine(reprojectionObj* reprojector,
1197
1295
#undef p_y
1198
1296
#endif
1199
1297
1298
+ #ifdef USE_GEOS
1299
+ if ( shape -> type == MS_SHAPE_LINE &&
1300
+ msProjectShapeShouldDoLineCutting (reprojector ) )
1301
+ {
1302
+ shapeObj tmpShapeInputLine ;
1303
+ msInitShape (& tmpShapeInputLine );
1304
+ tmpShapeInputLine .type = MS_SHAPE_LINE ;
1305
+ tmpShapeInputLine .numlines = 1 ;
1306
+ tmpShapeInputLine .line = line ;
1307
+
1308
+ shapeObj * diff = NULL ;
1309
+ if ( msGEOSIntersects (& tmpShapeInputLine , & (reprojector -> splitShape )) )
1310
+ {
1311
+ diff = msGEOSDifference (& tmpShapeInputLine , & (reprojector -> splitShape ));
1312
+ }
1200
1313
1314
+ tmpShapeInputLine .numlines = 0 ;
1315
+ tmpShapeInputLine .line = NULL ;
1316
+ msFreeShape (& tmpShapeInputLine );
1317
+
1318
+ if ( diff )
1319
+ {
1320
+ for (int j = 0 ; j < diff -> numlines ; j ++ )
1321
+ {
1322
+ for ( i = 0 ; i < diff -> line [j ].numpoints ; i ++ ) {
1323
+ msProjectPointEx (reprojector , & (diff -> line [j ].point [i ]));
1324
+ }
1325
+ if ( j == 0 )
1326
+ {
1327
+ line_out -> numpoints = diff -> line [j ].numpoints ;
1328
+ memcpy (line_out -> point , diff -> line [0 ].point , sizeof (pointObj ) * line_out -> numpoints );
1329
+ }
1330
+ else
1331
+ {
1332
+ msAddLineDirectly (shape , & (diff -> line [j ]));
1333
+ }
1334
+ }
1335
+ msFreeShape (diff );
1336
+ msFree (diff );
1337
+ return MS_SUCCESS ;
1338
+ }
1339
+ }
1340
+ #endif
1201
1341
1202
1342
wrap_test = out != NULL && out -> proj != NULL && msProjIsGeographicCRS (out )
1203
1343
&& !msProjIsGeographicCRS (in );
0 commit comments